# System Design Interview: Designing a Payment System "Design a payment system like Stripe checkout" is less about scale and more about correctness: money must never be charged twice or lost. ## Requirements - A customer pays for an order with a card; the merchant sees a final status (succeeded, failed). - Exactly-once charging from the user's point of view, even with retries and timeouts. - An auditable record of every money movement. - Scale is modest (a few thousand payments per second at peak), so correctness dominates. ## Core components 1. **Payment service**: accepts a payment request, stores a `payment` row in `PENDING`, and calls the payment service provider (PSP). 2. **PSP adapter**: talks to the card processor; never stores raw card numbers (the PSP's hosted form tokenizes them, which keeps you out of most PCI scope). 3. **Ledger**: an append-only, double-entry table. Each payment writes balanced debit and credit entries, so the books always sum to zero. 4. **Wallet / balance service**: merchant balances derived from the ledger. 5. **Reconciliation job**: compares the PSP's daily settlement file against your ledger and flags mismatches. ## Idempotency is the key idea The client sends an **idempotency key** (for example the order ID) with every request. The payment service stores it with a unique constraint: - First request: insert the key, process the payment, store the result. - Retry with the same key: return the stored result instead of charging again. Pass the same key through to the PSP so its side is idempotent too. ## Handling timeouts If the PSP call times out you don't know whether the charge happened. Don't retry blindly: - Keep the payment in `PENDING`. - Query the PSP for the status, or wait for its webhook. - Only mark `FAILED` when the PSP confirms it. ## Consistency between services Writing the payment row and publishing an event to other services should use the **outbox pattern**: write the event into an outbox table in the same database transaction, then a relay publishes it. This avoids "charged but order never updated". ## Follow-ups interviewers like - **Refunds**: a new ledger entry that reverses the original, never an edit. - **Currency**: store amounts as integer minor units (cents) plus a currency code, never floats. - **Fraud checks**: a risk service before authorization, with rules plus a score. --- *Disclosure: I'm part of the team at [Linkjob AI](https://www.linkjob.ai/), an AI interview assistant.*