Idempotency
Networks drop. Timeouts happen. 503s happen. Idempotency keys make POSTs safe to retry without creating duplicate shipments.
The Idempotency-Key header
Send a unique Idempotency-Key on every POST — UUID v4 recommended. The first request is processed normally and the result is cached against the key; subsequent calls with the same key return the cached response without re-running the operation.
curl https://imileexpress.com/api/v1/shipments \ -H "Authorization: Bearer mk_test_rh9ABekJfP31cN7sQ8jKvLwY" \ -H "Idempotency-Key: 5f3c7a44-2d2b-4f63-a8b1-9c0f1d8e7b62" \ -H "Content-Type: application/json" \ -d '{ "service_tier_id": "HKASTDGGSTCM", "recipient": {...}, ... }' # Same key + same body → identical response, no duplicate shipment. # Same key + different body → 409 Conflict (sys_code 1409002)
⚠ One key = one order
An Idempotency-Key identifies one logical request — not your account, and not your integration. Every new order needs a new, unique key. Hard-coding a single key in a script or an API client (Postman, Insomnia) is the most common integration mistake we see.
The cache stores failed responses too. If an order is rejected with a 409 because the wallet balance was too low, then you top up and retry with the same key, you will get that same stale 409 back — the balance is never re-checked, the cached response is simply replayed. Retry with a fresh key and the request is processed from scratch.
In practice: generate a UUID v4 at the moment you build the request and store it alongside your order record, then reuse it only when retrying that same order. In Postman, set the header value to {{$guid}} so a new key is generated on every send.
Per-endpoint requirement
Not every mutating endpoint needs an Idempotency-Key. Create-style endpoints (which mint a new resource / debit the wallet) require it; endpoints that are naturally idempotent (delete, cancel, rotate) treat it as optional.
| Endpoint | Idempotency-Key | Why |
|---|---|---|
| POST /api/v1/shipments | REQUIRED | Creates a shipment & debits the wallet — retries must not duplicate. |
| POST /api/v1/webhooks | REQUIRED | Creates a new webhook endpoint — retries must not duplicate. |
| DELETE /api/v1/webhooks/{id} | OPTIONAL | Naturally idempotent — deleting twice has the same effect. |
| POST /api/v1/shipments/{id}/cancel | OPTIONAL | Naturally idempotent — cancelling an already-cancelled shipment is a no-op. |
| POST /api/v1/webhooks/{id}/rotate | OPTIONAL | Naturally idempotent — converges on resource state, safe to retry. |
24-hour window
Cached responses live for 24 hours — both successes (2xx) and client errors (4xx) are cached. After that, the same key is treated as a fresh request. Server errors (5xx) are never cached, so retrying with the same key re-runs the operation.
Conflicts
Same key, different body → rejected with 409 (sys_code 1409002). The error message includes a digest of the original body so you can identify the mismatch.