01

Requirements & scope

Problem Statement & Requirements

Design a payment processing platform that handles the full lifecycle of financial transactions — accepting payments from customers, routing to card networks, managing settlements, handling refunds, and preventing fraud — similar to Stripe, Square, Adyen, or PayPal.

Functional Requirements

  • Charge a payment method — credit/debit cards, bank transfers (ACH), digital wallets (Apple Pay, Google Pay)
  • Payment intents — two-phase: authorize (hold funds) → capture (collect funds), or single-phase direct charge
  • Refunds — full or partial refund of a completed payment
  • Payment methods — store, retrieve, and delete customer payment methods (tokenized)
  • Idempotency — every API call accepts an idempotency key; retries are safe and produce identical results
  • Webhooks — notify merchants of async events (payment succeeded, refund completed, dispute opened)
  • Multi-currency — accept payments in 135+ currencies; settle in merchant's preferred currency
  • Subscriptions / Recurring billing — charge customers on a schedule (monthly, annual)
  • Dispute / Chargeback handling — manage the lifecycle of customer-initiated disputes
  • Payout / Settlement — aggregate funds and transfer to merchant bank accounts on a schedule
  • Ledger — double-entry bookkeeping for every money movement; audit trail

Non-Functional Requirements

  • Correctness above all — money must never be created, lost, or double-counted
  • Exactly-once processing — no duplicate charges, no lost refunds
  • High availability — 99.999% for payment acceptance (< 5 min downtime/year)
  • Low latency — payment authorization in < 2 seconds end-to-end
  • PCI DSS compliance — Level 1; card data encrypted at rest and in transit; tokenization
  • Strong consistency — payment state transitions must be ACID
  • Auditability — every state change logged immutably for regulatory compliance
  • Scalability — handle Black Friday traffic (10x normal peak)

Out of Scope

  • Detailed card network protocol internals (ISO 8583 message format)
  • KYC/AML onboarding flow for merchants
  • Tax calculation engine
  • Full invoicing system
02

Scale estimations

Scale Estimations

Traffic

MetricValue
Payments processed / day50M
Payments / second (avg)~580 TPS
Payments / second (peak — Black Friday)~6,000 TPS
Refunds / day2.5M (5% refund rate)
Webhook deliveries / day200M (avg 4 events per payment lifecycle)
API calls / second (all endpoints)~10K RPS
Active merchants5M
Stored payment methods (tokens)2B

Storage

MetricValue
Payment record size~2 KB (metadata, status, amounts, timestamps)
Payments per year50M × 365 = ~18.25B
Payment storage (1 year)18.25B × 2 KB = ~36.5 TB
Ledger entries (2 per payment + refunds + fees)~50B/year
Ledger storage (1 year)50B × 500 bytes = ~25 TB
Event log (webhooks, audits)~20 TB/year
Total storage (1 year)~80 TB
Retention7+ years (regulatory)

Bandwidth

MetricValue
API ingress10K RPS × 2 KB = ~20 MB/s
Webhook egress200M/day × 1 KB = ~2.3 MB/s avg, 50 MB/s peak
Card network traffic~580 TPS × 1 KB = ~0.6 MB/s

Hardware Estimate

ComponentSpec
API servers20-50 (stateless, auto-scaling)
Payment processing workers30-100 (orchestrate payment flow)
Database (primary)10-20 shards (PostgreSQL, SSD-backed)
Ledger database5-10 dedicated nodes (append-only, SSD)
Card network gateway10-20 (connection pooling to Visa/MC)
Webhook delivery fleet20-50 (async, retry-capable)
Redis (idempotency + rate limiting)3-6 nodes
03

Layered architecture

Phase 1 of 4 · Client & edge

Start with the entry points

First, define who uses the system and where requests enter. This is the boundary of the design, not yet a complete request path.

Merchant
Use an idempotency key for each logical payment, including retries after network timeouts.
API gateway
Authenticate the merchant and bind an idempotency key to a request fingerprint.
Architecture after phase 1. Includes Merchant, API gateway. Merchant connects to API gateway.
Phase 1 — Start with Merchant, API gateway.SVGSVGEditable diagramEditable diagram

This first layer defines the system boundary. The next chapters add application logic and data dependencies. After examining the request paths and tradeoffs, we will add operational safeguards and bring the complete architecture together.

04

API & contracts

Phase 2 of 4 · Application & compute

Add the application logic

Keep the entry points and add the services that do the work. Give each service a clear responsibility before defining its contracts. Storage and background dependencies come next.

Orchestrator
Track explicit payment states and resolve ambiguous provider outcomes before retrying a charge.
Risk + token vault
Use a token boundary for payment details and evaluate risk before authorization.
Architecture after phase 2. Includes Merchant, API gateway, Orchestrator, Risk + token vault. Merchant connects to API gateway. API gateway connects to Orchestrator. Orchestrator connects to Risk + token vault.
Phase 2 — Added Orchestrator, Risk + token vault. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

API Design

Create Payment Intent (Authorize)

EXAMPLE
POST /v1/payment_intents
Idempotency-Key: pi_req_abc123
Authorization: Bearer sk_live_...

Request:
{
  "amount": 2999,                        // cents (avoid floating point!)
  "currency": "usd",
  "payment_method": "pm_card_visa_4242",
  "capture_method": "manual",            // "automatic" for single-phase
  "description": "Order #1234",
  "metadata": {"order_id": "ord-1234"},
  "customer": "cus_abc123",
  "receipt_email": "alice@example.com"
}

Response (200 OK):
{
  "id": "pi_3MtwBwLkdIwHu7ix",
  "object": "payment_intent",
  "amount": 2999,
  "currency": "usd",
  "status": "requires_confirmation",
  "payment_method": "pm_card_visa_4242",
  "client_secret": "pi_3MtwBw_secret_YkS2...", // for frontend confirmation
  "created": 1712150400
}

Confirm Payment (Execute Authorization)

EXAMPLE
POST /v1/payment_intents/{id}/confirm
Idempotency-Key: pi_confirm_abc123

Response (200 OK):
{
  "id": "pi_3MtwBwLkdIwHu7ix",
  "status": "requires_capture",     // if manual capture
  // OR
  "status": "succeeded",            // if automatic capture
  "charges": {
    "data": [{
      "id": "ch_abc123",
      "amount": 2999,
      "currency": "usd",
      "status": "succeeded",
      "authorization_code": "A12345",
      "network_transaction_id": "NT98765",
      "risk_score": 12,
      "outcome": {
        "network_status": "approved_by_network",
        "risk_level": "normal"
      }
    }]
  }
}

Capture Payment

EXAMPLE
POST /v1/payment_intents/{id}/capture
Idempotency-Key: pi_capture_abc123

Request:
{
  "amount_to_capture": 2999           // can be less than authorized (partial capture)
}

Response (200 OK):
{
  "id": "pi_3MtwBwLkdIwHu7ix",
  "status": "succeeded",
  "amount_captured": 2999
}

Create Refund

EXAMPLE
POST /v1/refunds
Idempotency-Key: ref_req_xyz789

Request:
{
  "payment_intent": "pi_3MtwBwLkdIwHu7ix",
  "amount": 1500,                     // partial refund (in cents)
  "reason": "customer_request"        // customer_request | duplicate | fraudulent
}

Response (200 OK):
{
  "id": "re_abc123",
  "amount": 1500,
  "currency": "usd",
  "status": "pending",               // pending → succeeded (async from network)
  "payment_intent": "pi_3MtwBwLkdIwHu7ix"
}

Webhook Event

EXAMPLE
POST https://merchant.example.com/webhooks/stripe
Stripe-Signature: t=1712150400,v1=sha256_hmac_signature

{
  "id": "evt_abc123",
  "type": "payment_intent.succeeded",
  "data": {
    "object": {
      "id": "pi_3MtwBwLkdIwHu7ix",
      "amount": 2999,
      "status": "succeeded"
    }
  },
  "created": 1712150400
}

Merchant must respond 2xx within 10 seconds.
No 2xx → retry with exponential backoff (up to 3 days, ~20 attempts).
05

Data model

Phase 3 of 4 · Data & async work

Connect data and background work

The services now need their dependencies: durable state, fast lookups, or work that continues outside a request. Separate these responsibilities rather than treating every component as a database.

Ledger
Record financial movements as balanced entries with an auditable transaction history.
Payment adapters
Isolate provider protocols and normalize outcomes without assuming every provider behaves identically.
Payment networks
Treat timeouts as unknown outcomes; reconcile against external provider records.
Architecture after phase 3. Includes Merchant, API gateway, Orchestrator, Risk + token vault, Ledger, Payment adapters, Payment networks. Merchant connects to API gateway. API gateway connects to Orchestrator. Orchestrator connects to Risk + token vault. Orchestrator connects to Ledger. Orchestrator connects to Payment adapters. Payment adapters connects to Payment networks.
Phase 3 — Added Ledger, Payment adapters, Payment networks. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

Data Model

Payment Intent

Payment Intent
Payment IntentSVGSVGEditable diagramEditable diagram

Ledger Entry (Double-Entry Bookkeeping)

Ledger Entry (Double-Entry Bookkeeping)
Ledger Entry (Double-Entry Bookkeeping)SVGSVGEditable diagramEditable diagram

Payment State Machine

Payment State Machine
Payment State MachineSVGSVGEditable diagramEditable diagram
06

Core design decisions

Core Design Decisions

Decision 1: How to Guarantee Exactly-Once Payment Processing

This is the single most important design problem. Charging a customer twice is catastrophic.

Decision 1: How to Guarantee Exactly-Once Payment Processing
Decision 1: How to Guarantee Exactly-Once Payment ProcessingSVGSVGEditable diagramEditable diagram
Solution: Multi-Layer Idempotency
Solution: Multi-Layer Idempotency
Solution: Multi-Layer IdempotencySVGSVGEditable diagramEditable diagram

Decision 2: The Double-Entry Ledger

Decision 2: The Double-Entry Ledger
Decision 2: The Double-Entry LedgerSVGSVGEditable diagramEditable diagram

Decision 3: Smart Routing to Maximize Authorization Rate

Decision 3: Smart Routing to Maximize Authorization Rate
Decision 3: Smart Routing to Maximize Authorization RateSVGSVGEditable diagramEditable diagram
07

Request flows

Detailed Flow Diagrams

Payment Authorization Flow

Payment Authorization Flow
Payment Authorization FlowWide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram

Refund Flow

Refund Flow
Refund FlowWide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram

Settlement / Payout Flow

Settlement / Payout Flow
Settlement / Payout FlowSVGSVGEditable diagramEditable diagram
08

Performance & caching

Payment status is correctness-sensitive, so caching cannot replace the authoritative operation record. Cache stable configuration and provider routing data instead. Move receipts and nonessential analytics off the charge path, while keeping durable recording and idempotency checks within the acceptance boundary.

09

Advanced design

Tokenization & PCI Compliance

Tokenization & PCI Compliance
Tokenization & PCI ComplianceSVGSVGEditable diagramEditable diagram

Fraud Detection Engine

Fraud Detection Engine
Fraud Detection EngineSVGSVGEditable diagramEditable diagram

Subscription / Recurring Billing

Subscription / Recurring Billing
Subscription / Recurring BillingSVGSVGEditable diagramEditable diagram
10

Edge cases

Handling Edge Cases

Partial Capture / Over-Capture

EXAMPLE
Authorized: $100.00

Case 1: Partial capture (customer removed items from cart)
  → Capture $75.00. Remaining $25.00 auth released to cardholder.
  → Ledger: DEBIT network $75, CREDIT merchant $72.82, CREDIT fees $2.18

Case 2: Multi-capture (ship items separately)
  → Capture $40.00 (shipment 1)
  → Capture $35.00 (shipment 2)
  → Total captured: $75.00. Remaining $25.00 released.
  → Each capture is a separate ledger transaction.

Authorization Expiry

EXAMPLE
Problem: Merchant authorizes $100 but never captures

  Card network rules:
    Visa: auth expires in 7 days
    Mastercard: auth expires in 7-30 days (varies)
    If not captured → funds released to cardholder automatically

  Our handling:
    Background job scans for old uncaptured auths
    After 6 days: send webhook warning merchant
    After 7 days: mark as expired, release ledger hold
    Merchant can re-authorize if needed

Network Timeout (Ambiguous Response)

EXAMPLE
Problem: We send auth request to Visa → timeout after 30s
         Did Visa approve it? Decline it? Never receive it?

  This is the HARDEST edge case in payments.

  Solution: Status Inquiry + Reconciliation

  1. Immediately: mark payment as "processing" (not succeeded/failed)
  2. After 30s: send "status inquiry" to Visa
     → "I sent request REQ-123, what happened?"
     → Visa responds: approved / declined / not found
  3. If "not found": safe to retry with new request ID
  4. If approved/declined: update our state accordingly
  5. If status inquiry also times out:
     → Mark as "requires_manual_review"
     → Nightly reconciliation batch compares our records
       with network settlement files
     → Catches ALL discrepancies within 24 hours

Double-Charge Prevention on Retry

EXAMPLE
Scenario:
  1. Merchant calls POST /confirm (Idempotency-Key: IK-123)
  2. We auth with Visa → approved → our server crashes BEFORE responding
  3. Merchant times out → retries with same IK-123
  4. We see IK-123 exists with status="processing" (not completed)

  Handling:
  → Check: is there a network_txn_id for this payment?
  → Yes: we already sent to Visa and it was approved
  → Return the original approval result (don't send to Visa again)
  → Update idempotency cache with final result

  If network_txn_id is NULL:
  → We crashed before sending to Visa
  → Safe to send authorization now (first attempt from network's POV)

Dispute / Chargeback Handling

EXAMPLE
Customer calls bank: "I didn't make this purchase!"

Timeline:
  Day 0:   Issuer initiates dispute, debits merchant's account
  Day 1:   We receive dispute notification from network
           → Webhook: "charge.dispute.created"
           → Ledger: DEBIT merchant, CREDIT dispute_reserve
  Day 1-21: Merchant submits evidence (receipt, tracking, logs)
           → We forward evidence to network (representment)
  Day 30-75: Issuer reviews evidence
           → Won: funds returned to merchant (CREDIT merchant)
           → Lost: funds stay with customer (dispute_reserve cleared)
           → Webhook: "charge.dispute.closed" with outcome

  Financial impact tracking:
  dispute_rate = disputes / total_charges (by merchant)
  If > 1%: warn merchant (Visa/MC programs penalize high dispute rates)
  If > 2%: risk of losing processing privileges entirely
11

Tradeoffs

Tradeoffs & Design Decisions Summary

DecisionOption AOption BChosenWhy
IdempotencyDB-based (check before every write)Redis SETNX + DBRedis + DBRedis for fast dedup (< 1ms); DB as durable backup
LedgerSingle-entry (simple balance tracking)Double-entry bookkeepingDouble-entryProvable correctness; audit trail; catches bugs via balance invariant
Money representationFloat/decimalInteger cents (BIGINT)Integer centsFloats have rounding errors; $29.99 = 2999 cents; zero ambiguity
Card storageEncrypt in main DBIsolated Token Vault + HSMToken VaultMinimizes PCI scope from 100+ servers to < 5; massive compliance savings
Network routingSingle acquirerSmart routing with fallbackSmart routing2-5% auth rate improvement = millions in recovered revenue
State transitionsEventual consistencyACID transactionsACIDMoney requires absolute correctness; payment + ledger + event = atomic
Webhook deliverySynchronous (block on merchant)Async with retry queueAsync + retryMerchant downtime shouldn't block our pipeline; retry up to 3 days
SettlementReal-time (per-transaction)Daily batchDaily batchReduces ACH costs; provides fraud review window; industry standard
Fraud scoringRules-onlyML model + rulesML + rulesML catches patterns rules can't; rules handle explicit policies
ConsistencyOptimistic (retry on conflict)Pessimistic (lock on payment)PessimisticPayment state transitions must be serialized; no lost updates
12

Reliability & fault tolerance

Phase 4 of 4 · Operations & resilience

Add operational safeguards

With the request paths and tradeoffs established, add the controls that help detect trouble and keep the system operating. The final diagram retains every layer introduced so far.

Reconciliation
Compare internal records with provider settlement data and deliver signed webhooks with retry.
Architecture after phase 4. Includes Merchant, API gateway, Orchestrator, Risk + token vault, Ledger, Payment adapters, Payment networks, Reconciliation. Merchant connects to API gateway. API gateway connects to Orchestrator. Orchestrator connects to Risk + token vault. Orchestrator connects to Ledger. Orchestrator connects to Payment adapters. Payment adapters connects to Payment networks. Ledger connects to Reconciliation. Payment networks connects to Reconciliation.
Phase 4 — Added Reconciliation. Earlier layers remain in place.SVGSVGEditable diagramEditable diagram

Reliability & Fault Tolerance

Single Points of Failure & Mitigations

Single Points of Failure & Mitigations
Single Points of Failure & MitigationsSVGSVGEditable diagramEditable diagram

Disaster Recovery

Disaster Recovery
Disaster RecoverySVGSVGEditable diagramEditable diagram

Reconciliation — The Ultimate Safety Net

Reconciliation — The Ultimate Safety Net
Reconciliation — The Ultimate Safety NetSVGSVGEditable diagramEditable diagram
13

Production architecture

High-Level Architecture

High-Level Architecture
High-Level ArchitectureSVGSVGEditable diagramEditable diagram

Component Breakdown

Component Breakdown
Component BreakdownSVGSVGEditable diagramEditable diagram

Full System Architecture (Production-Grade)

Full System Architecture (Production-Grade)
Full System Architecture (Production-Grade)Wide diagram — scroll horizontally.SVGSVGEditable diagramEditable diagram
14

Further exploration

A provider reports success through a webhook before the original API request returns. Trace how both paths converge on the same payment record. Then deliver that webhook again and out of order with a later status update. The state machine should reject regressions rather than trusting arrival order.

15

Interview playbook

Interview Tips

  1. Lead with correctness, not performance — "The #1 requirement is money never gets lost or double-counted." Explain idempotency keys, ACID transactions, double-entry ledger. Performance is secondary to correctness for payments.

  2. Draw the payment lifecycle state machine — requires_payment_method → requires_confirmation → requires_capture → succeeded → refunded. Show you understand the two-phase (auth + capture) model and why it exists (hotel holds, preorders).

  3. Explain idempotency concretely — Walk through the retry scenario: merchant sends charge, times out, retries with same key. Show how SETNX in Redis prevents duplicate processing, and how stored results return the original response.

  4. Double-entry ledger is the showstopper answer — Most candidates say "store balances in a column." Explain: every money movement creates debit + credit entries; sum must always be zero; corrections are reversing entries, never updates. This invariant catches bugs, fraud, and data corruption.

  5. Use integers for money, never floats — $29.99 = 2999 cents as BIGINT. Floating point: 0.1 + 0.2 = 0.30000000000000004. In payments, one cent off in a billion transactions = audit nightmare.

  6. Tokenization minimizes PCI scope — Card numbers never touch your main infrastructure. Token Vault (< 5 servers in PCI scope) vs entire platform (100+ servers). Dramatically reduces audit cost and security risk.

  7. Network timeout is the hardest edge case — Don't handwave "just retry." Explain: timeout is ambiguous (approved? declined? lost?). Solution: status inquiry to network + nightly reconciliation as safety net.

  8. Smart routing improves auth rates — Not all acquirers are equal. Routing based on BIN, country, card type, historical performance can lift auth rates 2-5%. At scale, this is millions in recovered revenue.

  9. Reconciliation is the last line of defense — Three-way nightly comparison: our records vs network settlement files vs ledger balances. Any mismatch = alert. This catches everything that all other safeguards missed.

  10. End with fraud and disputes — Mention ML scoring (< 10ms real-time), 3DS challenges for medium-risk, and the dispute lifecycle. Show you understand the business impact: > 1% dispute rate = card network penalties.