# Idempotency keys

> Make a retried POST do its work exactly once by remembering the client’s request key.

Concept · Networking & APIs · https://levelcode.org/concepts/idempotency-keys

An operation is **idempotent** if doing it twice has the same effect as doing it once. `GET`, `PUT` and `DELETE` are idempotent by definition; `POST` — create an order, charge a card, send a message — usually isn't. Yet clients must retry POSTs, because a timeout doesn't tell them whether the server did the work.

An **idempotency key** fixes that. The client generates a unique key per logical operation and sends it with every attempt:

```http
POST /v1/payments
Idempotency-Key: 5f8a2c1e-8d3b-4e7a-9c55-0b6c1f7a2d90
Content-Type: application/json

{"order_id": "ord_981", "amount": 4200, "currency": "usd"}
```

## Server behaviour

1. **First request with a key:** atomically record the key as "in progress" (a unique constraint makes this safe under concurrency), do the work, then store the response with the key.
2. **Repeat with the same key and body:** return the stored response without doing the work again.
3. **Repeat while the first is still running:** return `409 Conflict` (or wait), never run it in parallel.
4. **Same key, different body:** reject with `422`, because it's a client bug.

Keep keys long enough to cover retries — 24 hours is common — and scope them per client or API key so different clients can't collide.

## Getting the details right

- **Store the key in the same transaction as the effect** when the effect is in your database, so a crash can't leave one without the other.
- **Pass keys downstream.** If your handler calls a payment provider, derive *its* idempotency key from yours (or from your payment ID), so your retries can't create a second charge there.
- **Generate the key once per user action**, on the client, before the first attempt — not on each retry.

The same idea applies to message processing: see [idempotent consumers](https://levelcode.org/concepts/idempotent-consumers) and [delivery guarantees](https://levelcode.org/concepts/delivery-semantics). The System Design roadmap's payment lesson builds a complete idempotency layer.
