What Is Idempotency in REST APIs?
Learn what idempotency means in REST APIs, why PUT and DELETE are idempotent, and how idempotency keys make POST retries safe.
Expected Interview Answer
An idempotent operation is one that produces the same server-side result no matter how many times an identical request is sent, so retrying it after a timeout or network failure is always safe.
Idempotency is about the end state on the server, not about whether the response body looks identical on every call. Sending PUT /users/42 with the same payload five times leaves the user record in exactly the same state as sending it once, so it is idempotent even though each response might include a fresh timestamp. DELETE is idempotent because deleting an already-deleted resource still leaves it deleted, even if the second call returns 404 instead of 200. POST is the classic non-idempotent case: submitting “create an order” twice usually creates two orders, which is why idempotency keys are layered on top of POST for payment and order APIs to make retries safe. Client and proxy retry logic relies on this contract, so servers must actually implement the guarantee, not just document it.
- Makes network retries after timeouts safe without duplicating side effects
- Lets load balancers and clients resend requests without extra coordination
- Simplifies distributed system design around at-least-once delivery
- Forms the basis for idempotency-key patterns on inherently non-idempotent POST calls
AI Mentor Explanation
Idempotency is like a scorer entering “set the total to 180 for 4 wickets” on the digital board. Whether that instruction is sent once or accidentally sent three times because the network blipped, the board still reads 180 for 4 at the end. Compare that to “add one run,” which is not idempotent because repeating it by accident inflates the score. The board update is safe to resend precisely because it states a final value rather than an incremental change.
Step-by-Step Explanation
Step 1
Identify the operation type
Determine whether the request sets an absolute state (idempotent) or appends/increments (non-idempotent).
Step 2
Design for retry safety
Use PUT or DELETE semantics for state-setting operations so clients can safely resend them.
Step 3
Add idempotency keys where needed
For inherently non-idempotent operations like POST payments, require a client-generated key the server deduplicates against.
Step 4
Verify server-side enforcement
Confirm the server actually deduplicates or converges to the same state, not just that the API contract claims idempotency.
What Interviewer Expects
- Correct definition centered on end server state, not identical response bodies
- Accurate classification of GET, PUT, DELETE as idempotent and POST as not
- Mention of idempotency keys as the pattern for safe POST retries
- Understanding of why this matters for network retries and distributed systems
Common Mistakes
- Confusing idempotent with “returns the exact same response body every time”
- Claiming POST can never be made retry-safe, ignoring idempotency keys
- Assuming DELETE is not idempotent because the second call returns 404
- Mixing up idempotency with safety (GET has no side effects) as if they were the same property
Best Answer (HR Friendly)
“Idempotency means that if you send the exact same request multiple times, the end result on the server stays the same as if you had sent it just once. This is important because networks are unreliable, so clients often retry requests after a timeout, and idempotent operations make that safe.”
Code Example
// Idempotent: PUT sets an absolute state, safe to retry
app.put('/users/:id', async (req, res) => {
await db.users.upsert({ id: req.params.id, ...req.body })
res.json({ id: req.params.id, ...req.body })
})
// Non-idempotent by default: POST creates a new resource each call
app.post('/orders', async (req, res) => {
const key = req.headers['idempotency-key']
const existing = key && await db.idempotencyKeys.find(key)
if (existing) {
return res.status(200).json(existing.response) // safe replay
}
const order = await db.orders.create(req.body)
if (key) await db.idempotencyKeys.save(key, order)
res.status(201).json(order)
})Follow-up Questions
- Why is DELETE considered idempotent even though the second call often returns a 404?
- How would you design an idempotency-key store for a payments API?
- Is PATCH idempotent? Why does it depend on how it is implemented?
- How does idempotency relate to at-least-once message delivery in queues?
MCQ Practice
1. Which best defines an idempotent HTTP operation?
Idempotency is about converging to the same server-side state, not identical response payloads.
2. Which HTTP method is NOT idempotent by default?
POST typically creates a new resource on every call, so repeating it usually creates duplicates.
3. What pattern makes a POST-based payment endpoint safe to retry?
An idempotency key lets the server recognize a retried request and return the original result instead of creating a duplicate.
Flash Cards
Definition of idempotent? — Repeating the same request produces the same end server state as sending it once.
Is DELETE idempotent? — Yes — deleting an already-deleted resource still leaves it deleted.
Is POST idempotent by default? — No — it typically creates a new resource on each call.
How do you make POST retry-safe? — Use a client-generated idempotency key the server deduplicates against.