Stop 01 · Internet & Backend BasicsTopics · 14/15

Idempotency

Part of the Backend Developer Roadmap

In short

Networks fail at the worst moment. A payment request times out and the app retries. Did the user just pay twice? Idempotency is how good backends make retries safe.

A request is idempotent if making it multiple times has the same effect as making it once — a critical property for safely retrying failed requests, e.g. after a network timeout.

The mascot taps a phone nervously at a chai stall while the chai seller holds up a single receipt.

Think of it like this

Tapping Pay twice at the chai stall

The UPI screen hangs, so you tap Pay again. Panic! But the app reused the same transaction reference, so the bank sees one payment, not two. The chaiwala gets his 20 rupees once. Idempotency means: same request again, same result, no double effect.

Watch it happen

A retry that doesn't charge twice

App
Payments API
Database

POST /pay key=k7

1/6The app sends the payment with an Idempotency-Key header it generated for this one tap.

The big ideas

What you need to know

Same request, same effect

An operation is idempotent if doing it twice leaves things exactly as doing it once.

Which methods are

GET, PUT and DELETE are idempotent by design. POST is not, so a repeated POST can create duplicates.

Idempotency keys

The client sends a unique key with each action. The server stores key plus result and replays it on retries.

Unique constraints as backup

A unique index, for example on order_ref, stops duplicates even if two retries race each other.

See it in code

Walk through the code

js
1const seen = new Map(); // use Redis or a DB table in production2 3app.post("/payments", async (req, res) => {4  const key = req.get("Idempotency-Key");5  if (!key) return res.status(400).json({ error: "Idempotency-Key header required" });6 7  if (seen.has(key)) return res.status(201).json(seen.get(key));8 9  const payment = await charge(req.body.amount); // your payment logic10  seen.set(key, payment);11  res.status(201).json(payment);12});

1/3Demand a key, so every payment can be recognised if it comes again.

The client creates the key once per action, say with crypto.randomUUID(), and reuses it on retries. Real systems also lock the key so parallel retries can't both charge.

Save yourself the pain

Common mistakes

Oops

Automatically retrying POST requests with no key.

Do this instead

Only auto-retry idempotent requests, or add an Idempotency-Key so the server can spot duplicates.

Oops

Generating a fresh key on every retry.

Do this instead

A new key looks like a brand-new payment. Create the key once per user action and keep it for all retries.

Your mission

Make an endpoint retry-safe

~30 min

Quick check

Which of these requests is idempotent?

Go deeper

  1. 1Identify which HTTP methods are idempotent by spec (GET, PUT, DELETE) and which aren't (POST).
  2. 2Design an idempotency-key system for a payment endpoint to prevent double-charging.
  3. 3Understand why retries without idempotency can cause duplicate data or charges.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge