Why idempotency? Networks drop, clients retry, and messages can arrive twice. Idempotent APIs make those retries safe by ensuring that repeating the same request leads to the same effect and response.
1) Keys: how we identify a logical request
- Client-provided key: we accept an
Idempotency-Keyheader for POST/PUT endpoints that have side-effects. The same key + same payload equals the same operation. - Deterministic server key: if clients cannot supply a key, we derive one from stable fields (e.g., customerId + orderId + opType).
- Storage: we persist {key, request hash, response, status, ttl}. A repeat with the same key returns the original response; a different payload with the same key is rejected with a clear error.
2) Dedupe windows
Keys live for a bounded window (e.g., 24–72h). We use a TTL cache or a unique index with expiry so a replay outside the window is treated as new.
3) Retries & backoff
- When to retry: transient failures (5xx/429/timeouts). Do not retry hard 4xx.
- How to retry: exponential backoff + jitter, capped attempts; include the same idempotency key on each retry.
- Idempotent methods: GET/HEAD/DELETE are defined idempotent by HTTP semantics; creation endpoints must implement idempotency explicitly.
4) Exactly-once effects over at-least-once
In messaging we assume at-least-once delivery. We achieve exactly-once effects by combining dedupe (idempotent receiver), transactional outbox, and consumer-side processing that ignores duplicates. Systems like Kafka provide producer idempotence/transactions to help enforce this at scale.
5) Pitfalls to avoid
- Non-deterministic fields in payload (timestamps, random IDs) that change the hash.
- Generating irreversible side-effects before key check (e.g., charging, emailing) — always validate the key first.
- Unbounded key retention leading to hot storage; set sensible TTLs and monitoring.
Checklist
- Accept/derive an
Idempotency-Keyand persist response by key. - Use TTL + unique constraint to enforce a dedupe window.
- Retry with backoff+jitter only on retryable classes (5xx/429/timeouts).
- For messaging, pair idempotent receivers with an outbox or transactions.
Call to action
Need help hardening your endpoints? We can review one critical flow and deliver an idempotency+retries blueprint tailored to your stack.