Authentication
OAuth 2.0 token management
/api/v1/oauth/tokenGet access token
Exchange client credentials for a Bearer access token. Supports both JSON and form-urlencoded request bodies.
Request body*application/json, application/x-www-form-urlencoded
Responses
| 200 | Access token issued |
| 400 | Invalid request or scope |
| 401 | Invalid credentials |
| 403 | Partner account suspended |
Products
Browse eSIM product catalog
/api/v1/productsrequires authList products
Browse available eSIM products with filtering and pagination.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | — |
cursor | query | string | Opaque pagination cursor from previous response |
region | query | string | Filter by region (e.g. "Global", "Europe", "Asia") |
type | query | string | Filter by eSIM type |
status | query | string | — |
sort_by | query | string | — |
sort_order | query | enum | — |
Responses
| 200 | Product list |
| 400 | — |
| 401 | — |
| 429 | — |
/api/v1/products/{id}requires authGet product details
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Product details |
| 401 | — |
| 404 | — |
Orders
Create and manage orders
/api/v1/ordersrequires authList orders
List your orders with optional status filter and cursor pagination.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | — |
cursor | query | string | — |
status | query | enum | — |
Responses
| 200 | Order list |
| 401 | — |
| 429 | — |
/api/v1/ordersrequires authCreate order
Create a new order. Requires Idempotency-Key header to prevent duplicates.
If the same key is reused, the original order is returned with Idempotent-Replayed: true header.
Payment: production orders are charged atomically to the partner's
pre-funded wallet and are created as paid. If the balance is
insufficient the order is NOT created and 402 Insufficient Balance is
returned with the shortfall. Sandbox orders simulate payment — the
wallet is never charged. Check the balance with GET /api/v1/balance.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Key* | header | string | Unique key to prevent duplicate orders |
Request body*application/json
Responses
| 200 | Idempotent replay (order already exists) |
| 201 | Order created |
| 400 | Validation error, invalid product, or missing activation request |
| 401 | — |
| 402 | Wallet balance too low — no order created and no funds taken |
| 429 | — |
/api/v1/orders/{id}requires authGet order with fulfillment details
Returns order details including line items and fulfillment information (shipping tracking, eSIM codes, etc.)
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Order with fulfillment |
| 401 | — |
| 404 | — |
/api/v1/orders/{id}/activation-statusrequires authGet activation status for an order
Returns the status of all scheduled activations associated with an order.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Activation status details |
| 401 | — |
| 404 | — |
/api/v1/orders/bulkrequires authCreate bulk orders
Create up to 100 orders in a single request. Each order is processed independently; individual failures do not affect other orders in the batch.
Request body*application/json
Responses
| 200 | Bulk order results |
| 400 | Validation error |
| 401 | — |
Activations
Physical SIM activation requests and status
/api/v1/activationsrequires authList activation requests
List your physical SIM activation requests with optional filters.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
iccid | query | string | Filter by SIM number |
status | query | enum | — |
limit | query | integer | — |
Responses
| 200 | Activation request list |
| 401 | — |
| 429 | — |
/api/v1/activationsrequires authSubmit physical SIM activation
Submit a physical SIM card activation request with KYC data. The system auto-detects the carrier from the ICCID prefix:
896103*= Lycamobile58*= Optus
Currently supported carriers: Lycamobile and Optus. ICCIDs
for other carriers return 422 Carrier Not Supported with a
supported_carriers list.
KYC requirements differ by carrier (all listed fields required):
- Lycamobile: first_name, last_name, passport_no, passport_country, passport_expiry, date_of_birth, address, sim_last4, puk
- Optus: first_name, last_name, passport_no, passport_country, passport_expiry, date_of_birth, address, title
Request body*application/json
Responses
| 201 | Activation request created |
| 400 | Validation error or missing KYC fields |
| 401 | — |
| 409 | Duplicate ICCID or date conflict |
| 429 | — |
/api/v1/activations/{id}requires authGet activation details
Get detailed status of a specific activation request, including assigned mobile number and any error information.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Activation details |
| 401 | — |
| 404 | — |
/api/v1/activations/{id}requires authReschedule an activation request
Edit the requested activation date and/or note on an in-flight activation request. At least one of the two fields is required.
Only editable while status = "activation_requested". Once ops
has submitted the request to the carrier (or it has moved past that
state for any other reason), this returns 409 naming the current
status — coordinate with support instead. No KYC or customer fields
can be changed here; those go through the KYC pool endpoints.
Not found, or the activation belongs to another partner — 404
(existence is never leaked).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Request body*application/json
Responses
| 200 | Activation rescheduled |
| 400 | Validation error (no editable field, or a bad date) |
| 401 | — |
| 404 | — |
| 409 | Not editable — activation is no longer 'activation_requested' |
| 429 | — |
/api/v1/activations/{id}/cancelrequires authCancel an activation request
Cancel an in-flight activation request.
Only cancellable while status = "activation_requested". Once
ops has submitted the request to the carrier, this returns 409
naming the current status — contact support instead. Cancelling
atomically releases any KYC-pool passport draw (the passport's
per-brand use count and assigned_request_id are cleared, so it
never falsely counts toward its 4-use cap) and rolls the SIM's
activation status back to Inactive, so it becomes resubmittable.
Not found, or the activation belongs to another partner — 404
(existence is never leaked).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Request bodyapplication/json
Responses
| 200 | Activation cancelled |
| 401 | — |
| 404 | — |
| 409 | Not cancellable — activation is no longer 'activation_requested' |
| 429 | — |
/api/v1/activations/by-iccid/{iccid}/cancelrequires authCancel an activation request, looked up by ICCID
Same atomic core as POST /api/v1/activations/{id}/cancel — for
callers (e.g. ICC's automation) that hold the ICCID rather than our
internal activation id, so no extra GET /api/v1/activations lookup
is needed first.
Only cancellable while status = "activation_requested". Once
ops has submitted the request to the carrier, this returns 409
naming the current status — contact support instead. Cancelling
atomically releases any KYC-pool passport draw and rolls the SIM's
activation status back to Inactive, so it becomes resubmittable.
No open (in-flight) activation for this ICCID under your account —
whether it doesn't exist, belongs to another partner, or was never
submitted — 404 (existence is never leaked).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
iccid* | path | string | — |
Request bodyapplication/json
Responses
| 200 | Activation cancelled |
| 401 | — |
| 404 | — |
| 409 | Not cancellable — activation is no longer 'activation_requested' |
| 429 | — |
/api/v1/activations/by-iccid/{iccid}requires authReschedule an activation request, looked up by ICCID
Same guarded-update core as PATCH /api/v1/activations/{id} — for
callers (e.g. ICC's automation) that hold the ICCID rather than our
internal activation id. At least one of requested_activation_date
/ note is required.
Only editable while status = "activation_requested". Once ops
has submitted the request to the carrier (or it has moved past that
state for any other reason), this returns 409 naming the current
status. No KYC or customer fields can be changed here.
No open (in-flight) activation for this ICCID under your account —
whether it doesn't exist, belongs to another partner, or was never
submitted — 404 (existence is never leaked).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
iccid* | path | string | — |
Request body*application/json
Responses
| 200 | Activation rescheduled |
| 400 | Validation error (no editable field, or a bad date) |
| 401 | — |
| 404 | — |
| 409 | Not editable — activation is no longer 'activation_requested' |
| 429 | — |
/api/v1/activations/bulk/cancelrequires authCancel a batch of activation requests
Cancel up to 200 activation requests in one call. Each item is
cancelled through the same atomic core as the single-cancel
endpoint (POST /api/v1/activations/{id}/cancel) — one item's
failure never touches the others.
Identify items with activation_ids (our internal UUIDs), iccids
(for callers like ICC's automation that hold ICCIDs instead), or a
mix of both — combined, up to 200. ICCIDs are resolved to their
in-flight activation internally; outcomes are keyed by whichever
identifier you supplied for that item (activation_id or iccid).
Partial success is normal and returns 200. Ids/ICCIDs that
don't exist, don't belong to your account, or (for an ICCID) have no
open activation, come back as an outcome with
reason: "not_found" rather than failing the whole batch. Items that
are no longer activation_requested come back as
reason: "not_cancellable:<status>".
Request body*application/json
Responses
| 200 | Batch processed (see per-id outcomes; partial success is normal) |
| 400 | Validation error |
| 401 | — |
| 422 | Partner not provisioned (no agent record) |
| 429 | — |
/api/v1/activations/bulk/reschedulerequires authReschedule a batch of activation requests
Edit the requested activation date and/or note on up to 200
activation requests in one call. Each item identifies its activation
with EXACTLY ONE of activation_id (our internal UUID) or iccid
(for callers like ICC's automation that hold ICCIDs instead), needs
at least one of requested_activation_date / note, and is applied
through its own guarded update — one item's failure never touches
the others. Each outcome is keyed by whichever identifier the item
supplied.
Partial success is normal and returns 200. Ids/ICCIDs that
don't exist, don't belong to your account, or (for an ICCID) have no
open activation, come back as an outcome with
reason: "not_found". Items that are no longer
activation_requested come back as
reason: "not_editable:<status>" — the same "requested-only"
gate used everywhere else in the activation lifecycle.
Request body*application/json
Responses
| 200 | Batch processed (see per-id outcomes; partial success is normal) |
| 400 | Validation error |
| 401 | — |
| 422 | Partner not provisioned (no agent record) |
| 429 | — |
KYC
Passport / KYC pool management
/api/v1/kyc/passportsrequires authList your KYC pool passports
List the passports in your own KYC pool. Returns only the fields you
submitted plus a neutral outward status of received — our internal
verification and usage state is never exposed. Withdrawn (soft-deleted)
records are excluded.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | — |
Responses
| 200 | Passport list |
| 401 | — |
| 429 | — |
/api/v1/kyc/passportsrequires authImport passports into your KYC pool
Bulk-add passports into your own KYC pool (up to 200 per request). The pool is what the activation flow draws from when a bulk activation line carries no inline passport.
Imported passports are UNVERIFIED. Each record is stored with
verification_status = "pending". Our operations team must verify a
passport before the auto-draw will assign it to an activation — the
draw only selects verified (onshore) records. Importing here is not a
substitute for KYC verification.
Records are pinned to your own partner account; you can only write into
your own pool. Duplicate passport numbers — whether already in your pool
or repeated within the same request — are skipped (see
skipped_duplicates).
Request body*application/json
Responses
| 201 | Passports imported (unverified) |
| 400 | Validation error |
| 401 | — |
| 422 | Partner not provisioned (no agent record) |
| 429 | — |
/api/v1/kyc/passports/{id}requires authEdit a KYC pool passport
Edit one of your pool passports. Only allowed while the passport has
never been used for an activation — once used it is locked and must be
changed by our operations team (409 Passport In Use). Editing identity
fields (passport number, name, expiry) resets our verification, so the
record must be re-verified before it can be drawn again.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Request body*application/json
Responses
| 200 | Passport updated |
| 400 | Validation error |
| 401 | — |
| 404 | — |
| 409 | Passport already used (locked) or number conflict |
| 429 | — |
/api/v1/kyc/passports/{id}requires authWithdraw (soft-delete) a KYC pool passport
Withdraw one of your pool passports. This is a soft delete — the
record leaves your pool but is retained for compliance; it is never
physically deleted. Only allowed while the passport has never been
used for an activation — once used it is locked (409 Passport In Use) and must be handled by our operations team.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Passport withdrawn |
| 401 | — |
| 404 | — |
| 409 | Passport already used (locked) |
| 429 | — |
eSIMs
eSIM status and delivery
/api/v1/orders/{id}/esimsrequires authGet eSIMs for an order
Returns eSIM delivery details (ICCID, activation code, QR code URL) for a fulfilled order.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | eSIM delivery details |
| 400 | Order not yet fulfilled |
| 401 | — |
| 404 | — |
/api/v1/esims/{iccid}/statusrequires authGet eSIM status
Check the activation status, data usage, and location of an eSIM by ICCID.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
iccid* | path | string | ICCID (19-20 digits) |
Responses
| 200 | eSIM status |
| 400 | Invalid ICCID format |
| 401 | — |
| 403 | Not authorized to access this eSIM |
| 404 | — |
Inventory
Product availability
/api/v1/inventory/statusrequires authCheck product availability
Check real-time stock and availability status for products.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
product_ids | query | string | Comma-separated product UUIDs |
skus | query | string | Comma-separated SKU codes |
region | query | string | Filter by region |
Responses
| 200 | Inventory status |
| 401 | — |
Webhooks
Event notifications via HTTP POST to your registered endpoint. Supported events: `order.created`, `order.fulfilled`, `order.cancelled`, `esim.activated`, `esim.expired`, `payment.completed`, `payment.failed`, `activation.submitted`, `activation.confirmed`, `activation.activated`, `activation.failed` Webhook signature: `X-Webhook-Signature: t=<timestamp>,v1=<hmac_sha256_signature>`
/api/v1/webhooksrequires authList webhooks
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | — |
cursor | query | string | — |
status | query | enum | — |
environment | query | enum | — |
Responses
| 200 | Webhook list |
| 401 | — |
/api/v1/webhooksrequires authCreate webhook
Register a webhook endpoint to receive event notifications. The signing secret is returned only once in the response — store it securely.
Request body*application/json
Responses
| 201 | Webhook created with signing secret |
| 400 | Validation error |
| 401 | — |
/api/v1/webhooks/{id}requires authGet webhook details
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 200 | Webhook details |
| 401 | — |
| 404 | — |
/api/v1/webhooks/{id}requires authDelete webhook
Parameters
| Name | In | Type | Description |
|---|---|---|---|
id* | path | string · uuid | — |
Responses
| 204 | Webhook deleted |
| 401 | — |
| 404 | — |
Catalog
E-commerce catalog sync
/api/v1/catalog/syncrequires authGet product catalog for e-commerce
Export product catalog formatted for Shopify, WooCommerce, or generic use. Includes suggested retail pricing with configurable markup.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
format | query | enum | — |
include_images | query | enum | — |
region | query | string | — |
type | query | string | — |
markup | query | number | Markup percentage for suggested retail price |
Responses
| 200 | Product catalog |
| 401 | — |
Wallet
/api/v1/balancerequires authGet wallet balance
Current pre-funded wallet balance per currency. Orders are charged in the product's currency, so the matching wallet must be funded.
Responses
| 200 | Wallet balances |
| 401 | — |
| 429 | — |