- Home
- Blog
- API & Integration
- eSIM API Error Handling and Idempotency: Never Double-Charge an Order
eSIM API Error Handling and Idempotency: Never Double-Charge an Order
eSIM API idempotency means sending a unique key with every order so a retried request returns the original order instead of buying a second eSIM. Combine it with timeouts, clear handling of balance and catalogue errors, webhooks and daily reconciliation, and your integration will never double-charge a customer. Fully Signal's REST API supports idempotent orders and a free sandbox to test every case.
In this article
An eSIM order spends real money from your balance. If your server times out and retries, you must not buy the same eSIM twice. This guide covers eSIM API idempotency and the error cases every integration should handle before going live.
What is idempotency in an eSIM API?
An operation is idempotent when doing it twice has the same effect as doing it once. For eSIM orders, you send a unique idempotency key (for example your own order ID) with the request. If the same key arrives again, the API returns the original result instead of creating a new order.
Without it, this happens:
- Your server sends "order 1 × Italy 5 GB".
- The order succeeds, but the response is lost to a network timeout.
- Your code retries.
- A second eSIM is bought and charged.
With an idempotency key, step 4 returns the eSIM from step 2.
Rules for safe retries
- One key per customer order, generated before the first attempt and stored with the order.
- Reuse the key on every retry of that order — never generate a new one inside the retry loop.
- Retry only on network errors, timeouts and 5xx responses. A 4xx means the request itself is wrong; fix it rather than retrying.
- Back off: wait 1s, 2s, 4s… with a cap, rather than retrying instantly.
- Set a sensible timeout so a slow request does not hold your checkout forever.
order_key = "shop-order-10482" # stored before the first call
for attempt in 1..5:
response = POST /orders {plan, quantity: 1} Idempotency-Key: order_key
if response.ok: save eSIM; break
if response.status in 400..499: mark order failed; alert; break
sleep(min(2 ** attempt, 30))
The exact header and endpoint names are in the API documentation inside the Fully Signal partner panel.
Error cases to handle
| Situation | What it means | What to do |
|---|---|---|
| Insufficient balance | Your prepaid balance cannot cover the order | Stop, alert your team, show the customer a friendly delay message |
| Plan unavailable | The plan was changed or withdrawn from the catalogue | Refresh your catalogue; offer the closest alternative |
| Invalid request | Missing or wrong field | Log it and fix your code; do not retry |
| Authentication error | Wrong, revoked or test-vs-live key mismatch | Check the key and IP allowlist |
| Timeout / 5xx | Temporary problem | Retry with the same idempotency key |
Keep your catalogue fresh
Most "plan unavailable" errors come from stale catalogues. Sync the catalogue regularly through the API and check prices at checkout time rather than caching them for weeks. Fully Signal refreshes its catalogue continuously.
Use webhooks, not polling
After ordering, the eSIM moves through states (issued, installed, data used, expired). Subscribe to webhooks instead of polling status in a loop — see eSIM webhooks. Make your webhook handler idempotent too: the same event may arrive more than once, so store event IDs and ignore duplicates.
Reconcile daily
Once a day, compare:
- Orders in your database
- Orders in the partner panel / API order list
- Balance movements on your statement
Any difference — an order you charged the customer for but never received, or the reverse — shows up within 24 hours instead of at month end.
Test every case in the sandbox
The free sandbox uses test keys and sample data, and nothing is charged, so you can force timeouts, retry with the same key, and confirm only one order exists. Our sandbox testing guide has a full test plan.
Security checklist
- Separate test and live keys; never ship a live key in a mobile app
- Scoped API keys with only the permissions each service needs
- IP allowlists for your servers
- Rotate keys when staff leave
FAQ
What is an idempotency key?
A unique value you send with a request so the server can recognise repeats. If the same key arrives twice, the server returns the first result instead of acting again.
When should I retry an eSIM order?
Only after network errors, timeouts or 5xx server errors, always with the same idempotency key and with increasing waits between attempts.
Should I retry a 4xx error?
No. A 4xx error means the request was rejected — for example invalid data or insufficient balance. Fix the cause first.
Can webhooks arrive twice?
Yes, webhook systems may deliver an event more than once. Store event IDs and ignore duplicates.
How do I test error handling without spending money?
Use the sandbox with test keys. Nothing is charged, so you can simulate retries and failures safely.