High-Level Design Tutorial 0/42 lessons ~6 min read Lesson 40

    Online Payment System

    Design an online payment system like Stripe or PayPal — merchants accept payments, funds settle to bank accounts, with PCI compliance, idempotency, fraud detection, and ledger a…

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Design an online payment system like Stripe or PayPal — merchants accept payments, funds settle to bank accounts, with PCI compliance, idempotency, fraud detection, and ledger accuracy. Money paths demand strong consistency, audit trails, and regulatory reporting.

    HLD separates card data vault (PCI scope), ledger double-entry bookkeeping, and external processor integration. Never store raw PAN in application DB.

    Understanding the topic

    Key concepts

    • Payment intent: create → authorize → capture → settle → payout.
    • Idempotency-Key mandatory on all charge APIs.
    • Double-entry ledger: debit/credit accounts always balance.
    • Webhook from processor at-least-once — idempotent handler.
    • Fraud scoring async before capture; block high risk.
    • Reconciliation batch matches processor statement to internal ledger.
    text
    flowchart TB
    Client --> PG[Payment Gateway]
    PG --> Ledger
    PG --> Fraud
    PG --> Bank

    Internal architecture

    Architecture overview

    text
    flowchart TB
    Client --> PG[Payment Gateway]
    PG --> Ledger
    PG --> Fraud
    PG --> Bank

    Step-by-step explanation

    1. POST /v1/charges Idempotency-Key → Payment API → Fraud check → Processor token charge.
    2. Ledger service records immutable journal entries PostgreSQL.
    3. PCI: card tokenized via processor.js — vault stores token only.
    4. Webhook /webhooks/processor verifies HMAC signature, updates payment state.
    5. Settlement cron aggregates merchant balance → ACH payout file.
    6. Outbox publishes PaymentCaptured events to Kafka for email/receipt.

    Informative example

    Idempotent charge with ledger double-entry in one transaction:

    java
    @Service
    public class PaymentService {
    private final LedgerRepository ledger;
    private final ProcessorClient processor;
    private final IdempotencyStore idempotency;
    @Transactional
    public ChargeResult charge(ChargeRequest req, String idempotencyKey) {
    return idempotency.execute(idempotencyKey, () -> {
    FraudScore score = fraud.score(req);
    if (score.blocked()) throw new FraudBlockedException();
    ProcessorResult pr = processor.charge(req.token(), req.amount(), req.currency());
    ledger.post(JournalEntry.builder()
    .debit("cash:processor", req.amount())
    .credit("payable:merchant:" + req.merchantId(), req.amount())
    .reference(pr.transactionId())
    .build());
    return ChargeResult.from(pr);
    });
    }
    }

    Ledger append-only. Reconciliation job flags mismatch. PCI scope minimized — no PAN in logs.

    Real-world use

    Real-world use cases

    • E-commerce checkout Stripe integration.
    • Marketplace split payments driver/restaurant/platform.
    • Subscription billing recurring charges.
    • Cross-border FX conversion fintech.

    Best practices

    • Immutable ledger — corrections via reversing entries.
    • HMAC verify all webhooks.
    • Separate PCI network segment for tokenization.
    • Monitor authorization success rate and chargeback ratio.
    • Daily reconciliation automated with alert on discrepancy.
    • Audit log every state transition with actor and timestamp.

    Common mistakes

    • Store PAN or CVV — PCI scope explosion.
    • Mutable balance column without journal — audit impossible.
    • Webhook without idempotency — double credit merchant.
    • Capture before fraud check completes.
    • No reconciliation — silent money loss months later.

    Advanced interview questions

    Q1BeginnerWhy idempotency in payments?
    Retries and network duplicates must not double-charge customer or merchant.
    Q2BeginnerAuthorize vs capture?
    Authorize holds funds; capture settles charge — allows cancel before shipment.
    Q3IntermediateDouble-entry ledger purpose?
    Financial audit trail where debits equal credits; immutable history.
    Q4IntermediateHandle processor webhook duplicate?
    Store event ID unique; skip if already processed; return 200.
    Q5AdvancedDesign Stripe-like platform for marketplaces.
    Connected accounts, split ledger entries, idempotent API, vault tokenization, fraud ML, webhook HMAC, reconciliation SFTP, multi-currency, STR reporting, 99.99% SLO auth path.

    Summary

    Payment HLD prioritizes correctness, audit, and PCI minimization. Idempotency and ledger double-entry are non-negotiable. Tokenize cards — never store raw PAN. Webhooks processed idempotently with signature verification. Reconciliation catches processor drift. Notification system delivers receipts and alerts async.

    Ready to mark this lesson complete?Track your journey across the entire course.