Skip to main content

Design a Payment System

Design a payment processing system that handles credit card charges, refunds, and payouts.

Related Concepts: Idempotency, Double-Entry Bookkeeping, Saga Pattern, Event Sourcing, PCI Compliance, Retry with Backoff, Reconciliation, State Machines, Distributed Transactions

Step 1: Requirements and Scope​

Functional Requirements​

  • Process credit/debit card payments
  • Handle refunds (full and partial)
  • Support multiple payment methods (cards, bank transfers, digital wallets)
  • Payout to merchants
  • Transaction history and receipts
  • Handle disputes/chargebacks

Non-Functional Requirements​

RequirementTargetRationale
Availability99.99%Every failed charge = lost revenue
LatencyUnder 2 secondsUsers will not wait
DurabilityZero data lossMoney cannot disappear
ConsistencyStrongDouble charges are unacceptable
CompliancePCI-DSS Level 1Legal requirement for card data

Scale Estimation​

  • 10 million transactions per day
  • Average transaction: $50
  • Daily volume: $500 million
  • Peak: 3x average (Black Friday, holidays)

Step 2: High-Level Design​

Loading diagram...

Step 3: Core Design Decisions​

Decision 1: Idempotency​

Network failures, retries, and duplicate requests are common in payment systems.

Loading diagram...

Idempotency Key TTL: 24-48 hours (stored in DynamoDB with TTL attribute)

Decision 2: Payment State Machine​

Every payment follows a strict state machine:

Loading diagram...

Decision 3: Double-Entry Bookkeeping​

Every transaction creates balanced ledger entries. For a $100 payment:

  • Customer Card receives a $100 credit (representing money owed to us)
  • Merchant Balance receives a $97.10 debit (representing money we owe the merchant)
  • Platform Fee Revenue receives a $2.90 debit (representing our earned revenue)

The key principle: debits must equal credits for every transaction. In this example, total debits ($97.10 + $2.90 = $100) equal total credits ($100), ensuring the books balance to zero.

Decision 4: Handling External Payment Processors​

Communication with Visa/Mastercard can fail at any point:

Loading diagram...

Step 4: Refund Flow​

Refunds are separate transactions, not reversals:

Loading diagram...

Step 5: Database Schema​

The payments table (immutable after creation) stores:

  • id: UUID primary key
  • idempotency_key: Unique constraint ensuring no duplicate processing
  • merchant_id: Which merchant receives the funds
  • amount_cents: Payment amount in smallest currency unit (cents/pence)
  • currency: Three-letter currency code (USD, EUR, etc.)
  • status: Current payment state
  • payment_method: JSON containing card or bank details (tokenized)
  • created_at and updated_at: Timestamps
  • metadata: Additional JSON data from the merchant

The ledger_entries table (append-only, never update or delete) stores:

  • id: UUID primary key
  • payment_id: Links to the parent payment
  • account_id: Which account is affected
  • entry_type: Either DEBIT or CREDIT
  • amount_cents: Entry amount
  • currency: Currency code
  • created_at: When the entry was created

A balance check constraint (debits equal credits per payment) is enforced at the application level or via database triggers.

Step 6: Failure Handling​

Failure ScenarioDetectionRecovery
Network timeout to processorTimeout exceptionQuery status API, retry if safe
Database failure mid-transactionTransaction rollbackRetry from idempotency store
Service crash after chargeHealth checkReconciliation job matches with processor
Processor declines cardDecline responseReturn error to user, no retry
Duplicate requestIdempotency key matchReturn cached response

Reconciliation Process​

Loading diagram...

Step 7: Security and Compliance​

PCI-DSS Requirements​

RequirementImplementation
Never store CVVTokenize card data at edge
Encrypt card dataUse PCI-compliant vault (Stripe, Braintree)
Network segmentationCardholder data in isolated subnet
Access loggingAudit log every access to payment data
Regular auditsAnnual PCI assessment

Fraud Prevention​

Loading diagram...

Real-World Systems​

SystemNotable Design Choice
StripeIdempotency keys, complete API
PayPalTwo-sided marketplace, buyer protection
SquareHardware integration, POS systems
AdyenSingle platform for global payments

Summary​

DecisionRecommendationRationale
ConsistencyStrong (ACID transactions)Money cannot have eventual consistency
IdempotencyMandatory, 24h TTLNetwork retries are common
Ledger designAppend-only, double-entryAuditable, catches errors
Card storageTokenization via PCI vaultCompliance requirement
Failure handlingReconciliation + manual reviewSome failures need human judgment