# Idempotency

> Retry any write safely with an Idempotency-Key.

Source: https://docs.delivr.no/conventions/idempotency/

Networks fail. A request can time out after Delivr has booked the delivery, and a naive retry would book a second one. Idempotency keys make retries safe.

Every write except `POST /v1/merchant/quotes` needs an `Idempotency-Key` header with a UUID. Without one you get `400 idempotency_key_required`.

```bash
curl -X POST https://driver-staging-api.delivr.no/v1/merchant/orders \
  -H "Authorization: Bearer $DELIVR_API_KEY" \
  -H "Idempotency-Key: 0b9f0c4e-6f1d-4a5e-9a3c-2d7e8f1a6b42" \
  -H "Content-Type: application/json" \
  -d @order.json
```

## Rules

Make **one key per logical action**, store it with the action, and send the same key on every retry of it.

| You send                                                                       | You get                                                              |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| The same key and the same request (method, path and JSON body) within 24 hours | The first successful answer again, with `Idempotent-Replayed: true`. |
| The same key with a different request                                          | `422 idempotency_key_reused`.                                        |
| The same key while the first request is still running                          | `409 idempotency_key_in_flight`. Retry shortly with the same key.    |
| A retry after the first attempt was refused or failed                          | A fresh attempt: refused and failed requests free the key.           |

## Built-in idempotency for orders

On top of the key, placing an order is idempotent by `quoteId`, or by `externalRef` when there is no quote. Even with a new key, a second placement for the same quote answers the order already placed.

## Retry strategy

- Retry network errors, `409 idempotency_key_in_flight`, `429` and `503` with the **same key**, with exponential backoff and jitter.
- Respect `Retry-After` on `429`.
- Do not retry other `4xx` answers unchanged: fix the request first.