Objects
Every endpoint returns one of the objects on this page, or a list of them. The same objects are used in the sandbox and in live.
Used wherever an amount appears.
| Field | Type | Nullable | Description |
|---|---|---|---|
amount |
string | No | A decimal number with two decimal places, such as "249.00". |
currency |
string | No | The ISO 4217 currency code. It is INR. |
Package
Section titled “Package”One plan you can sell. Returned by the catalogue and by top-up packages.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | No | The package id, pkg_ and a number, such as pkg_10482. Send it as package_id when you order. |
name |
string | No | The display name of the plan. |
type |
string | No | country, region or global. |
country |
string | Yes | The two-letter country code for a country package. null for a package that covers more than one country. |
countries |
array of strings | No | The two-letter codes of every country the package works in. |
data_mb |
integer | Yes | The data allowance in megabytes. null when the package is unlimited, and only then. For a package with a daily allowance, such as “2 GB/Day”, it is the amount for one day. |
unlimited |
boolean | No | true when the package has no data cap. |
validity_days |
integer | No | How many days the plan lasts once it starts. |
price |
Money | No | What the package costs you: the retail price less your partner discount. This is the amount charged to your balance for one eSIM. |
retail_price |
Money | No | The price eSIMify sells the same package for. |
topup |
boolean | No | true when this package can be bought as a top-up. It is true for every package in the list today. Which packages one eSIM can take is answered by its top-up packages. |
{ "id": "pkg_10482", "name": "Thailand 1 GB 7 days", "type": "country", "country": "TH", "countries": [ "TH" ], "data_mb": 1024, "unlimited": false, "validity_days": 7, "price": { "amount": "249.00", "currency": "INR" }, "retail_price": { "amount": "349.00", "currency": "INR" }, "topup": true}A purchase of one or more eSIMs. Returned by the orders endpoints and inside order.completed and order.failed events.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | No | The order id. It starts with ord_. Sandbox orders start with ord_test_. |
status |
string | No | processing, completed, partially_completed, failed or cancelled. See Order status. |
mode |
string | No | test or live. |
package_id |
string | Yes | The package that was bought. null when the order holds more than one package: read items. |
quantity |
integer | Yes | How many eSIMs were ordered. null when the order holds more than one package: read items. |
items |
array of objects | No | What was bought, one entry for each package. An order placed through the API always has exactly one entry. An order placed in the Business portal can have several. |
items[].package_id |
string | No | The package. |
items[].quantity |
integer | No | How many eSIMs of it were ordered. |
customer_ref |
string | Yes | Your own reference, as you sent it. null when you sent none or an empty string. |
total |
Money | No | The amount charged to your balance for the order. |
refunded |
Money | No | The amount returned to your balance. "0.00" when nothing was returned. |
balance_after |
Money | No | Your balance right after the order was charged. It does not include refunded: for a failed or partially completed order your balance is balance_after plus refunded. |
created |
string | No | When the order was created. ISO 8601, UTC. |
esims |
array of objects | No | One entry for each eSIM that was issued. It can be incomplete or empty while the order is processing, is shorter than the quantity when it is partially_completed, and is empty when it failed. |
esims[].iccid |
string | No | The ICCID of the eSIM. |
esims[].status |
string | No | The eSIM status. |
{ "id": "ord_test_3f9a1c2b7d4e", "status": "completed", "mode": "test", "package_id": "pkg_10482", "quantity": 1, "items": [ { "package_id": "pkg_10482", "quantity": 1 } ], "customer_ref": "booking-84512", "total": { "amount": "249.00", "currency": "INR" }, "refunded": { "amount": "0.00", "currency": "INR" }, "balance_after": { "amount": "999751.00", "currency": "INR" }, "created": "2026-10-02T09:14:07Z", "esims": [ { "iccid": "8999999000000012345", "status": "ready" } ]}One eSIM. Returned in full by GET /v1/esims/{iccid}. The list endpoint returns the same object without activation.
| Field | Type | Nullable | Description |
|---|---|---|---|
iccid |
string | No | The ICCID. It identifies the eSIM in the API. Sandbox ICCIDs start with 8999999. |
status |
string | No | ready, active, depleted, expired or cancelled. See eSIM status. |
mode |
string | No | test or live. |
order_id |
string | Yes | The order the eSIM was issued for. |
customer_ref |
string | Yes | The customer_ref of that order. |
package |
object | No | The package the eSIM was bought with. |
package.id |
string | Yes | The package id. |
package.name |
string | No | The package name. |
qr_code_url |
string | Yes | The address of a PNG image of the QR code. It needs no API key. null for a cancelled eSIM, and in the rare case the install details are not stored yet. See the QR code image. |
activation |
object | No | The install details. Present when you fetch one eSIM, left out of lists. |
activation.lpa |
string | Yes | The full activation string, in the form LPA:1$address$code. null for a cancelled eSIM, and in the rare case the install details are not stored yet: fetch again. |
activation.smdp_address |
string | Yes | The SM-DP+ address, for manual entry. null in the same cases. |
activation.activation_code |
string | Yes | The activation code, for manual entry. null in the same cases. |
install_links |
object | No | One-tap install links. |
install_links.ios |
string | Yes | Opens eSIM setup on an iPhone. The activation string in it is percent-encoded: use the link as returned. null in the same cases as activation.lpa. |
install_links.android |
string | Yes | Opens eSIM setup on an Android phone. The same rules apply. |
data |
object | No | Data usage. |
data.unlimited |
boolean | No | true for an unlimited plan. |
data.total_mb |
integer | Yes | The total allowance in megabytes, completed top-ups included. null for an unlimited plan. |
data.used_mb |
integer | No | Megabytes used so far. Never more than total_mb. |
data.remaining_mb |
integer | Yes | Megabytes left. null for an unlimited plan. |
validity_days |
integer | No | How many days the plan lasts once it starts, completed top-ups included. |
activated_at |
string | Yes | When the eSIM was first used. null until then. |
expires_at |
string | Yes | When the plan ends. null until the eSIM is activated. |
created |
string | No | When the eSIM was issued. ISO 8601, UTC. |
{ "iccid": "8999999000000012345", "status": "ready", "mode": "test", "order_id": "ord_test_3f9a1c2b7d4e", "customer_ref": "booking-84512", "package": { "id": "pkg_10482", "name": "Thailand 1 GB 7 days" }, "qr_code_url": "https://api.example.com/partner/api/v1/qr/ODk5OTk5OTAwMDAwMDAxMjM0NQ.3f9a1c2b5e8d7c6b4a39281706f5e4d3c2b1a098.png", "activation": { "lpa": "LPA:1$sandbox.esimify.in$TEST-A1B2C3D4E5F6", "smdp_address": "sandbox.esimify.in", "activation_code": "TEST-A1B2C3D4E5F6" }, "install_links": { "ios": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24sandbox.esimify.in%24TEST-A1B2C3D4E5F6", "android": "https://esimsetup.android.com/esim_qrcode_provisioning?carddata=LPA%3A1%24sandbox.esimify.in%24TEST-A1B2C3D4E5F6" }, "data": { "unlimited": false, "total_mb": 1024, "used_mb": 0, "remaining_mb": 1024 }, "validity_days": 7, "activated_at": null, "expires_at": null, "created": "2026-10-02T09:14:07Z"}eSIM summary in events
Section titled “eSIM summary in events”The esim.* events carry a shorter form of the eSIM, with these fields only: iccid, status, order_id, customer_ref, data and expires_at. They mean the same as above, and show the eSIM as it was when the event was created. Fetch the eSIM if you need the rest.
{ "iccid": "8999999000000012345", "status": "active", "order_id": "ord_test_3f9a1c2b7d4e", "customer_ref": "booking-84512", "data": { "unlimited": false, "total_mb": 1024, "used_mb": 0, "remaining_mb": 1024 }, "expires_at": "2026-10-09T11:02:40Z"}A package added to an existing eSIM. Returned by the top-up endpoints and inside topup.completed events.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | No | The id of the top-up: top_ and lower-case letters and digits. Sandbox top-ups are top_test_ and 12 hex characters. |
status |
string | No | completed, processing or failed. Check it before you tell the customer. completed means the package was added. failed means nothing was added and the amount was returned to your balance. |
iccid |
string | No | The eSIM that was topped up. |
package_id |
string | No | The package that was added. |
customer_ref |
string | Yes | Your own reference for the top-up. null when you sent none. |
total |
Money | No | The price of the top-up. |
balance_after |
Money | No | Your balance right after the top-up was charged. For a failed top-up it is the balance after the amount was returned. |
created |
string | No | When the top-up was created. ISO 8601, UTC. |
{ "id": "top_test_7a1c9e02b4d6", "status": "completed", "iccid": "8999999000000012345", "package_id": "pkg_10482", "customer_ref": "booking-84512-topup-1", "total": { "amount": "249.00", "currency": "INR" }, "balance_after": { "amount": "999502.00", "currency": "INR" }, "created": "2026-10-04T06:30:12Z"}Something that happened on your account. Sent to your webhook endpoints and returned by the events endpoints.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | No | The event id, evt_ and 24 hex characters. Use it to ignore repeats. |
type |
string | No | The event type, such as order.completed. See Event types. |
mode |
string | No | test or live. |
created |
string | No | When the event was created. ISO 8601, UTC, to the second. |
sequence |
integer | No | A number that grows with every event on your account, counted separately for test and live. Use it to put events in order. Numbers can be skipped. 0 on a ping. |
data |
object | No | The object the event is about. Its shape depends on type. |
{ "id": "evt_5b81c0d2e4f6a7b8c9d0e1f2", "type": "order.completed", "mode": "test", "created": "2026-10-02T09:14:08Z", "sequence": 41, "data": { "id": "ord_test_3f9a1c2b7d4e", "status": "completed", "mode": "test", "package_id": "pkg_10482", "quantity": 1, "items": [ { "package_id": "pkg_10482", "quantity": 1 } ], "customer_ref": "booking-84512", "total": { "amount": "249.00", "currency": "INR" }, "refunded": { "amount": "0.00", "currency": "INR" }, "balance_after": { "amount": "999751.00", "currency": "INR" }, "created": "2026-10-02T09:14:07Z", "esims": [ { "iccid": "8999999000000012345", "status": "ready" } ] }}The body of every response with a 4xx or 5xx status. See Errors & rate limits for every code.
| Field | Type | Nullable | Description |
|---|---|---|---|
error |
object | No | The wrapper. |
error.code |
string | No | A stable code for your program to act on, such as insufficient_balance. |
error.message |
string | No | A sentence for a developer to read. Do not show it to customers and do not match on its text. |
error.request_id |
string | No | The id of the request, the same as the X-Request-Id header. |
error.param |
string | Optional | The field or header that was wrong. Present when one field or header is at fault, absent otherwise. |
{ "error": { "code": "invalid_request", "message": "quantity must be an integer between 1 and 50.", "request_id": "req_7c1d92ab34ef5a60", "param": "quantity" }}
