Integration guide
Handle failures and retries
The only failure that is genuinely ambiguous is a network timeout. Idempotency keys turn it into a safe, repeatable request.
Idempotency
Send an `Idempotency-Key` header on every `POST /orders`. Use a value that is stable for the purchase — your booking reference, or a UUID you store before calling us. Keys are scoped to your account and environment.
- First request with a key: the order is created and charged, and you get 201.
- Any later request with the same key: the original order is returned with 200 and an Idempotent-Replay: true header. No second eSIM, no second charge.
- A concurrent duplicate hits a database uniqueness rule and takes the same replay path, so parallel retries are safe too.
- Change the key only when you genuinely want another eSIM.
retry policy
async function orderWithRetry(body, key) {
for (let attempt = 1; attempt <= 3; attempt++) {
try {
const res = await fetch(url, { method: "POST", headers: { ...h, "Idempotency-Key": key }, body });
if (res.status === 429) { await sleep(60_000); continue; }
if (res.status >= 500) { await sleep(attempt * 2000); continue; }
return res; // 2xx, or a 4xx you must not retry blindly
} catch (networkError) {
await sleep(attempt * 2000); // timeout: resend the identical request
}
}
throw new Error("order unresolved — reconcile with GET /orders");
}When an order times out
Your request may time out after the order has already been created and charged. Resend the identical request with the same idempotency key: you will get the completed order back. If retries are exhausted, reconcile with `GET /orders` and match on `customer.reference` before ever creating a new order.
When money moves
- Debited: after validation, before the profile is allocated. The wallet transaction notes the order ID.
- Refunded: in full, inside the same request, if issuing fails. You end on 502 provider_error with your balance restored.
- Never debited: validation failures, unknown plans, inactive accounts and rate limiting never touch the balance.
- There are no partial charges. An order is completed and paid, or failed and refunded.
Which errors to retry
- Retry with the same key: network timeout, 500 internal_error, 429 rate_limited after Retry-After.
- Retry with a new key only after a deliberate decision: 502 provider_error — you were refunded, so this would be a fresh purchase.
- Do not retry: 400 invalid_request, 402 insufficient_funds (top up first), 403 account_inactive, 404 not_found.
Log the order ID before anything else
Persist the ID from the order response against your booking immediately. It is the key to every subsequent support question, re-delivery and reconciliation.