How do you make a payment system reliable against retries?
993 views
64 of 106
1
The problem
Question presented to candidate:
"Your checkout calls a payment service, which calls a card processor such as Stripe or Adyen. Requests time out, clients retry, workers crash halfway. How do you guarantee a customer is charged exactly once, and that your records always match what the processor actually did?"
What a strong answer should cover:
Why retries are unavoidable: a timeout means the outcome is unknown, at every hop (client to service, service to processor)
End-to-end idempotency: a client key on your API, stored under a unique constraint, and a key passed downstream to the processor (derived from your payment ID) so the processor deduplicates too
A durable payment state machine (for example CREATED -> PENDING_PSP -> SUCCEEDED / FAILED / UNKNOWN) written before the external call, so a crash leaves a row that a recovery worker can finish with the same key
A double-entry ledger and daily reconciliation against processor reports to catch anything the online path missed
Retry policy: only retry what is safe, exponential backoff with jitter, retry at one layer, and dedup webhooks by event ID
Numbers: a worked estimate of request rate and storage for the key table and ledger
Clarifying questions expected:
Is this card-on-file charging, a wallet, or payouts? Do we hold funds or only forward to a processor?
Which processor, and does it support idempotency keys and a "look up by key or reference" call?
What is the scale and what is the acceptable time for a payment to sit in an unknown state?
Code / implementation expected: Optional โ a sketch of the key check, the state machine and the recovery job is strong; the example simulates timeouts and crashes and counts real charges.
payments
idempotency
2
Try it yourself
Sketch your approach before you read the solution. That is what the interview tests.
Stuck? Get a hint.
A short nudge toward the approach. It will not give the answer away.
3
Solution
Target Audience: Engineers who know what an API and a database transaction are, and want to design the money path so that retries and crashes can never double-charge a customer.
Difficulty: Hard
Verified with: Node 22.22 and Python 3.12 (both print identical output). Stripe idempotency behaviour is cited from the Stripe API reference ("Idempotent requests"). Capacity numbers are worked arithmetic from stated assumptions, recomputed in Python.
How to read this doc: Every idea is explained in plain language first, then tagged with ๐ Interview term: so you also learn the words an interviewer expects. The basics of idempotency are covered in What is idempotency and why does it matter?; this page applies them to the money path, where one mistake is a double charge. The full payment product (wallets, payout
The solution is hidden so you can try first
19 min read ยท 16 sections
4
Read the code
Payment retries: double charges without keys, end-to-end keys through the PSP, crash recovery, reconciliation and jittered backoff