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