Lesson 30 of 30
Calling the same request twice should either be obviously safe or obviously not — idempotency is the precise, checkable property that tells you which, and it's the reason retry logic doesn't just create duplicate side effects.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
A payment POST request times out. Is it safe to simply retry it exactly as-is?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
An operation is idempotent if calling it once has the exact same effect as calling it many times with the same input. This isn't about the response being identical — it's about the resulting state being identical.
PUT /users/42 { name: "Ada" } — idempotent: calling it 5 times still leaves name = "Ada"
DELETE /users/42 — idempotent: already deleted? still deleted. Same end state.
GET /users/42 — idempotent (and safe: no side effects at all)
POST /orders { item: "widget" } — NOT idempotent: calling it 5 times creates 5 orders
This maps directly onto HTTP method semantics, by design: GET, PUT, DELETE are specified to be idempotent; POST and PATCH generally are not. This isn't just a convention — it's exactly why a browser can safely auto-retry a failed GET without asking, but warns you before resubmitting a POST form.
POST /payments times out. Did it actually succeed server-side before the response got lost? You genuinely can't know.
POST /payments
Idempotency-Key: 7f3a9c21-...
# retrying with the SAME key returns the original result, doesn't create a second payment
The client generates a unique key once per logical operation and includes it on every retry attempt. The server stores "I've already processed this key" — a retry with the same key returns the original result instead of re-executing the (non-idempotent) operation a second time. This is the standard pattern real payment APIs (Stripe and others) use specifically for this reason.
DELETE clearly has a side effect (something gets deleted) — it's idempotent because repeating it doesn't change the outcome further, not because it does nothing.PATCH being "generally not idempotent" depends on what it expresses — a PATCH that sets an absolute value ({ status: "shipped" }) is idempotent; one that expresses a relative change ({ increment: 1 }) is not, for the same reason POST /orders isn't."Your app's payment request times out — is it safe to retry?" is a real, high-stakes question, and the correct answer (only if the operation is idempotent, or protected by an idempotency key) is a strong, concrete signal about understanding failure modes in distributed systems, not just happy-path API design.