Skip to main content
HS
HiSETSuccess
LeetCode Prep

System Design

Comprehensive interview guide: scalability, databases, distributed systems, cloud architecture, and full case-study walkthroughs — plus adaptive quizzes.

Case study

Design a Payment Processing System

Process card and wallet payments with exactly-once semantics, audit trails, and PCI-compliant isolation.

transactionsidempotencyledger

Requirements

  • Functional: charge, refund, partial refund; support cards and wallet balance
  • Idempotent payment API; webhook callbacks to merchants
  • Strong consistency for money movement; full audit ledger
  • Non-functional: p99 authorization < 500ms; 99.99% correctness (no lost/duplicate funds)
  • Scale: 50M users; 100M transactions/month; avg $25

PCI scope

Never store raw PAN/CVV in application DB. Tokenize via Stripe/Adyen vault; our system handles tokens only.

Back-of-envelope Estimation

MetricCalculationResult
Transactions/month100MGiven
TPS avg100M / (30 × 86,400)~40/sec
TPS peak (Black Friday)50× avg~2K/sec
Ledger rows/month100M × 2 entries (debit/credit)200M rows/mo
Storage/year (ledger)200M × 12 × 300 B~720 GB

API Design

EndpointDescription
POST /v1/payments{ amount, currency, paymentMethodToken, idempotencyKey } → paymentId
GET /v1/payments/{id}Status: pending | authorized | captured | failed | refunded
POST /v1/payments/{id}/refund{ amount?, idempotencyKey }
POST /v1/webhooks/stripeInternal: PSP callback handler

Data Model

EntityFields
paymentspayment_id, merchant_id, amount, currency, status, idempotency_key, psp_ref
ledger_entriesentry_id, account_id, payment_id, debit, credit, ts — append-only
accountsaccount_id, type (user|merchant|platform), balance — derived from ledger
idempotency_storekey, request_hash, response, expires_at — 24h TTL

High-level Design

Payment flow
Merchant ──► Payment API ──► Idempotency check
                              │
                    Payment Orchestrator (saga state machine)
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
         Ledger Service   PSP (Stripe)   Notification
         (double-entry)   authorize/capture   webhooks

Deep Dive: Idempotency & Saga

  1. Check idempotency_key in store; return cached response if duplicate
  2. Create payment row status=pending; write ledger hold entry
  3. Call PSP authorize; on success status=authorized
  4. Capture (sync or async); ledger debit user credit merchant
  5. On failure: compensating ledger entry releases hold

Deep Dive: Double-entry Ledger

Every payment creates balanced entries: debit customer account, credit merchant escrow. Platform fees as separate line. Ledger is append-only; balances computed or materialized via nightly reconciliation. Discrepancy alert triggers finance freeze.

Exactly-once

At-least-once PSP webhooks + idempotent handler keyed by psp_event_id. Never mutate ledger rows — only append corrections.

Failure Modes & Monitoring

SLOTarget
Authorization p99< 500ms
Ledger balance accuracy100% reconciled daily
Duplicate charge rate0
  • Alert: PSP timeout spike, saga stuck in pending > 5 min, reconciliation mismatch
  • Immutable audit log retained 7 years for compliance