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

Testing your integration

This is a test plan for the sandbox. It needs no knowledge of eSIMs. Work through it top to bottom and tick each check. Every check says what to do and what you should see.

You need:

  • a test key (sk_test_...) and your base URL, from the Business portal under Developers
  • a test-mode webhook endpoint on your staging server, added on the Webhooks tab, and its signing secret
  • a way to see what your server received and stored

Run the checks through your own system where you can, not only with curl. The point is to test your code. The commands below show the API call behind each check.

Terminal window
export ESIMIFY_API_URL="<the base URL from the Developers page>"
export ESIMIFY_API_KEY="sk_test_..."

1. A good key works.

Terminal window
curl -i "$ESIMIFY_API_URL/v1/balance" -H "Authorization: Bearer $ESIMIFY_API_KEY"
  • Status 200. The body has "mode": "test". The response has an X-Request-Id header.

2. A bad key is refused.

Terminal window
curl -i "$ESIMIFY_API_URL/v1/balance" -H "Authorization: Bearer sk_test_wrong"
  • Status 401. The body has "code": "invalid_api_key" and a request_id.
  • Run it once or twice only. Sixty bad keys in 10 minutes block your address for the rest of those 10 minutes.
  • Your system reports a configuration problem and does not retry forever.

3. The destination list loads. Call GET /v1/countries.

  • Your destination picker shows the names from the response.

4. Packages load for one country, across pages. Call GET /v1/packages?country=TH&limit=2, then call again with cursor set to the next_cursor you received.

  • The second page has different packages from the first.
  • Your system stops when has_more is false.
  • Prices are shown with two decimal places and are not rounded wrongly.

5. An unknown package is handled. Call GET /v1/packages/pkg_999999999.

  • Status 404 with "code": "package_not_found". Your system shows a sensible message.

6. A normal order completes. Place an order for one package from check 4, with a fresh booking number as customer_ref and as Idempotency-Key.

  • Status 201. status is completed. esims has one entry whose ICCID starts with 8999999.
  • balance_after is lower than before by total.
  • Your booking is marked as issued and stores the order id and the ICCID.

7. A repeated order is not bought twice. Send exactly the same request again, with the same Idempotency-Key.

  • Status 200. The response has the header Idempotent-Replayed: true. The order id is the same as in check 6.
  • Your system still shows one eSIM for the booking.

8. A reused key with a different body is refused. Send the same Idempotency-Key with a different quantity.

  • Status 409 with "code": "idempotency_key_reused".

9. A missing key is refused. Send an order with no Idempotency-Key header.

  • Status 400 with "code": "idempotency_key_required".

10. A bad quantity is refused. Send an order with "quantity": 51.

  • Status 400 with "code": "invalid_request" and "param": "quantity".

11. An order for several eSIMs works. Send an order with "quantity": 3.

  • esims has three entries with three different ICCIDs. Your system delivers three separate eSIMs.

12. Low balance is handled. Send an order with customer_ref set to test_insufficient_balance-001.

  • Status 402 with "code": "insufficient_balance".
  • The customer is not shown an eSIM. Your team is alerted. The booking can be completed later.

13. A failed order is handled. Send an order with customer_ref set to test_order_failed-001.

  • Status 201. The order has status failed, an empty esims list and refunded equal to total.
  • An order.failed webhook arrives. Your system tells the customer and does not show an eSIM.

14. A slow order is handled. Send an order with customer_ref set to test_processing-001.

  • The response has status processing. Your system shows a waiting state, not an error, and does not order again.
  • Between 10 and 25 seconds later an order.completed webhook arrives and your system delivers the eSIM.
  • GET /v1/orders/{id} now shows completed.

15. An outage is handled. Send an order with customer_ref set to test_supplier_down-001.

  • Status 503 with "code": "supplier_unavailable". Your system retries with the same Idempotency-Key, then gives up cleanly and alerts your team.

In live you are more likely to see check 13, a failed order, than this response. Handle both.

16. The eSIM can be shown. Open the eSIM from check 6 in your product.

  • The QR code image from qr_code_url is displayed.
  • On a phone, the one-tap link from install_links is offered for the right platform.
  • The SM-DP+ address and the activation code are shown for manual entry, each with a copy button.
  • The customer can find the same screen again later.

A sandbox eSIM cannot be installed. This check is about your screens and emails.

17. The test event arrives. Choose Send test event on your webhook endpoint in the portal.

  • The portal shows the result: delivered, with status 200. A test event is not written to the delivery log.
  • Your server received an event with "type": "ping" and accepted its signature.

18. A forged request is refused. Send your webhook endpoint a POST with a valid-looking body and a wrong X-Esimify-Signature. Then send one with no signature header at all.

  • Your server answers 400 both times and stores nothing.

19. eSIM events are handled. For the eSIM from check 6, call the simulate endpoint three times, in this order: activated, usage_80, usage_100. Use a new Idempotency-Key each time.

  • Your server receives esim.activated, esim.usage_80 and esim.usage_100.
  • After each one, your product shows the right state: connected, running low, out of data.
  • GET /v1/esims/{iccid} shows the matching status and data values: active, active, depleted.
  • Sending activated a second time changes nothing and sends no webhook.

20. A repeated event is ignored. Send your webhook endpoint the same request twice: replay a body and its headers that you captured, within 5 minutes. Or make your server answer 500 once, so that the delivery is retried.

  • Your server answers 2xx both times and acts on the event once.

21. A missed event is recovered. Stop your webhook server, place an order, then start the server again.

  • The delivery log shows the delivery as retrying.
  • Your reconciliation job finds the event with GET /v1/events, or the retry arrives, and the order is handled once.

22. Events are put in order. Look at the sequence of the events you received in check 19.

  • Each one is higher than the one before. Your system uses sequence, not arrival order, to decide which event is newer.

23. A top-up works. For the eSIM from check 6, call GET /v1/esims/{iccid}/topup-packages, then POST /v1/esims/{iccid}/topups with one of the packages.

  • Status 201. The response is a top-up with status completed.
  • A topup.completed webhook arrives.
  • GET /v1/esims/{iccid} shows more data than before, and status is active again.
  • GET /v1/esims/{iccid}/topups lists the top-up.

24. A failed top-up is handled. Send a top-up with customer_ref set to test_order_failed-001.

  • Status 201, and the top-up has status failed. Your system checks status, tells the customer nothing was added, and does not show more data.

25. An ended plan is handled. For the eSIM from check 6, simulate expired. Then try to top it up again.

  • Your server receives esim.expired and your product shows the plan as ended.
  • The top-up is refused with 409 and "code": "esim_not_topupable". Your product does not offer a top-up for this eSIM.

26. Test data stays in test. If you already have a live key, call GET /v1/orders/{id} with it, using a sandbox order id.

  • Status 404 with "code": "order_not_found".