API v2 Documentation

All v2 endpoints use Bearer token authentication and return a standard response envelope.

Header required in all requests:

Authorization: Bearer <your_token>

Client-facing API updates

Client-visible API updates will be published here from this point forward. Historical operational and implementation details are not part of the public API documentation.

Standard Response Envelope

All v2 endpoints wrap responses in a consistent envelope:

// Success (2xx)
{
  "data": { },
  "meta": { "requestId": "..." },
  "message": "Additional message" // Optional
}

// Error (4xx / 5xx)
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description",
    "details": { }
  },
  "meta": { "requestId": "..." }
}

User

User profile, permissions and wallet endpoints. Prefix: /api/v2/user

GET /api/v2/user/permissions

Returns the list of permissions assigned to the authenticated user.

Response:

{
  "data": {
	    "permissions": ["acceso_msmvl"]
  },
  "meta": { "requestId": "..." }
}
GET /api/v2/user/wallet

Returns wallet information (balance, currency) for the authenticated user.

Response:

{
  "data": {
    "balance": 50000,
    "currency": "EUR"
  },
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
UNAUTHORIZED 401 Missing or invalid authentication token
WALLET_NOT_FOUND 404 No wallet associated to the authenticated user
GET /api/v2/user/wallet/history

Returns the wallet balance change history for the authenticated user.

Query params:

Name Type Description
limit number Items per page (default: 10)
offset number Offset for pagination, max 100 (default: 0)

Response:

{
  "data": [
    {
      "name": "John Doe",
      "amount": 1500,
      "type": "debit",
      "description": "eSIM activation",
      "createdAt": "2026-03-11T10:00:00.000Z"
    }
  ],
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
UNAUTHORIZED 401 Missing or invalid authentication token
INVALID_QUERY 400 Invalid limit or offset query parameters
WALLET_NOT_FOUND 404 No wallet associated to the authenticated user
internal_error 500 Failed to retrieve wallet history

MSMVL - Activation

SIM/eSIM activation via MSMVL. Prefix: /api/v2/msmvl/activation. Requires acceso_msmvl permission.

Compatibility note: for compatibility, the brand value "Lyca" also covers Llamaya. The API parameter must still be sent as "Lyca".

POST /api/v2/msmvl/activation

Registers and activates a SIM or eSIM number. Performs ICC validation (SIM only), document/age validation, and the activation call. Checks wallet balance before activation, but does not charge the wallet nor trigger recharge or bundle in this step.

After a successful activation, follow the corresponding flow depending on the SIM type:

SIM type Required steps (in order)
eSIM /bundlecash
Physical SIM — 'product price > facial value' /recharge → /bundle
Physical SIM — 'product price ≤ facial value' or 'facial value = 0' /bundlecash

Orange brand is not available for this endpoint and will return BRAND_NOT_AVAILABLE.

Body (JSON):

{
  "productId": "PO_Mali_M",
  "brand": "Lebara",
  "name": "Juan",
  "surname": "Pérez",
  "surname2": "García",
  "documentNumber": "12345678A",
  "dateOfBirth": "1990-05-15",
  "nationalityId": "ES",
  "iccId": "89340712341234567890",
  "simType": "sim",
  "identificationType": "personal-identity-code",
  "email": "user@example.com",
  "language": "eng"
}

Body fields:

Field Type Description
productId string Product/plan identifier (required)
brand "Lebara" | "Lyca" | "Orange" Brand (required). Use "Lyca" when referring to Llamaya.
name string Customer first name (required)
surname string Customer first surname (required)
surname2 string Customer second surname (optional)
documentNumber string Document number (required)
dateOfBirth string Date of birth (required)
nationalityId string Nationality code, 2 chars ISO (required)
iccId string ICC ID, 19–20 chars (required when simType is sim)
simType "sim" | "esim" SIM type (required)
identificationType "business-identity-code" | "nie" | "passport" | "personal-identity-code" Document type (required)
email string Customer email (required)
language string Contact language, 3 chars ISO 639-2/T (required, e.g. "eng")

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "qrCode": "LPA:1$sm-..."
  },
  "message": "Activation completed successfully.",
  "meta": { "requestId": "..." }
}

Success data fields:

Field Type Description
msisdnId string Assigned phone number
qrCode string | null QR code for eSIM activation (null for physical SIM)

⏱️ The generated QR code (qrCode) is valid for 24 hours from the moment of activation. After that period, the QR expires and cannot be used to install the eSIM.


Possible errors:

Code HTTP Description
BRAND_NOT_AVAILABLE 400 Orange brand is not available for this endpoint
WALLET_NOT_FOUND 500 No wallet associated to user
PRODUCT_NOT_FOUND 400 Requested product not found
ICC_ID_REQUIRED 400 iccId missing when simType is "sim"
ACTIVATION_COST_UNAVAILABLE 400 Could not determine the activation cost for the SIM
ICC_ID_NOT_AVAILABLE 400 The provided ICC ID is not available for activation
INSUFFICIENT_BALANCE 400 Wallet balance too low — retry after topping up the wallet
ACTIVATION_SAVE_FAILED 500 SIM activated but DB record failed — contact support with the msisdnId in error.details
POST /api/v2/msmvl/activation/recharge

Step 2 — Charge the user's wallet and trigger the external recharge for the number. Call this after a successful POST /activation.

For physical SIM: charges only the difference between the product price and the SIM facial value. If the facial value already covers the full product price, the wallet is not charged and the operation succeeds immediately. In that case, you may also skip this endpoint entirely and call /bundlecash directly instead of invoking /recharge + /bundle separately.

Body (JSON):

{
  "mobileNumber": "612345678"
}

Body fields:

Field Type Description
mobileNumber string Mobile number from the activation step (required)

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "valueCharged": 5.00
  },
  "message": "Recharge completed successfully. 5 EUR have been deducted from the wallet.",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
ACTIVATION_NOT_FOUND 404 No activation registered for this mobile number
FORBIDDEN 403 The activation belongs to a different user
ACTIVATION_PRODUCT_MISSING 500 Activation has no product associated
PRODUCT_NOT_FOUND 400 Requested product not found
ICC_ID_MISSING 500 Physical SIM activation has no ICCID associated
ACTIVATION_COST_UNAVAILABLE 400 Could not determine the recharge cost for this SIM
WALLET_NOT_FOUND 500 No wallet associated to user
INSUFFICIENT_BALANCE 400 Wallet balance too low — retry after topping up the wallet
WALLET_UPDATE_FAILED 500 Failed to deduct from wallet
BRAND_NOT_MAPPED 400 Brand could not be mapped to the configured recharge product
RECHARGE_FAILED 500 External recharge call failed
POST /api/v2/msmvl/activation/bundle

Step 3a (physical SIM) — Purchases the bundle to apply the product tariff to the number.

Body (JSON):

{
  "mobileNumber": "612345678"
}

Body fields:

Field Type Description
mobileNumber string Mobile number from the activation step (required)

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "provisionId": "PROV-123456"
  },
  "message": "Bundle purchased successfully.",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
ACTIVATION_NOT_FOUND 404 No activation registered for this mobile number
FORBIDDEN 403 The activation belongs to a different user
ACTIVATION_PRODUCT_MISSING 500 Activation has no product associated
PRODUCT_NOT_FOUND 400 Requested product not found
BUNDLE_FAILED 500 Bundle purchase failed — contact support
POST /api/v2/msmvl/activation/bundlecash

Combines the recharge (/recharge) and bundle purchase (/bundle) into a single call. Can be used in two scenarios:

  • eSIM activations — shortcut that replaces both /recharge and /bundle.
  • Physical SIM activations where the product price ≤ facial value — since no recharge is needed, you can skip /recharge and /bundle and call this endpoint directly to apply the bundle in one step.

Body (JSON):

{
  "mobileNumber": "612345678"
}

Body fields:

Field Type Description
mobileNumber string Mobile number from the activation step (required)

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "basketReference": "REF-123",
    "basketId": "BKT-456",
    "localReference": "LOC-789"
  },
  "message": "BundleCash applied successfully.",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
ACTIVATION_NOT_FOUND 404 No activation registered for this mobile number
FORBIDDEN 403 The activation belongs to a different user
BUNDLECASH_REQUIRES_ESIM 400 BundleCash is only valid for eSIM activations or physical SIM activations where the product price ≤ facial value
ACTIVATION_PRODUCT_MISSING 500 Activation has no product associated
PRODUCT_NOT_FOUND 400 Requested product not found
BUNDLECASH_FAILED 500 BundleCash application failed — contact support
POST /api/v2/msmvl/activation/deactivation-roaming

Step 4 — Deactivates roaming control for the activated number. Call this after bundle/bundlecash succeeds. For Lyca Globe products, the operation is skipped automatically and success is returned.

Body (JSON):

{
  "mobileNumber": "612345678"
}

Body fields:

Field Type Description
mobileNumber string Mobile number from the activation step (required)

Success response:

{
  "data": { "msisdnId": "612345678" },
  "message": "Roaming deactivated successfully.",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
ACTIVATION_NOT_FOUND 404 No activation registered for this mobile number
FORBIDDEN 403 The activation belongs to a different user
GET /api/v2/msmvl/activation/facial/:iccId

Get the facial value (activation cost) for a given ICC ID. Used to determine how much balance the SIM already has before activation.

Path params:

Name Type Description
iccId string ICC ID, 19–20 chars (required)

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand name (required)
language string Language code, 2 chars ISO 639-1 (required)

Response:

{
  "data": {
    "value": 10.00
  },
  "meta": { "requestId": "..." }
}
GET /api/v2/msmvl/activation/history

Get MSMVL activation history for the authenticated user.

Query params:

Name Type Description
page number Page number, min 1 (default: 1)
limit number Items per page, 1–100 (default: 10)
dateFrom date Filter from date (optional, ISO format)
dateTo date Filter to date (optional, ISO format)

Response:

{
  "data": {
    "activationHistory": [
      {
        "id": 1,
        "msisdnId": "612345678",
        "qrCode": "LPA:1$sm-...",
        "createdAt": "2026-03-11T10:00:00.000Z"
      }
    ],
    "total": 42
  },
  "message": "Activation history retrieved successfully.",
  "meta": { "requestId": "..." }
}

Direct top-ups

Balance top-ups for Orange and Llamaya. Prefix: /api/v2/msmvl/topup. Requires the permission acceso_msmvl.

Commercial security: each sale requires a Idempotency-Key unique. If the supplier's response is uncertain, the platform blocks the automatic retry and returns the identifier for reconciliation.

GET/api/v2/msmvl/topup/readiness

Checks the availability of top-ups and the supported brands. It does not query the number nor execute any sale to the provider.

{
  "data": {
    "readyForCommercialSubmission": false,
    "commercialSubmissionLocked": true,
    "providerEnvironment": "staging",
    "supportedBrands": ["Orange", "Llamaya"]
  }
}
POST/api/v2/msmvl/topup

Validates that the number belongs to the selected brand, sells the top-up, and deducts from the wallet only after confirmation from the supplier.

Required header: Idempotency-Key: <unique-key-16-to-100-characters>

{
  "brand": "Orange",
  "msisdnId": "+34612345678",
  "amount": 10
}

Successful response: includes rechargeId, amount in cents, brand, and provider reference when provided.

CodeHTTPMeaning
LIVE_RECHARGES_LOCKED423The real sales switch is locked; the supplier is not contacted.
OPERATOR_MISMATCH400The number does not belong to the requested brand; it is neither sold nor charged.
RECHARGE_REQUIRES_REVIEW409The previous result is uncertain; do not retry the same operation.
GET/api/v2/msmvl/topup/llamaya-bonuses

Returns only Llamaya vouchers assigned and active for the client's token. Does not query the number or the provider. Use the catalogProductId returned in the next step; priceCents is the commercial rate that will be discounted, not the PVP.

{
  "data": [{
    "catalogProductId": 65,
    "providerProductId": "PO_Travel_80",
    "name": "Travel 80",
    "priceCents": 4000,
    "currency": "EUR",
    "simType": "sim"
  }]
}
POST/api/v2/msmvl/topup/llamaya-bonuses

Applies a Llamaya bonus to an existing line via POST /bundle/cash of MASORANGE. Validates that the line is Llamaya and that the rate remains available. Debits the wallet only once and only after all provider confirmations.

Required header: Idempotency-Key: <unique-key-16-to-100-characters>. Keep the same key to retrieve a completed response; do not reuse it with another number or rate.

{
  "msisdnId": "+34612345678",
  "catalogProductId": 65
}

Sequence: call /readiness; obtain the catalog with GET /llamaya-bonuses; select catalogProductId; send the POST; save rechargeId and providerReferences for reconciliation.

Displayed commercial rateMASORANGE BundleCash productComponents
National 5, 10, 15 or 20PO_Lyca_Globe5/10/15/201
Travel 15, 30 or 40PO_Travel_15/30/401
Travel 80PO_Travel_402
Travel 120PO_Travel_403
Travel 160 / UnlimitedPO_Travel_404

Important: Travel 80/120/160 is a single commercial recharge, with a single customer rate and an idempotent key. The platform generates a distinct reference per component. If a result is uncertain, it blocks the request for review and does not automatically retry any component.

CodeHTTPMeaning
LIVE_LLAMAYA_BONUSES_LOCKED423Blocked vouchers; MASORANGE is not queried or contacted.
LLAMAYA_BONUS_NOT_ASSIGNED404The rate is not assigned or is no longer valid for the customer.
BONUS_RESULT_UNKNOWN502Uncertain result; remains under review and should not be retried automatically.
GET/api/v2/msmvl/topup/llamaya-lines/readiness

Indicates whether the Llamaya tariff and consumption reading query is available. Check readyForProviderQuery, simulationMode, realProviderQueryLocked and dataSource before querying a line. In staging it remains locked by default; an authorized test uses exclusively the internal simulator.

GET/api/v2/msmvl/topup/llamaya-lines/:msisdn

Retrieve the rate, active bonuses, and usage of a Llamaya line that has been activated by the same token. This is a read-only operation: it does not activate, renew, top up, or deduct balance. Check first /readiness"; in an authorized staging simulation the response contains " simulated: true and dataSource: internal_staging_simulator. MASORANGE reports consumption per voucher. The platform only adds remainingAmount = totalAmount − consumedAmount and never estimates GB if the supplier does not provide them.

Invocation: replace :msisdn by the nine-digit mobile number or by its international form +34"; send the owner token in " Authorization: Bearer. There is no parameter to query numbers of other clients.

curl --request GET \
  --url 'https://api-staging.activationsim.es/api/v2/msmvl/topup/llamaya-lines/612345678' \
  --header 'Authorization: Bearer TU_TOKEN_API' \
  --header 'Accept: application/json'
{
								  "data": {
								    "msisdn": "612345678",
								    "lineStatus": "ACTIVE",
								    "dataSource": "masorange_readonly",
								    "simulated": false,
								    "activeTariffs": [{ "providerProductId": "PO_Travel_40", "bundleType": "BundleCash", "activationDate": "..." }],
    "bonuses": [{
      "name": "Travel 80",
      "consumptionSummary": [{
        "consumptionType": "DATA",
        "totalAmount": 171798691840,
        "consumedAmount": 21474836480,
        "remainingAmount": 150323855360,
        "unit": "BYTE"
      }]
    }]
  }
}

Data usage: Respect the unit returned by the supplier. If consumptionSummary arrives empty, the consumption is not available and must not be calculated from the tariff name.

CodeHTTPMeaning
LLAMAYA_LINE_QUERY_LOCKED423Query blocked; MASORANGE was not contacted.
NUMBER_NOT_OWNED403The number does not belong to the customer's activation history.
POST/api/v2/msmvl/topup/llamaya-renewals

Schedule renewals after the first voucher. Does not apply or charge the first bonus: it must already have been completed with an activation or POST /llamaya-bonuses. A plan of totalMonths: 8 creates seven future cycles, separated by 28 days.

{
  "msisdnId": "+34612345678",
  "catalogProductId": 65,
  "totalMonths": 8,
  "maxPriceCents": 4000
}
FieldRule
msisdnIdLlamaya line completed and activated by the same token.
catalogProductIdCommercial identifier returned by GET /llamaya-bonuses; do not use MASORANGE's technical ID.
totalMonthsBetween 1 and 24, including the initial bonus. With 1, no future cycle is scheduled.
maxPriceCentsOptional. Renewal cap; by default the current rate is applied. If the rate increases above the cap, the plan remains at requires_review and does not charge.

Response: returns id, nextRenewalAt, completedRenewals and remainingRenewals. Does not require Idempotency-Key because it does not complete a sale.

GET/api/v2/msmvl/topup/llamaya-renewals

Lists the token's plans, with the current price, the authorized limit, wallet balance, sufficiency for the next cycle, dates and last error. The token never receives lines from another client.

POST/api/v2/msmvl/topup/llamaya-renewals/:renewalId

Manage a self-renewal without repeating any BundleCash. Send exactly one of the following bodies:

{ "action": "pause" }
{ "action": "resume" }
{ "action": "cancel" }

pause retains the calendar; resume reactivate a paused or under review plan; cancel it closes it irreversibly for future cycles, without altering recharges already completed.

GET/api/v2/msmvl/topup/llamaya-renewals/:renewalId/executions

Returns the auditable ledger per cycle: scheduled date and attempt, status, amount actually charged, rechargeId and MASORANGE references. If there is insufficient balance, price higher than authorized, tariff not assigned or uncertain result, the cycle and the plan remain in requires_review; they are not automatically retried.

MSMVL – Validation

Validation utilities. Prefix: /api/v2/msmvl/validate. Requires acceso_msmvl permission.

GET /api/v2/msmvl/validate/:iccid

Validate if an ICC ID (SIM card identifier) is available for activation.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required)
GET /api/v2/msmvl/validate/age

Validate minimum age requirement (must be at least 18 years old).

Query params:

Name Type Description
dateOfBirth string Date of birth in YYYY-MM-DD format (required)
GET /api/v2/msmvl/validate/document

Validate an identification document number.

Query params:

Name Type Description
documentNumber string Document number (required)
identificationType "business-identity-code" | "nie" | "passport" | "personal-identity-code" Document type (required)

MSMVL – Products

Commercial catalog associated with the token. Prefix: /api/v2/msmvl/products. Requires acceso_msmvl permission.

GET /api/v2/msmvl/products

Returns only the products with a commercial tariff in effect for the token. Each element includes catalogProductId for reference, productId to send during activation, simType, priceCents and priceEur. The price is the one that will be deducted from the customer's wallet; it must never be replaced by the supplier's technical rate.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand required. Use "Lyca" for Llamaya.
language "en" | "es" Optional language for the labels. The default value is es.

MSMVL – MSISDN Operations

Phone number management. Prefix: /api/v2/msmvl/msisdn-op. Requires acceso_msmvl permission.

GET /api/v2/msmvl/msisdn-op/operator/:msisdn

Get the operator info for a phone number (current operator, origin, portability status).

GET /api/v2/msmvl/msisdn-op/balance/:msisdn

Get balance for a phone number.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required)
GET /api/v2/msmvl/msisdn-op/msisdn/:msisdn

Get comprehensive MSISDN info (ICC ID, IMSI, PINs, PUKs, status, product, balance, bonuses, QR code).

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required)
GET /api/v2/msmvl/msisdn-op/msisdn/:mobileNumber/services

Get active services for a phone number.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required)
GET /api/v2/msmvl/msisdn-op/msisdn/:mobileNumber/esimQr

Get eSIM activation QR info (URL and request date) for a phone number.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required)

MSMVL – Inventory

Inventory lookup. Prefix: /api/v2/msmvl/inventory. Requires acceso_msmvl permission.

GET /api/v2/msmvl/inventory/:mobileNumber

Get inventory info (ID and brand) for a mobile number.

Path params:

Name Type Description
mobileNumber string Mobile number, exactly 9 digits (required)

Response:

{
  "data": {
    "id": "INV_12345",
    "brand": "Lebara"
  },
  "meta": { "requestId": "..." }
}