Firsty

Search...

Search...

eSIM

Order an eSIM

Orders an eSIM and creates a new profile in a single operation.

Returns the eSIM details including the activation code (LPA string) for device installation, along with the newly created profile reference for future API calls.

To port an existing number onto the new eSIM, include the optional portIn block — an eSIM that waits for its port then stays pre-active (installable, but no service) until the port completes. See the Porting tag for the full workflow.

post/esims

Authorization

Authorization: Bearer {token} — an OAuth2 access token from the client-credentials flow. How authentication works

Headers

X-Idempotency-Keystring

Optional idempotency key for mutating requests (POST, PATCH). If provided, duplicate requests with the same key within 48 hours will return the cached original response without duplicating side effects.

Behavior:

  • Same key + same request body → returns cached response (prevents duplicate operations)
  • Same key + different request body → returns 422 error
  • Same key + in-flight request → returns 409 error with Retry-After header
  • Keys expire after 48 hours

Request Body Matching: Request bodies are compared by their JSON content. Object key order, including in nested objects, and whitespace do not affect matching. This means:

  • {"a":1,"b":2} and {"b":2,"a":1} are treated as identical ✓
  • Whitespace differences are ignored ✓
  • URL parameters and headers are NOT included in request body matching

Best Practices:

  • Use UUIDs or client-generated unique strings
  • Store keys on your side to support retries
  • Don't reuse keys across different operations

Request body

application/json

externalProfileIdstring

Optional client-provided external ID to associate with this eSIM. Must be unique per client.

esimVariantstring

The eSIM variant of the new eSIM (e.g. 'travel'), one of those GET /catalog/esim-variants lists. Defaults to the client's default eSIM variant.

portInobject

Optional port-in of an existing number onto the ordered eSIM. When present, the response contains a portIn object, and an eSIM that waits for its port stays pre-active until the port completes.

Show properties
msisdnstringrequired

The number to port, in international format (E.164 without a leading +) — i.e. the country code, not the national 0 trunk prefix. Belgium: 324 + 8 digits, e.g. 32470123456; Netherlands: 316 + 8 digits, e.g. 31612345678.

detailsone of Belgium | Netherlandsrequired

Donor details of the number to port. Their shape depends on the country of the selected eSIM's variant: the Belgian or the Dutch shape. Unknown fields are rejected.

Show properties
Belgiumobject

Donor details of a Belgian number. A prepaid contract takes donorIccid and/or donorSimNumber; a postpaid contract any of donorIccid, donorSimNumber and donorAccountNumber; a business contract donorAccountNumber only.

Show properties
donorContractTypestringrequired

Contract type of the number at the donor operator

Optionsprepaidpostpaidbusiness
donorIccidstring

ICCID of the donor SIM card, with a valid check digit. The preferred proof of a donor SIM: most donor operators accept it.

donorSimNumberstring

The number printed on the donor SIM card. Send it only when the donor SIM's ICCID is not available; donorIccid is accepted by more donor operators.

donorAccountNumberstring

Account/customer number at the donor operator

Netherlandsobject

Donor details of a Dutch number. A postpaid contract requires donorAccountNumber.

Show properties
donorContractTypestringrequired

Contract type of the number at the donor operator

Optionsprepaidpostpaid
donorAccountNumberstring

Customer number at the donor operator

communicationLanguageCodestringExperimental

The language to message the customer in, as a two-character lowercase ISO 639-1 code, stored on the created profile. Set it whenever you know the customer's language, en included: a profile without one is messaged in the client's default language, which can change. Change it later with PATCH /profiles/{profileReference}. Independent of numberRegistration.languageCode, which is registry data.

packagesarray of OrderPackageRequestExperimental

Packages ordered with the eSIM. Each is created pending as an order of the package itself would be, so a plan that cannot be ordered on this eSIM fails the whole order, and is loaded once the eSIM has network service, for example after its installation, its activation request or a port-in. Its validity counts from its activation; until then it has no expiresAt.

Show properties
planReferencestringrequired

Plan reference identifier (14-character opaque token)

externalTransactionIdstring

Optional client-provided external transaction ID to associate with this package.

numberRegistrationobject

Optional subscriber facts to register the number in its country's number registry, required in markets whose regulator mandates it. Applies to the preloaded number, or to the ported number when portIn is present. A registration that cannot be captured fails the order: a country whose registry is not supported is a 422; a country that does not match the number, or subscriber details the registry cannot accept, are a 400 with field errors under numberRegistration.

Responses

201Profile created and eSIM successfully orderedapplication/json
Show response body
dataobjectoptional
Show properties
profileReferencestring

The eSIM's profile reference for API access (16-digit numeric)

externalProfileIdstring | null

The client's external profile ID if provided

esimReferencestring

eSIM reference identifier (18-digit opaque token)

iccidstring

The SIM's ICCID (needed for device installation)

activationCodestring | null

LPA activation code for device installation; null for a physical SIM

pin1string

PIN1 for the eSIM profile, as personalised by the manufacturer. Required to unlock the profile when SIM PIN is enabled on the device.

puk1string

PUK1 for the eSIM profile. Resets PIN1 after it has been entered incorrectly three times.

pin2string

PIN2 for the eSIM profile, guarding SIM service settings.

puk2string

PUK2 for the eSIM profile. Resets PIN2.

esimVariantstring | null

The eSIM's variant (e.g. 'travel'), or null if it has none.

statusstring

Profile state on the device, as reported by the SM-DP+. A physical SIM has no download lifecycle and stays released; its service state is lifecycleStatus.

  • released: Ready for use; an eSIM profile in this state is available for download (QR code ready)
  • downloaded: Profile has been downloaded to the device
  • installed: Profile is installed on the eSIM chip
  • enabled: Profile is active on the device
  • disabled: Profile is installed but disabled on the device
  • deleted: Profile has been removed from the device
  • faulted: Profile failed to download or install on the device
Optionsreleaseddownloadedinstalledenableddisableddeletedfaulted
lifecycleStatusstring

Network service state of the eSIM.

  • preactive: not live on the network yet
  • active: live on the network
  • suspended: temporarily without network service; can be reactivated
  • terminated: permanently without network service
  • faulted, stale: network service could not be set up; contact support
Optionspreactiveactivesuspendedterminatedfaultedstale
msisdnsarray of object

Phone numbers (MSISDNs) attached to the eSIM. Only available for eSIM variants that include a phone number; empty for variants without one, and until a number is assigned.

Show properties
msisdnstring

Phone number in E.164 format without the leading +

primaryboolean

Whether this is the eSIM's primary phone number

createdAtstring · date-time
portInobjectoptional

Present when the order included a portIn block.

Show properties
portInRequestReferencestring

Public opaque port-in request reference (8-char uppercase base36)

statusstring

Extensible enum.

  • requested: Accepted by Firsty; provider submission in progress
  • approved: The donor accepted the port; scheduledAt is when the number moves, once known, which can be days ahead. The port finishes at completed
  • cancelling: Cancellation requested, awaiting provider confirmation
  • completed: The donor released the number and it is assigned to this SIM
  • rejected: Donor rejected the request (see reason); submit a corrected request. A rejection the customer can still correct may keep the request requested until it is final
  • failed: Port failed (see reason); submit a corrected request
  • cancelled: Cancellation confirmed; the eSIM stays pre-active for a corrected request or abandon
Examplesrequestedapprovedcancellingcompletedrejectedfailedcancelled
reasonobjectoptional

Why the port-in was rejected or failed. Present when status is rejected or failed, and on a requested port-in the donor has rejected for a reason the customer can still correct

Show properties
codestring

Normalized cause of the rejection or failure, the same for every porting provider. provider_failure covers every cause without a more specific code. The list of values is open-ended; new values may be added

Examplesmsisdn_sim_mismatchmsisdn_account_mismatchdonor_contract_type_mismatchnumber_not_activenumber_not_portablenumber_porting_in_progressporting_window_unavailableprovider_failure
messagestring | null

Human-readable detail of the cause for support; free-form, not intended to be parsed. Null when there is none

numberRegistrationobjectoptional

The registration of the number the eSIM is on or porting to, in its country's number registry. The field is absent when that number has no registration.

Show properties
numberRegistrationReferencestring
registrystring

The registry the number was registered with.

msisdnstring

The registered number, in international format (E.164 without a leading +).

statusstring

processing while the registration is on its way to the registry, completed once the registry accepted it, error when it was rejected (see reason).

Optionsprocessingcompletederror
reasonobject | null

Rejection detail; null unless the registration ended in error

Show properties
codestring

The registry's own rejection code, or one of ours when the registration never reached it

messagestring | null

Human-readable detail when available

packagesarray of objectoptionalExperimental

Present when the order included packages, in the same order. Each package is pending until the eSIM has network service.

Show properties
packageReferencestring

Package reference identifier (23-character opaque token)

planReferencestring
externalTransactionIdstring | null
404No available eSIM foundapplication/problem+json
Show response body
typestring · uri

URI reference to error documentation

titlestring

Short, consistent error summary

statusinteger

HTTP status code

detailstring

Human-readable explanation specific to this occurrence

codestring

Extensible enum. Machine-readable error slug. This is the field clients should branch on. The URI in type documents the code. Handle an unknown code by its HTTP status.

Examplesbad_requestvalidation_failedunauthorizedpayment_requiredfeature_not_enabledforbiddenbalance_not_foundesim_not_foundnot_foundnumber_registration_not_foundport_in_not_foundprofile_not_foundscheduled_action_not_foundsubscription_not_foundsubscription_plan_not_foundwebhook_endpoint_not_foundbalance_not_availablebalance_update_pendingconcurrent_modificationconflictesim_change_pendingesim_not_activeesim_not_provisionedesim_suspendedesim_swap_cooldownesim_swap_pendingesim_terminatedinvalid_state_transitionlimit_reachedno_esim_availablenumber_registration_pendingport_in_pendingservices_change_pendingservices_not_availablebalance_not_supportedbalance_operation_not_supportedbalance_update_refusedclient_transaction_id_reusedesim_variant_not_allowedesim_variant_not_swappableidempotency_key_reusedinsufficient_balancenumber_not_availablenumber_registration_not_supportedport_in_cancel_refusedporting_not_supportedservices_change_refusedservices_not_changeableservices_not_supportedsim_refused_by_networkunprocessable_entitylockedrate_limit_exceededinternal_errorbad_gatewayservice_unavailable
409A profile with this externalProfileId already existsapplication/problem+json
Show response body
typestring · uri

URI reference to error documentation

titlestring

Short, consistent error summary

statusinteger

HTTP status code

detailstring

Human-readable explanation specific to this occurrence

codestring

Extensible enum. Machine-readable error slug. This is the field clients should branch on. The URI in type documents the code. Handle an unknown code by its HTTP status.

Examplesbad_requestvalidation_failedunauthorizedpayment_requiredfeature_not_enabledforbiddenbalance_not_foundesim_not_foundnot_foundnumber_registration_not_foundport_in_not_foundprofile_not_foundscheduled_action_not_foundsubscription_not_foundsubscription_plan_not_foundwebhook_endpoint_not_foundbalance_not_availablebalance_update_pendingconcurrent_modificationconflictesim_change_pendingesim_not_activeesim_not_provisionedesim_suspendedesim_swap_cooldownesim_swap_pendingesim_terminatedinvalid_state_transitionlimit_reachedno_esim_availablenumber_registration_pendingport_in_pendingservices_change_pendingservices_not_availablebalance_not_supportedbalance_operation_not_supportedbalance_update_refusedclient_transaction_id_reusedesim_variant_not_allowedesim_variant_not_swappableidempotency_key_reusedinsufficient_balancenumber_not_availablenumber_registration_not_supportedport_in_cancel_refusedporting_not_supportedservices_change_refusedservices_not_changeableservices_not_supportedsim_refused_by_networkunprocessable_entitylockedrate_limit_exceededinternal_errorbad_gatewayservice_unavailable
422The request was well-formed but cannot be applied as given, for example an idempotency key reused with a different request body, or a physical SIM its network refuses for good (`code` `sim_refused_by_network`; the SIM stays assigned to the profile). The `detail` field identifies the cause.application/problem+json
Show response body
typestring · uri

URI reference to error documentation

titlestring

Short, consistent error summary

statusinteger

HTTP status code

detailstring

Human-readable explanation specific to this occurrence

codestring

Extensible enum. Machine-readable error slug. This is the field clients should branch on. The URI in type documents the code. Handle an unknown code by its HTTP status.

Examplesbad_requestvalidation_failedunauthorizedpayment_requiredfeature_not_enabledforbiddenbalance_not_foundesim_not_foundnot_foundnumber_registration_not_foundport_in_not_foundprofile_not_foundscheduled_action_not_foundsubscription_not_foundsubscription_plan_not_foundwebhook_endpoint_not_foundbalance_not_availablebalance_update_pendingconcurrent_modificationconflictesim_change_pendingesim_not_activeesim_not_provisionedesim_suspendedesim_swap_cooldownesim_swap_pendingesim_terminatedinvalid_state_transitionlimit_reachedno_esim_availablenumber_registration_pendingport_in_pendingservices_change_pendingservices_not_availablebalance_not_supportedbalance_operation_not_supportedbalance_update_refusedclient_transaction_id_reusedesim_variant_not_allowedesim_variant_not_swappableidempotency_key_reusedinsufficient_balancenumber_not_availablenumber_registration_not_supportedport_in_cancel_refusedporting_not_supportedservices_change_refusedservices_not_changeableservices_not_supportedsim_refused_by_networkunprocessable_entitylockedrate_limit_exceededinternal_errorbad_gatewayservice_unavailable
423A request with this idempotency key is still being processedapplication/problem+json
Show response body
typestring · uri

URI reference to error documentation

titlestring

Short, consistent error summary

statusinteger

HTTP status code

detailstring

Human-readable explanation specific to this occurrence

codestring

Extensible enum. Machine-readable error slug. This is the field clients should branch on. The URI in type documents the code. Handle an unknown code by its HTTP status.

Examplesbad_requestvalidation_failedunauthorizedpayment_requiredfeature_not_enabledforbiddenbalance_not_foundesim_not_foundnot_foundnumber_registration_not_foundport_in_not_foundprofile_not_foundscheduled_action_not_foundsubscription_not_foundsubscription_plan_not_foundwebhook_endpoint_not_foundbalance_not_availablebalance_update_pendingconcurrent_modificationconflictesim_change_pendingesim_not_activeesim_not_provisionedesim_suspendedesim_swap_cooldownesim_swap_pendingesim_terminatedinvalid_state_transitionlimit_reachedno_esim_availablenumber_registration_pendingport_in_pendingservices_change_pendingservices_not_availablebalance_not_supportedbalance_operation_not_supportedbalance_update_refusedclient_transaction_id_reusedesim_variant_not_allowedesim_variant_not_swappableidempotency_key_reusedinsufficient_balancenumber_not_availablenumber_registration_not_supportedport_in_cancel_refusedporting_not_supportedservices_change_refusedservices_not_changeableservices_not_supportedsim_refused_by_networkunprocessable_entitylockedrate_limit_exceededinternal_errorbad_gatewayservice_unavailable
400Bad request - invalid parameters401Unauthorized - missing or invalid API key403Forbidden - client does not have access to this resource429Rate limit exceeded. A `429` can also arrive without these headers or this body; handle it by its status code.500Internal server error