Ace your next technical interview.
162 real interview questions across 32 companies and 17 roles, each with an expert answer and a plain-English explanation.
Every question, answered seven ways.
One real question from the database, shown exactly as it appears on its own page.
How do you design an idempotent API endpoint, and why does it matter for payment retries?
An idempotent endpoint produces the same result no matter how many times the same request is sent, so a client that times out and retries never causes a duplicate side effect, like charging a customer's card twice for one purchase. The standard pattern is an idempotency key: the client generates a unique token per logical operation (not per HTTP attempt) and sends it in a header, and the server stores the outcome of the first request against that key so any retry with the same key just returns the original result instead of re-executing the operation.
Why retries are unavoidable
Networks fail in ways that leave the client unable to tell whether the server actually processed the request or not, the request could have succeeded and the response got lost. Since the client can't distinguish these cases, it has to retry to be safe, which means the server has to be the one guaranteeing safety, not the client.
Best practice
Store the idempotency key, the request's result, and its status in a fast, durable store (a database row or Redis with an appropriate TTL) keyed by that token, before returning a response. On a retried request, look up the key first, if found, return the stored result immediately without touching the underlying business logic (like charging a card) again.
Edge case interviewers probe for
What happens if a retry arrives while the first request is still in-flight (not yet finished)? A naive check-then-act lookup lets both requests slip through and double-execute; the fix is to atomically claim the key first (an insert with a uniqueness constraint, or a Redis SETNX) so the second request sees it's already claimed and waits for or returns the first request's eventual result instead of racing it.
Common mistake
Making the endpoint's business logic itself naturally idempotent (like a database update, which is; running it twice sets the same final value) is not the same thing as making the whole HTTP operation idempotent, non-idempotent operations like "charge $50" or "send one email" need this explicit key-based pattern since re-running them isn't naturally safe.
What the interviewer is checking
Whether you think about distributed systems in terms of failure modes (timeouts, retries, partial failures) rather than assuming the happy path, and whether you know a concrete, standard mechanism (idempotency keys) rather than a vague "we'd handle duplicates somehow."
Imagine mailing a check, not hearing back for weeks, and not knowing if it got lost or if it arrived and the reply is just slow. If you mail a second check "just in case," you risk paying twice if the first one actually arrived. An idempotency key is like writing the same reference number on both checks: the bank sees the second check has the same reference number as one it already cashed, so it simply ignores the duplicate instead of cashing it again.
That's exactly what happens when an app's network request times out. The app doesn't know if the payment went through, so it wants to safely retry. By sending the same unique "reference number" (the idempotency key) with the retry, the server can recognize it already handled this exact request and just resend the original result, instead of charging the customer a second time.
Interviewers often continue with:
- How long should an idempotency key be valid for?
- How would you handle a retry arriving while the original request is still processing?
- Is GET naturally idempotent, and why doesn't it need this pattern?
# Atomically claim the key before doing anything, so concurrent retries can't both slip through
def charge(idempotency_key, amount, customer_id):
existing = db.execute(
"INSERT INTO idempotency_keys (key, status) VALUES (%s, 'processing') "
"ON CONFLICT (key) DO NOTHING RETURNING key",
[idempotency_key],
)
if existing is None:
# Key already exists: another request owns it, return its stored result
return db.fetch_result(idempotency_key)
result = payment_gateway.charge(amount, customer_id)
db.execute(
"UPDATE idempotency_keys SET status='done', result=%s WHERE key=%s",
[result, idempotency_key],
)
return resultChoose your goal.
Pick the role you're interviewing for and go straight to questions written for it.
Find your track.
Pulled from real interview experience, organized by company.
ServiceNow
AI Engineer, Backend Developer, Cloud Engineer
20 questions
Mphasis
Data Engineer, Database Administrator, DevOps Engineer
11 questions
VMware
Cloud Engineer, Data Engineer, Database Administrator
10 questions
Microsoft
Backend Developer, Cloud Engineer, DevOps Engineer
8 questions
Deloitte
Backend Developer, Cloud Engineer, Data Engineer
7 questions
Honeywell
Backend Developer, Cloud Engineer, Database Administrator
7 questions
What actually moves the needle.
Preparation habits pulled from candidates who went through the process more than once.
Study the pattern, not the problem
Two Sum and Subarray Sum look different until you notice they're both solved with the same hash map trick. Learn the pattern once, recognize it everywhere.
Say your answer out loud
Silent practice hides the moments where your reasoning has a gap. Reading aloud finds them before the interview does.
Time-box every rep
Twenty-five minutes per question, no exceptions. Interviewers won't give you the extra ten either.
Revisit what you got wrong
A missed question you review twice sticks. One you skip past tends to show up again in a different interview.