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>

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_srcm", "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": "Activación eSIM",
      "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

Activate a SIM or eSIM card. Performs the full flow: ICC validation (SIM only), document/age validation, activation with the telecom platform, wallet charge, recharge and bundle purchase when applicable.

If the external activation succeeds but a later step fails, the error response will include a recovery object with an activationId and a step field indicating where the process stopped. The client must call POST /api/v2/msmvl/activation/resume with just { "activationId": ... } to resume.

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-...",
    "valueCharged": 5.00,
    "provisionId": "PROV-123456"
  },
  "message": "Activation completed successfully. The amount has been deducted from the wallet...",
  "meta": { "requestId": "..." }
}

Success data fields:

Field Type Description
msisdnId string Assigned phone number
qrCode string QR code for eSIM activation (present for eSIM)
valueCharged number Amount charged from wallet in EUR (only present when a charge was made)
provisionId string Bundle provision ID (only for non-Orange brands)

Error response (with step recovery):

{
  "error": {
    "code": "WALLET_UPDATE_FAILED",
    "message": "Failed to process the activation charge.",
    "recovery": {
      "activationId": 42,
      "step": "charge",
      "partialData": {
        "msisdnId": "612345678",
        "qrCode": "LPA:1$sm-..."
      }
    }
  },
  "meta": { "requestId": "..." }
}

When the response includes error.recovery, call the resume endpoint with the activationId:

POST /api/v2/msmvl/activation/resume
{ "activationId": 42 }

Possible values of recovery.step:

Step Meaning
"charge" Wallet charge failed. Resume will run: charge + recharge + bundle.
"recharge" Wallet already charged, recharge failed. Resume will run: recharge + bundle.
"bundle" Wallet and recharge done, bundle failed. Resume will run: bundle only.

Possible errors:

Code HTTP Description
WALLET_NOT_FOUND 500 No wallet associated to user
ICC_ID_REQUIRED 400 iccId missing when simType is "sim"
ICC_ID_NOT_AVAILABLE 400 The provided ICC ID is not available for activation
BRAND_NOT_MAPPED 400 Brand could not be mapped to the configured recharge product
PRODUCT_NOT_FOUND 400 Requested product not found
ACTIVATION_COST_UNAVAILABLE 400 Could not determine the activation cost for the SIM
INSUFFICIENT_BALANCE 400 Wallet balance too low (a pending recharge is created)
WALLET_UPDATE_FAILED 500 Failed to deduct from wallet (step: charge)
RECHARGE_FAILED 500 External recharge failed (a pending recharge is created)
BUNDLE_FAILED 500 Bundle purchase failed (step: bundle)
ACTIVATION_SAVE_FAILED 500 SIM activated successfully but DB record failed — no recovery available, contact support with the msisdnId in details
PENDING_RECHARGE_SAVE_FAILED 500 Failed to save the pending recharge record
POST /api/v2/msmvl/activation/resume

Resume an activation that stopped mid-way. Use this when a previous call to POST /api/v2/msmvl/activation returned an error that included error.recovery.activationId. The server reads the activation state from the database and continues from the step where it stopped.

Body (JSON):

{
  "activationId": 42
}

Body fields:

Field Type Description
activationId number (integer) Activation ID obtained from error.recovery.activationId (required)

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "qrCode": "LPA:1$sm-...",
    "valueCharged": 5.00,
    "provisionId": "PROV-123456"
  },
  "message": "Activation completed successfully. The amount has been deducted from the wallet...",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
BAD_REQUEST 400 Body validation failed (activationId missing or not a positive integer)
ACTIVATION_NOT_FOUND 404 No activation found for the given activationId
FORBIDDEN 403 The activation belongs to a different user
ACTIVATION_FAILED 500 This activation was permanently marked as failed — contact support
WALLET_NOT_FOUND 500 No wallet associated to user
BRAND_NOT_MAPPED 400 Brand could not be mapped to the configured recharge product
PRODUCT_NOT_FOUND 400 Requested product not found
ACTIVATION_COST_UNAVAILABLE 400 Could not determine the activation cost
INSUFFICIENT_BALANCE 400 Wallet balance too low (a pending recharge is created)
WALLET_UPDATE_FAILED 500 Failed to deduct from wallet — response includes recovery
RECHARGE_FAILED 500 External recharge failed — response includes recovery
BUNDLE_FAILED 500 Bundle purchase failed — response includes recovery
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": "..." }
}
GET /api/v2/msmvl/activation/recharge-pending

Get pending recharges for incomplete MSMVL activations. A pending recharge record is created only when the user had insufficient wallet balance at activation time (INSUFFICIENT_BALANCE). Other failure cases (recharge API errors, BundleCash errors) are handled via the /resume endpoint and do not create a pending recharge record.

Query params:

Name Type Description
limit number Items to return (optional)
offset number Offset for pagination, max 100 (optional)

Response:

{
  "data": [...],
  "message": "Pending activation recharges retrieved successfully.",
  "meta": { "requestId": "..." }
}

Possible errors:

Code HTTP Description
PENDING_RECHARGES_RETRIEVE_FAILED 500 Failed to retrieve pending recharges
POST /api/v2/msmvl/activation/recharge-pending

Admin-only endpoint. Completes an activation left pending due to insufficient wallet balance (INSUFFICIENT_BALANCE). Bypasses the wallet and calls Masmovil directly (Topup for physical SIM, BundleCash for eSIM). On success, the pending recharge record is deleted and the activation status in msmvl_historial_activaciones is updated to completed. If the SIM facial value already covers the product price, no external call is made but cleanup is still applied. For other failure types use POST /resume instead.

Body (JSON):

{
  "mobileNumber": "612345678"
}

Body fields:

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

Success response:

{
  "data": {
    "msisdnId": "612345678",
    "amount": 500
  },
  "message": "Recarga realizada correctamente para completar el proceso de activación.",
  "meta": { "requestId": "..." }
}

Success data fields:

Field Type Description
msisdnId string The mobile number
amount number Amount recharged (in cents)

Possible errors:

Code HTTP Description
PENDING_RECHARGE_NOT_FOUND 404 No pending recharge found for this mobile number
PENDING_RECHARGE_RETRIEVE_FAILED 500 Failed to retrieve the pending recharge
PRODUCT_NOT_FOUND 500 Product associated to the pending recharge not found
ACTIVATION_REFERENCE_NOT_FOUND 500 Activation reference not found for this mobile number
ACTIVATION_REFERENCE_RETRIEVE_FAILED 500 Failed to retrieve the activation reference
BUNDLE_CASH_FAILED 500 Failed to apply BundleCash in Masmovil Services (eSIM)
FACIAL_VALUE_RETRIEVE_FAILED 500 Failed to retrieve the facial value for the physical SIM
ICCID_NOT_FOUND 500 ICCID not found for physical SIM recharge
RECHARGE_FAILED 500 External recharge (Topup) failed
BUNDLE_FAILED 500 Bundle purchase failed after recharge

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

Product catalog. Prefix: /api/v2/msmvl/products. Requires acceso_msmvl permission.

GET /api/v2/msmvl/products

Get the list of available products for a brand.

Query params:

Name Type Description
brand "Lebara" | "Lyca" | "Orange" Brand (required). Use "Lyca" when referring to Llamaya.
language "en" | "es" Language for product names (optional. 'es' by default)

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": "..." }
}