eSimerge

Top-ups

Add more data or more days to an eSIM that the end-user is already using.

How it works

A top-up is an additional purchase against an existing, already-issued eSIM. It does not replace the eSIM, the ICCID, or the QR code — the user keeps the same profile installed on their device. The plan's data allowance and/or validity are simply extended.

  • The eSIM must exist and be in issued or active status.
  • Top-up packages are plan-specific: each plan exposes its own compatible list. Always call GET /v1/esims/{id}/topup-packages for the eSIM you want to top up — never reuse a list from another plan.
  • Not every plan supports top-ups. The plan object returned by GET /v1/catalog and GET /v1/orders/{id} includes supports_topup: true|false. If false, the top-up endpoints will return topup_not_supported.
  • Top-up orders are billed against the same wallet / credit line as new eSIM orders, at your partner tier price.
  • A successful top-up emits order.topup.completed. A failed top-up emits order.topup.failed. No customer email is sent by eSimerge for top-ups.

End-to-end flow

1. POST /v1/orders                          → issue the eSIM (kind: "new")
2. … customer installs and uses the eSIM …
3. GET  /v1/esims/{id}/topup-packages       → list compatible top-ups for THIS eSIM
4. POST /v1/orders/topup                    → charge partner & apply top-up
5. Webhook: order.topup.completed           → confirm to your system
6. GET  /v1/esims/{id}/usage                → new totals reflect the top-up

GET /v1/esims/{id}/topup-packages

Returns the list of top-up packages compatible with the given eSIM. Prices are already priced in USD and include your tier markup.

curl https://portal.esimerge.com/api/public/v1/esims/esm_esim_AbCdEf/topup-packages \
  -H 'Authorization: Bearer esm_sk_test_...'

Example response

{
  "object": "list",
  "esim_id": "esm_esim_AbCdEf...",
  "count": 3,
  "data": [
    { "id": "topup_test_3gb_7d",   "object": "topup_package", "name": "Top-up 3GB / 7d",       "type": "fixed",     "data_mb": 3072, "is_unlimited": false, "validity_days": 7,  "price_sar": 22.50 },
    { "id": "topup_test_5gb_15d",  "object": "topup_package", "name": "Top-up 5GB / 15d",      "type": "fixed",     "data_mb": 5120, "is_unlimited": false, "validity_days": 15, "price_sar": 37.50 },
    { "id": "topup_test_unlim_7d", "object": "topup_package", "name": "Top-up Unlimited / 7d", "type": "unlimited", "data_mb": null, "is_unlimited": true,  "validity_days": 7,  "price_sar": 45.00 }
  ]
}

Top-up package fields

FieldTypeDescription
idstringTop-up package identifier. Pass this to POST /v1/orders/topup.
objectstringAlways "topup_package".
namestringDisplay name (e.g. "Top-up 5GB / 15d").
typestringfixed | unlimited
data_mbnumber?Extra data added to the eSIM. null when type=unlimited.
is_unlimitedbooleantrue for unlimited data top-ups.
validity_daysnumberExtra validity days added to the eSIM from the moment the top-up is applied.
price_sarnumberPartner price in USD (already includes your tier markup).

POST /v1/orders/topup

Apply a top-up package to an eSIM. The partner wallet (or credit line) is charged immediately at the listed price_sar. Always send a unique Idempotency-Key so retries don't double-charge.

Request body

  • esim_id (required) — the target eSIM id (esm_esim_…).
  • topup_package_id (required) — id from GET /v1/esims/{id}/topup-packages.
  • customer_reference (optional, ≤120 chars) — your internal reference, echoed back.
curl -X POST https://portal.esimerge.com/api/public/v1/orders/topup \
  -H 'Authorization: Bearer esm_sk_test_...' \
  -H 'Idempotency-Key: 8f0b1f9e-1f70-4a3e-9b3a-2c2bdcf7a1d2' \
  -H 'Content-Type: application/json' \
  -d '{"esim_id":"esm_esim_AbCdEf","topup_package_id":"topup_test_5gb_15d","customer_reference":"cust_42"}'

Example response (201)

{
  "id": "esm_order_GhIjKl...",
  "object": "order",
  "kind": "topup",
  "status": "issued",
  "parent_order_id": "esm_order_AbCdEf...",
  "esim_id": "esm_esim_AbCdEf...",
  "topup_package_id": "topup_test_5gb_15d",
  "topup_package": {
    "id": "topup_test_5gb_15d",
    "name": "Top-up 5GB / 15d",
    "data_mb": 5120,
    "validity_days": 15
  },
  "amount_sar": 37.50,
  "customer_reference": "cust_42",
  "created_at": "2026-06-21T08:30:00Z"
}

Error codes

CodeHTTPMeaning
esim_not_found
404
No eSIM with that id belongs to your account.
topup_not_supported
409
The eSIM's plan does not allow top-ups.
topup_package_unavailable
404
The chosen package id is not in the eSIM's compatible list (always refresh from GET /v1/esims/{id}/topup-packages).
esim_not_topupable
409
The eSIM is expired, cancelled, or not yet issued.
insufficient_funds
402
Wallet balance or credit line cannot cover price_sar.

Webhook events

EventWhen
order.topup.completedTop-up applied successfully. Payload includes order_id, parent_order_id, esim_id, iccid, topup_package_id, amount_sar.
order.topup.failedTop-up could not be applied. Payload includes esim_id, topup_package_id, code, reason.