Skip to content
Preview. The Partners API is not live yet, so details on this page can change before launch.

Orders

An order buys one package, one or more times. Each unit becomes one eSIM. The order total is charged to your partner balance when the order is created, at the package’s price at that moment.

Method Path What it does
POST /v1/orders Buy one or more eSIMs.
GET /v1/orders/{id} Get one order.
GET /v1/orders List your orders, newest first.
Status Meaning Final
processing The order is accepted and charged. The eSIMs are still being issued. esims lists the ones issued so far. No
completed Every eSIM was issued. Yes
partially_completed Some eSIMs were issued and some were not. esims holds the ones that were, and refunded holds the amount returned to your balance. Yes
failed No eSIM was issued. refunded holds the amount returned to your balance. Yes
cancelled The order was cancelled in the Business portal or by eSIMify support, before its eSIMs were used. refunded holds the amount returned. No webhook is sent. Yes

An order in processing moves to one of the final statuses on its own. You are told by the order.completed or order.failed webhook, or you can fetch the order again. Most orders finish within a few minutes. An order that makes no progress for 15 minutes is settled automatically: the eSIMs that were not issued are refunded.

order.completed is sent for completed and for partially_completed orders. Always read status and count esims: a partially completed order holds fewer eSIMs than quantity, and refunded shows what went back to your balance.

A supplier failure in live does not give an error response. It gives an order with the status failed or partially_completed, answered with 201.

Top-ups are not orders. They are not in this list. See Top-ups.

Orders your staff place in the Business portal appear here too, and send the same events. Such an order can hold several packages. Then items lists them and the top-level package_id and quantity are null.

eSIMify does not email or message your customer. Delivery is yours. See Delivering eSIMs.

POST /v1/orders

Buys quantity eSIMs of one package.

The call waits up to about 20 seconds for the eSIMs. Set your HTTP client timeout to at least 30 seconds. If the eSIMs are not all issued by then, the order comes back as processing and finishes in the background. This is more likely for large quantities.

Name In Type Required Description
Idempotency-Key header string Yes 1 to 255 characters. Identifies this purchase on your side. Use a new one for each new order. See Idempotency.
package_id body string Yes The exact id of the package to buy, such as pkg_10482.
quantity body integer No How many eSIMs, from 1 to 50. Default 1. It must be a JSON number: "2" is refused.
customer_ref body string No Your own reference for the sale, up to 120 characters. It is copied to the order and to each eSIM, and you can filter by it.
customer body object No Optional details of the traveller. They are shown to your staff on the order in the Business portal. They are not returned by the API, and eSIMify never uses them to contact the traveller.
customer.name body string No The traveller’s name, up to 120 characters.
customer.email body string No The traveller’s email address, up to 254 characters. It must be one valid address.
Terminal window
curl -X POST "$ESIMIFY_API_URL/v1/orders" \
-H "Authorization: Bearer $ESIMIFY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: booking-84512" \
-d '{
"package_id": "pkg_10482",
"quantity": 1,
"customer_ref": "booking-84512"
}'

201 Created with the new Order.

{
"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"
}
]
}

If you send the same Idempotency-Key and the same body again, you get 200 OK, the same order, and the header Idempotent-Replayed: true. Nothing is bought twice. The replay is the first response as it was sent: fetch the order for its current state. This also applies to an order that failed: to try again, use a new Idempotency-Key.

Check status before you deliver. Most orders are completed in the same call. An order can also come back as processing:

{
"id": "ord_test_91b7e04c5a2d",
"status": "processing",
"mode": "test",
"package_id": "pkg_10482",
"quantity": 1,
"items": [
{
"package_id": "pkg_10482",
"quantity": 1
}
],
"customer_ref": "test_processing-84513",
"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": []
}
Status Code When
400 invalid_request package_id is missing, quantity is not a whole number from 1 to 50, customer_ref or customer.name is longer than 120 characters, customer.email is not a valid address, a text field has control characters, the Idempotency-Key is longer than 255 characters, or the body is not a JSON object. param names the field when one field is at fault.
400 idempotency_key_required A POST was sent without an Idempotency-Key header.
402 insufficient_balance Your balance does not cover the order. Nothing was bought. Add funds and send the same request again with the same key.
404 package_not_found No package you can sell has this id.
409 idempotency_key_reused This Idempotency-Key was already used with a different request body.
409 request_in_progress A request with the same Idempotency-Key is still being processed. Wait a moment and send it again.
503 supplier_unavailable Sandbox only: returned for the test_supplier_down trigger. In live, a supplier failure gives an order with the status failed and a full refund. Retry a 503 with the same Idempotency-Key.

Any endpoint can also return the common errors.

GET /v1/orders/{id}

Returns one order with the eSIMs issued for it.

Name In Type Required Description
id path string Yes The order id, such as ord_test_3f9a1c2b7d4e.
Terminal window
curl "$ESIMIFY_API_URL/v1/orders/ord_test_3f9a1c2b7d4e" \
-H "Authorization: Bearer $ESIMIFY_API_KEY"

200 OK with an Order.

{
"id": "ord_test_3f9a1c2b7d4e",
"status": "completed",
"mode": "test",
"package_id": "pkg_10482",
"quantity": 3,
"items": [
{
"package_id": "pkg_10482",
"quantity": 3
}
],
"customer_ref": "booking-84512",
"total": {
"amount": "747.00",
"currency": "INR"
},
"refunded": {
"amount": "0.00",
"currency": "INR"
},
"balance_after": {
"amount": "999253.00",
"currency": "INR"
},
"created": "2026-10-02T09:14:07Z",
"esims": [
{
"iccid": "8999999000000012345",
"status": "ready"
},
{
"iccid": "8999999000000012346",
"status": "ready"
},
{
"iccid": "8999999000000012347",
"status": "ready"
}
]
}

esims lists only the units that were issued. Fetch each one with GET /v1/esims/{iccid} for its install details.

Status Code When
404 order_not_found No order has this id for your account in this mode. A live key cannot see sandbox orders, and a test key cannot see live ones. Ids are exact and lower case.

Any endpoint can also return the common errors.

GET /v1/orders

Returns your orders, newest first. Top-ups are not included.

Name In Type Required Description
status query string No One order status: processing, completed, partially_completed, failed or cancelled.
customer_ref query string No Orders with exactly this customer_ref. Case matters.
created_after query string No ISO 8601 date or timestamp. Orders created at or after it.
created_before query string No ISO 8601 date or timestamp. Orders created before it, not including that instant.
limit query integer No 1 to 100. Default 25.
cursor query string No The next_cursor of the previous page.
Terminal window
curl "$ESIMIFY_API_URL/v1/orders?customer_ref=booking-84512" \
-H "Authorization: Bearer $ESIMIFY_API_KEY"

200 OK with a list of Order objects.

{
"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"
}
]
}
],
"has_more": false,
"next_cursor": null
}

The two time filters make a half-open window: created_after is included and created_before is not. Two windows that share a boundary, such as one day and the next, never miss an order and never return one twice. A value without a zone is read as UTC. created in the response is given to the second, while the filters compare to the millisecond, so to page through new orders use cursor, not the created of the last order you saw.

Status Code When
400 invalid_request A query parameter is not valid, for example an unknown status, a timestamp that is not ISO 8601, or a date that does not exist. param names it.

Any endpoint can also return the common errors.