Idempotency
Retry writes safely without applying them twice.
Networks fail. If a write times out you can't tell whether it reached Zaher — and retrying something like "adjust stock by -3" blindly could apply it twice.
Every write endpoint (POST and PATCH) accepts an Idempotency-Key header.
Send a unique value per change, and send the same value when you retry it:
curl https://api.zaher.io/v1/products/PRODUCT_ID/variants/VARIANT_ID/stock \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 0b8f6d1e-2c3a-4f5b-9e7d-1a2b3c4d5e6f" \
-d '{ "mode": "adjust", "quantity": -3 }'How it behaves
| Situation | Result |
|---|---|
| First request with a key | Runs normally; the result is kept for 24 hours |
| Retry with the same key and body | The first result is returned again, with Idempotent-Replayed: true. Nothing runs twice |
| Same key, different body or endpoint | 409 idempotency_mismatch |
| Retry while the first is still running | 409 idempotency_in_progress — wait and retry |
The first request failed with a 5xx | The key is released, so your retry runs for real |
Results of 4xx errors are kept too: retrying a request that was rejected
returns the same rejection.
Choosing keys
- Use a UUID per change, or derive one from your own data — e.g.
shipment-{your shipment id}— so a crashed job that restarts reuses it. - Keys are scoped to your store and are up to 255 characters.
- Don't reuse a key for a different change.
Reads don't need it
GET requests never change anything and are always safe to retry.