Skip to content
C Codeloom
Backend

Idempotency Keys Explained: Safe Retries Made Simple

Learn how idempotency keys make APIs safe to retry, with patterns for storage, expiry, conflict handling, and common pitfalls.

·3 min read · By Codeloom
Intermediate 9 min read

What you'll learn

  • What idempotency means in HTTP
  • How to store and key idempotency records
  • Handling conflicts and expirations
  • Where idempotency belongs in the stack
  • Common mistakes to avoid

Prerequisites

  • Familiar with HTTP and databases

What and Why

Networks fail. Retries happen. Without idempotency, a single user click can become two charges, two reservations, or two messages. Idempotency keys let clients retry safely: the server treats repeated requests with the same key as the same operation.

This is mandatory for any API that touches money, inventory, or external side effects.

Mental Model

An idempotency key is a client-chosen unique string attached to a request. The server remembers the result of that key. If the same key comes back, the server returns the original result instead of running the operation again.

Three things matter: the key, the request fingerprint, and the stored response.

Architecture

On first request, the server records (key, fingerprint, response) after the work is done. On a repeat, it checks: same key plus same fingerprint returns the cached response; same key plus different fingerprint is an error (the client reused the key for something else).

Client -> Server (Idempotency-Key: K1)
          |
      Lookup K1
       |       |
     found    not found
       |       |
     same     execute work
     body?      |
     yes -> return cached
     no  -> 422 conflict
                store (K1, fingerprint, response)
                return response
Idempotent request handling

The storage layer is usually Redis with a TTL, or a Postgres table with an indexed key. Redis is faster; Postgres is more durable and lets you do conflict checks in the same transaction as the business work.

Trade-offs

Storing only the key is fastest but means you cannot detect “same key, different request” misuse. Storing the fingerprint catches client bugs at the cost of more memory.

A short TTL (24 hours) keeps the table small but breaks long-running flows. A long TTL covers more cases but grows storage. Match TTL to the retry window of your clients.

In-flight requests are tricky: two requests with the same key arrive simultaneously. A reservation row with a unique constraint lets the first one win and the second one wait or fail predictably.

Practical Tips

Make keys client-generated UUIDs. Server-generated keys defeat the purpose because retries cannot reuse them.

Reject very long keys and any with weird characters. A 64-character cap on alphanumerics plus dashes is a sensible policy.

Persist the response body alongside the status code so retries return byte-identical responses. Clients sometimes parse subtle fields.

Run the idempotency check inside the same transaction as the work. If you check then write in separate transactions, you have a race that lets two operations slip through.

Wrap-up

Idempotency keys are a small primitive with outsized impact. Done right, they turn flaky networks into a non-issue. Done wrong, they create a false sense of safety. Treat the idempotency table as part of your domain model, not an afterthought, and the rest of your reliability work gets much easier.