1Context and scope
A payment must happen exactly once: a retried request must not charge twice, a saved charge must always produce its webhook, and a card network outage must not take checkout down. This design covers charges and status reads: a WAF and fraud scoring in front, a double-entry ledger, a card network with a second acquirer as fallback, and webhooks through a transactional outbox and idempotent delivery workers. It is based on Stripe’s public documentation on idempotent requests, Radar and webhooks.
2Goals and non-goals
Goals
- 1,500 requests a second: 70% charges, 30% status reads.
- Success at least 99%, p99 at most 2 s, zero duplicate side effects.
- Every charge produces exactly one webhook delivery, even when the network or a merchant endpoint fails.
Non-goals
- Card data storage and PCI scope.
- Subscriptions, invoices and payouts.
- The dashboard.
3Capacity estimate
| Quantity | Value | How |
|---|---|---|
| Charges | ≈ 1,050/s | 70% of 1,500 |
| Ledger writes | ≈ 1,050/s at 10 ms | 400 slots: about 11 busy |
| Card network | ≈ 1,050/s at 350 ms, 2% declines | 2,000 slots: about 370 busy; declines are not errors of yours |
| Webhooks | ≈ 1,050/s, 1,024 workers | each delivery waits on a merchant endpoint (150 ms, 1% errors) |
| Status reads | ≈ 450/s | through a 10-minute cache; misses read the ledger |
| Fraud false positives | 0.2% of charges | real customers declined by the filter |
The rest of the doc
The design · Key concepts · Alternatives considered · Failure modes and fixes · Try it in the lab · Check yourself · Further reading
Unlock the Stripe design doc
Every component and why it is there, the capacity numbers behind it, what breaks when you push it and how to fix it, and the same system open in the lab to break and fix yourself. Paid once, on your account.