Design a Distributed Payment Gateway & Immutable Double-Entry Ledger (Stripe / Adyen)
Architect a mission-critical payment processing platform featuring idempotent charge capture, distributed Saga transactions, immutable double-entry ledger bookkeeping, and PCI-DSS tokenization vaults.
Functional Requirements
- •Process credit card charges, ACH transfers, and refunds with zero double billing
- •Enforce immutable double-entry ledger where sum(debits) === sum(credits) at all times
- •Send real-time webhook event notifications with guaranteed at-least-once delivery
Non-Functional Requirements
- •Strict ACID transaction consistency across financial accounts
- •PCI-DSS Level 1 compliance (Zero raw card numbers stored in application databases)
- •99.999% availability with zero silent transaction drops
Capacity & Scale Estimation
Core Architectural Components
1Card Tokenization Vault (Isolated HSM)
Hardware Security Module (HSM) encrypting PANs with AES-256-GCM, returning non-sensitive surrogate tokens to the core app.
2Idempotency Layer (Redis Cluster)
Stores `Idempotency-Key` hash with lock state; duplicate client requests within 24h return cached responses immediately.
3Payment Orchestrator & Saga State Machine
Coordinates multi-step checkout workflow (Authorize -> Tokenize -> Acquire -> Settle -> Notify) with compensating transactions.
4Immutable Double-Entry Ledger (PostgreSQL / CockroachDB)
Append-only relational ledger enforcing zero row updates; every monetary transfer creates equal debits and credits.
5Webhook Retry Dispatcher (Kafka + Dead Letter Queue)
Dispatches HTTPS webhooks to merchant endpoints with exponential backoff retries over 72 hours.
Architectural FAQs & Interview Deep Dives
How do Idempotency Keys prevent duplicate charges when network timeouts occur?
When a client sends `Idempotency-Key: abc-123`, the gateway attempts an atomic `SET NX` in Redis. If the key exists, it returns the in-progress state or cached result, preventing duplicate credit card authorizations.
What is the Double-Entry Bookkeeping rule in financial software architecture?
Every transaction must contain at least two entries: one account is debited and another is credited by the exact same amount (`sum(debits) - sum(credits) === 0`). Rows are append-only and never updated or deleted.
How does the Saga pattern manage distributed transaction failures in microservices?
Instead of slow 2-Phase Commits that lock databases across networks, a Saga executes local ACID transactions sequentially. If a step fails (e.g. Card Expired), compensating transactions execute in reverse order (e.g. Release Reserved Inventory).
What is PCI-DSS Tokenization and why is it mandatory?
Payment Card Industry Data Security Standard forbids storing Primary Account Numbers (PANs) in regular databases. Tokenization swaps the PAN for a random surrogate token, isolating cardholder data into a certified vault.
How do you handle merchant webhooks that fail to respond?
Webhook payloads are queued in Kafka. If a merchant server returns 500 or times out, the message enters exponential retry queues (1m, 5m, 15m, 1h, 6h, 24h) before moving to a Dead Letter Queue (DLQ).
How are currency exchange rates rounded to prevent micro-penny rounding errors?
Financial systems never use floating-point types (`float` / `double`). They store monetary amounts in integer minor currency units (cents / satoshis) or use arbitrary-precision decimal types (e.g. `BigDecimal`).