All v2 endpoints use Bearer token authentication and return a standard response envelope.
Header required in all requests:
Authorization: Bearer <your_token>
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.
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 profile, permissions and wallet endpoints. Prefix: /api/v2/user
/api/v2/user/permissions
Returns the list of permissions assigned to the authenticated user.
Response:
{
"data": {
"permissions": ["acceso_msmvl"]
},
"meta": { "requestId": "..." }
}
/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 |
/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 |
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".
/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) |
| 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
|
/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 |
/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 |
/api/v2/msmvl/activation/bundlecash
Combines the recharge (/recharge) and bundle purchase (/bundle) into a single
call. Can be used in two scenarios:
/recharge and
/bundle.
/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 |
/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 |
/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": "..." }
}
/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": "..." }
}
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.
/api/v2/msmvl/topup/readinessChecks 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"]
}
}
/api/v2/msmvl/topupValidates 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.
| Code | HTTP | Meaning |
|---|---|---|
| LIVE_RECHARGES_LOCKED | 423 | The real sales switch is locked; the supplier is not contacted. |
| OPERATOR_MISMATCH | 400 | The number does not belong to the requested brand; it is neither sold nor charged. |
| RECHARGE_REQUIRES_REVIEW | 409 | The previous result is uncertain; do not retry the same operation. |
/api/v2/msmvl/topup/llamaya-bonusesReturns 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"
}]
}
/api/v2/msmvl/topup/llamaya-bonusesApplies 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 rate | MASORANGE BundleCash product | Components |
|---|---|---|
| National 5, 10, 15 or 20 | PO_Lyca_Globe5/10/15/20 | 1 |
| Travel 15, 30 or 40 | PO_Travel_15/30/40 | 1 |
| Travel 80 | PO_Travel_40 | 2 |
| Travel 120 | PO_Travel_40 | 3 |
| Travel 160 / Unlimited | PO_Travel_40 | 4 |
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.
| Code | HTTP | Meaning |
|---|---|---|
| LIVE_LLAMAYA_BONUSES_LOCKED | 423 | Blocked vouchers; MASORANGE is not queried or contacted. |
| LLAMAYA_BONUS_NOT_ASSIGNED | 404 | The rate is not assigned or is no longer valid for the customer. |
| BONUS_RESULT_UNKNOWN | 502 | Uncertain result; remains under review and should not be retried automatically. |
/api/v2/msmvl/topup/llamaya-lines/readinessIndicates 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.
/api/v2/msmvl/topup/llamaya-lines/:msisdnRetrieve 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.
| Code | HTTP | Meaning |
|---|---|---|
| LLAMAYA_LINE_QUERY_LOCKED | 423 | Query blocked; MASORANGE was not contacted. |
| NUMBER_NOT_OWNED | 403 | The number does not belong to the customer's activation history. |
/api/v2/msmvl/topup/llamaya-renewalsSchedule 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
}
| Field | Rule |
|---|---|
msisdnId | Llamaya line completed and activated by the same token. |
catalogProductId | Commercial identifier returned by GET /llamaya-bonuses; do not use MASORANGE's technical ID. |
totalMonths | Between 1 and 24, including the initial bonus. With 1, no future cycle is scheduled. |
maxPriceCents | Optional. 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.
/api/v2/msmvl/topup/llamaya-renewalsLists 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.
/api/v2/msmvl/topup/llamaya-renewals/:renewalIdManage 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.
/api/v2/msmvl/topup/llamaya-renewals/:renewalId/executionsReturns 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.
Validation utilities. Prefix: /api/v2/msmvl/validate. Requires
acceso_msmvl permission.
/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) |
/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) |
/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) |
Commercial catalog associated with the token. Prefix: /api/v2/msmvl/products. Requires acceso_msmvl permission.
/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. |
Phone number management. Prefix: /api/v2/msmvl/msisdn-op. Requires
acceso_msmvl permission.
/api/v2/msmvl/msisdn-op/operator/:msisdn
Get the operator info for a phone number (current operator, origin, portability status).
/api/v2/msmvl/msisdn-op/balance/:msisdn
Get balance for a phone number.
Query params:
| Name | Type | Description |
|---|---|---|
| brand | "Lebara" | "Lyca" | "Orange" |
Brand (required) |
/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) |
/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) |
/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) |
Inventory lookup. Prefix: /api/v2/msmvl/inventory. Requires
acceso_msmvl permission.
/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": "..." }
}