Skip to main content

Idempotency

Networks fail. If a booking request times out, you can't tell whether Reeds received it. An Idempotency-Key lets you send the same request again without creating or charging twice.

Which requests need a key​

Send an Idempotency-Key header (any unique string up to 200 characters) on every request that creates a delivery or moves money:

  • POST /deliveries
  • POST /deliveries/{id}/book
  • POST /deliveries/{id}/cancel
  • POST /wallet/fund

These requests are refused without a key, with 400 IDEMPOTENCY_KEY_REQUIRED. The header is also accepted on every other POST.

curl -X POST https://api.getreeds.co/shipping/v1/deliveries \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN" \
-H "Idempotency-Key: order-10045-delivery-1" \
-H "Content-Type: application/json" \
-d '{ "quote_id": "qt_2bX9Wn4K", "reference": "ORDER-10045" }'

How it works​

  • Keys are scoped to your account and the mode (Test or Live), and kept for 24 hours.
  • Same key, same body: Reeds returns the original response with the header Idempotent-Replayed: true. Nothing is created or charged twice.
  • Same key, different body: 422 IDEMPOTENCY_KEY_REUSED.
  • Same key while the first request is still running: 409 REQUEST_IN_PROGRESS. Wait a moment and retry.

What is saved, and what releases the key​

Reeds saves and replays a response only when the same request would always get it again.

ResponseWhat happens to the key
2xx successSaved. Retrying replays the response.
400, 404, 422Saved. Retrying replays the error.
401, 402, 403, 409, 429Released. The same request can succeed once the cause is fixed (wallet funded, address confirmed, overdue invoice paid), so retry it with the same key.
5xxReleased only if nothing was saved. See below.

After fixing a 400 or 422, send the corrected request with a new key.

A 5xx after the work was saved​

For a 5xx, the key's record is written in the same database transaction as the work. So:

  • If nothing was saved, the key is released and your retry runs the request again.
  • If the work was saved and the request failed afterwards (while queueing a webhook, for example), your retry replays the saved result like any success.

Either way, retrying a 5xx with the same key is safe. You never get a duplicate.

Choose good keys​

Use a key that identifies the attempt, such as order-10045-delivery-1, or a UUID you store with the order.

  • Generate the key once, before the first attempt, and reuse it for every retry of that attempt.
  • Don't reuse your order number as the key if one order can have several deliveries. Put the order number in reference instead.
  • Don't generate a new key on each retry. That defeats the purpose.

Retry loop with backoff​

This example retries on network errors, 429 and 5xx, waits longer each time (and honours Retry-After), and reuses the same key.

KEY="order-10045-delivery-1"

for attempt in 1 2 3 4 5; do
STATUS=$(curl -s -o response.json -w '%{http_code}' \
-X POST https://api.getreeds.co/shipping/v1/deliveries \
-H "Authorization: Bearer $REEDS_ACCESS_TOKEN" \
-H "Idempotency-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{ "quote_id": "qt_2bX9Wn4K", "reference": "ORDER-10045" }')

# Done unless it is a retryable status (000 means a network error)
case "$STATUS" in 000|429|5??) ;; *) break ;; esac
sleep $((2 ** attempt))
done

cat response.json

For 402 and 403, fix the cause first (fund the wallet, pay the invoice), then send the request again with the same key. Don't loop on them automatically.

Next steps​