System Design Problems
Design a Payment System
A payment system processes financial transactions between buyers, sellers, and payment networks. Systems like Stripe, PayPal, and Square handle billions of transactions with strict correctness, idempotency, and regulatory compliance.
- Financial Correctness β No lost or duplicate transactions; every penny accounted for
- Idempotency β Retried requests must not cause double-charges
- Compliance β PCI-DSS, SOX, and regional financial regulations
Payment systems are the most critical infrastructure in any business. A bug that loses money or double-charges customers can destroy a company. The design prioritizes correctness over performance.
Requirements
Functional Requirements
- Process credit/debit card payments
- Support refunds and chargebacks
- Merchant onboarding and KYC (Know Your Customer)
- Payment method management (saved cards)
- Transaction history and reporting
- Webhook notifications for payment events
- Multi-currency support
Non-Functional Requirements
- Correctness: Zero tolerance for financial errors
- Durability: Transaction logs must never be lost
- Idempotency: Retried requests must not cause duplicate charges
- Availability: 99.999% for payment processing
- Compliance: PCI-DSS Level 1, GDPR, SOX
Payment systems use double-entry bookkeeping: every transaction has a debit and a credit that must balance. This provides an auditable trail and mathematical verification of correctness.
Back-of-the-Envelope Estimation
Payment System Capacity
- 10M transactions/day Γ 1B/day
- QPS_write = 10M / 86400 β 116 TPS (transactions per second)
- Peak TPS (10x): ~1,160 TPS
- Transaction log: 10M Γ 1 KB Γ 365 days = 3.65 TB/year
- PCI-DSS requires 7 years retention: ~25 TB
API Design
POST /api/v1/payments
Request: {
"amount": 5000, // cents
"currency": "USD",
"source": "tok_visa_123",
"description": "Order #12345",
"idempotency_key": "order_12345_payment_1"
}
Response: {
"payment_id": "pay_abc123",
"status": "succeeded",
"amount": 5000,
"charge_id": "ch_xyz789"
}
POST /api/v1/refunds
Request: { "charge_id": "ch_xyz789", "amount": 2000 }
Response: { "refund_id": "ref_456", "status": "succeeded" }
GET /api/v1/payments/pay_abc123
Response: { "payment_id": "pay_abc123", "status": "succeeded", ... }
High-Level Architecture
Detailed Design
Idempotency
DfIdempotency
Idempotency ensures that processing the same request multiple times produces the same result as processing it once. For payments, this prevents double-charging when clients retry failed requests.
Idempotency Key Lookup
Here,
- =Client-provided idempotency key
- =Previously computed payment result
Idempotency keys must be stored with sufficient TTL (24+ hours). Without idempotency, a network timeout during payment processing could cause the client to retry, resulting in a double charge.
Double-Entry Ledger
Every payment creates two ledger entries that must balance:
Double-Entry Balance
Here,
- =Debit amounts (money leaving an account)
- =Credit amounts (money entering an account)
Double-Entry Example
Customer pays $100 to merchant:
Account Debit Credit
βββββββββββββββββββββββββββββββββββββ
Customer Wallet -$100
Merchant Wallet +$100
Processing Fee +$3
Platform Revenue +$97
βββββββββββββββββββββββββββββββββββββ
Total -$100 +$200 β Wait, that's wrong!
Corrected with offsetting entries:
Customer Wallet -$100
Merchant Wallet +$100
Each transaction has equal debits and credits.
Payment Processing Flow
Payment State Machine
DfPayment States
Payments transition through states: pending β authorized β captured β settled. Failed states: failed (declined) or refunded (after settlement).
Idempotency Design
Every payment request includes an idempotency key:
POST /api/v1/payments
Headers:
Idempotency-Key: order_12345_payment_1
Content-Type: application/json
The server checks Redis for the idempotency key:
- Key exists β return cached response (no reprocessing)
- Key doesn't exist β process payment, store result with 24h TTL
The idempotency key should be deterministic: for example, {order_id}_{payment_attempt}. This ensures retries use the same key while new payments use different keys.
Fraud Detection
Integrate fraud detection in the payment flow:
Fraud Score
Here,
- =Transaction frequency in short time window
- =Geographic risk score
- =Transaction amount relative to user average
- =User's historical fraud rate
Fraud detection must complete within 100ms (payment latency budget). Use pre-computed features and in-memory ML models for real-time scoring.
Practice Exercises
-
Design: How would you implement a payment refund that partially refunds a multi-item order? Design the ledger entries for a partial refund.
-
Reliability: If the payment network (Visa) is temporarily unavailable, design a retry strategy that doesn't double-charge the customer.
-
Compliance: What data must be encrypted at rest and in transit for PCI-DSS compliance? Design the encryption strategy for card data.
-
Scale: If the system processes 10,000 TPS, estimate the Redis cluster size for idempotency checks and the PostgreSQL cluster size for ledger storage.
Key Takeaways:
- Idempotency keys prevent double-charging on retries; store with 24h+ TTL
- Double-entry bookkeeping provides mathematical verification of financial correctness
- Payment lifecycle: created β authorized β captured β settled β (refunded)
- Fraud detection must complete within the payment latency budget (100ms)
- Append-only transaction logs provide audit trails for regulatory compliance
What to Learn Next
-> Design Ticket Booking Inventory management and reservation patterns.
-> Databases ACID transactions and ledger storage patterns.
-> Message Queues Async payment processing and webhook delivery.
-> Security Patterns Encryption, authentication, and PCI-DSS compliance.
-> Design Email System Sending payment receipts and transactional emails.
-> Distributed Consensus Ensuring consistent ledger state across replicas.