🎯 How Stripe Handles Payment Consistency
1️⃣ Core Framework
When discussing Stripe-style Payment Consistency, I frame it as:
- Idempotency
- Durable payment state machine
- Ledger correctness
- External processor uncertainty
- Retry and timeout safety
- Webhooks and async events
- Reconciliation
- Trade-offs: correctness vs latency vs external dependency
2️⃣ The Core Problem
Payment systems cannot rely on perfect networks.
The same request may be retried, external processors may timeout, and webhooks may arrive late or multiple times.
Dangerous Scenario
Client creates charge
↓
Payment succeeds internally
↓
Network timeout before response
↓
Client retries
↓
Duplicate charge risk
👉 Interview Memorization
Payment consistency is hard because retries, timeouts, external processors, and asynchronous events can make it unclear whether money moved.
3️⃣ High-level Architecture
Stripe-like Payment Path
Client
↓
Payment API
↓
Idempotency Layer
↓
Payment State Machine
↓
Ledger
↓
Processor / Bank Network
↓
Webhook / Reconciliation
Key Services
- Payment API
- Idempotency store
- Payment intent / charge service
- Ledger service
- Risk service
- Processor integration
- Webhook processor
- Reconciliation jobs
- Audit log
👉 Interview Memorization
A Stripe-like system protects payment consistency with idempotency at the API layer, durable state transitions in the payment layer, ledger correctness underneath, and reconciliation against external processors.
4️⃣ Idempotency Keys
Idempotency prevents duplicate business execution.
Flow
POST /payments
Idempotency-Key: abc123
↓
First request executes
↓
Result stored under abc123
↓
Retry with abc123 returns same result
What Gets Stored
- Idempotency key
- Request fingerprint
- Response status
- Response body
- Payment ID
- Expiration time
👉 Interview Memorization
Idempotency keys make client retries safe by ensuring the same logical payment request executes at most once.
5️⃣ Request Fingerprinting
The same idempotency key should not be reused for a different request.
Example
Key: abc123
Amount: $100
Retry:
Key: abc123
Amount: $200
This should be rejected because the request changed.
Why
Without request fingerprinting, a client bug could accidentally reuse a key for a different payment.
👉 Interview Memorization
Idempotency should compare request fingerprints so the same key cannot silently represent two different payment operations.
6️⃣ Durable Payment State Machine
Payment operations should move through explicit durable states.
Example State Machine
CREATED
↓
REQUIRES_PAYMENT_METHOD
↓
AUTHORIZED
↓
CAPTURED
↓
SETTLED
Failure States
FAILED
CANCELED
REFUNDED
DISPUTED
REVERSED
👉 Interview Memorization
A durable payment state machine makes money movement explicit, auditable, and protected from invalid transitions.
7️⃣ State Transition Rules
Not every transition is legal.
Valid
AUTHORIZED → CAPTURED
CAPTURED → REFUNDED
Invalid
FAILED → CAPTURED
REFUNDED → AUTHORIZED
Why This Matters
State transition rules prevent accidental money movement from retry bugs, duplicated events, or out-of-order callbacks.
👉 Interview Memorization
Payment consistency depends on strict state transition rules so duplicate or out-of-order events cannot move money into impossible states.
8️⃣ Ledger Correctness
The ledger is the source of truth for financial accounting.
Double-entry Ledger
Debit Customer Balance -100
Credit Merchant Balance +100
Every debit has a matching credit.
Why It Matters
- Auditable money movement
- Easier reconciliation
- Clear refund path
- Detects imbalance
- Prevents hidden money creation
👉 Interview Memorization
A payment system should use ledger-style accounting so every money movement is durable, balanced, and auditable.
9️⃣ External Processor Uncertainty
Payment processors and banks are external systems.
They can timeout, return ambiguous responses, or send delayed webhooks.
Ambiguous Case
Platform sends capture request
↓
Processor timeout
↓
Did capture happen?
Unknown
Handling
- Do not blindly retry non-idempotent calls
- Use processor idempotency when available
- Mark payment as pending or uncertain
- Poll processor status
- Wait for webhook
- Reconcile later
👉 Interview Memorization
External processor timeouts create ambiguous states, so payment systems need idempotent processor calls, pending states, webhooks, polling, and reconciliation.
🔟 Webhooks
External processors often notify status changes with webhooks.
Webhook Challenges
- Webhooks may arrive late
- Webhooks may arrive more than once
- Webhooks may arrive out of order
- Webhooks may fail delivery
- Webhooks must be authenticated
Webhook Processing
Receive webhook
↓
Verify signature
↓
Deduplicate event ID
↓
Load payment
↓
Apply valid state transition
👉 Interview Memorization
Webhook processing must be authenticated, deduplicated, and guarded by payment state transition rules.
1️⃣1️⃣ Retry Safety
Retries are necessary, but unsafe retries are dangerous.
Safe Retry Requirements
- Idempotency key at API layer
- Idempotency key with processor when possible
- Durable job state
- Exponential backoff
- Clear retry limit
- Dead-letter queue for manual review
Rule
Retry transport failure.
Do not duplicate business action.
👉 Interview Memorization
Payment retries should retry delivery, not duplicate the financial operation.
1️⃣2️⃣ Outbox Pattern
Payment systems often need to update a database and publish an event.
Problem
Update payment state
↓
Process crashes before publishing event
Downstream services never learn about the change.
Outbox Solution
Database transaction:
1. Update payment state
2. Insert outbox event
↓
Async relay publishes event
👉 Interview Memorization
The outbox pattern prevents payment state changes and downstream events from diverging.
1️⃣3️⃣ Reconciliation
Reconciliation compares internal records with processor and bank records.
Flow
Internal Ledger
↓ compare
Processor Report
↓
Matched / Missing / Mismatch
Reconciliation Finds
- Internal success, processor failure
- Processor success, internal missing record
- Amount mismatch
- Currency mismatch
- Duplicate charge
- Missing refund
- Settlement delay
👉 Interview Memorization
Reconciliation is the safety net that detects mismatches between the internal ledger and external payment processor records.
1️⃣4️⃣ Refunds and Disputes
Payments do not end after capture.
Follow-up Operations
- Refund
- Partial refund
- Chargeback
- Dispute
- Reversal
- Adjustment
Ledger Impact
Original charge:
Customer → Merchant
Refund:
Merchant → Customer
Do not delete the original transaction.
Append a new reversing entry.
👉 Interview Memorization
Refunds and disputes should be modeled as new ledger entries and state transitions, not by mutating history.
1️⃣5️⃣ Consistency Model
Payment consistency is not usually one global ACID transaction across all systems.
Strong Consistency Needed
- Internal payment state
- Ledger writes
- Idempotency key result
- Balance-impacting operations
Eventual Consistency Acceptable
- Notifications
- Receipts
- Analytics
- Search index
- Some reporting views
👉 Interview Memorization
Payment systems use strong consistency for internal money state and eventual consistency for downstream views and notifications.
1️⃣6️⃣ Observability
Monitor
- Payment success rate
- Payment failure rate
- Idempotency hit rate
- Duplicate request attempts
- Processor timeout rate
- Webhook delay
- Webhook duplicate rate
- Reconciliation mismatch rate
- Ledger imbalance alerts
- Refund failure rate
- Dispute rate
👉 Interview Memorization
Payment observability must track consistency risks, not only latency and error rate.
1️⃣7️⃣ Best Practices
Practical Rules
- Require idempotency for payment creation
- Store idempotency results durably
- Use request fingerprinting
- Model payments as state machines
- Use double-entry ledger
- Append entries instead of rewriting history
- Authenticate and deduplicate webhooks
- Use outbox for state-change events
- Reconcile with processors and banks
- Treat ambiguous states explicitly
Design Principle
Never trust retries.
Never trust external callbacks blindly.
Never lose the ledger trail.
👉 Interview Memorization
Stripe-like consistency comes from layers: idempotency, state machines, ledger correctness, webhook deduplication, and reconciliation.
🧠 Staff-Level Answer Final
👉 Full Interview Answer
A Stripe-like payment system handles consistency by assuming that clients retry, networks timeout, processors return ambiguous responses, and webhooks may be duplicated or delayed.
At the API layer, it uses idempotency keys so the same logical payment request executes at most once and retries return the original result.
The system should also fingerprint the request so a reused idempotency key cannot silently represent a different payment.
Underneath, the payment moves through a durable state machine with strict transition rules, such as created, authorized, captured, settled, refunded, or disputed.
Money movement should be recorded in a double-entry ledger so every debit has a matching credit and all changes are auditable.
External processor calls must be treated carefully because a timeout does not prove failure.
The system should use processor-side idempotency where possible, pending states for ambiguous outcomes, authenticated and deduplicated webhooks, polling, and reconciliation.
The outbox pattern helps keep payment state changes and downstream events consistent.
The main idea is that payment consistency is achieved through layered defenses rather than trusting one distributed transaction across clients, servers, banks, and processors.
⭐ Final Insight
Stripe-style Payment Consistency 的核心不是:
“请求成功就扣钱”
而是:
Idempotency
- State Machine
- Ledger
- Webhook Deduplication
- Retry Safety
- Reconciliation
最重要的一句话:
Retries must be safe.
Money history must be immutable.
中文部分
🎯 How Stripe Handles Payment Consistency(Stripe 风格支付一致性)
核心理解
支付系统最大的问题不是普通 API 延迟。
真正的问题是:
请求会重试
网络会超时
外部 processor 状态不确定
webhook 会重复或乱序
钱不能重复扣
高层架构
Client
↓
Payment API
↓
Idempotency Layer
↓
Payment State Machine
↓
Ledger
↓
Processor / Bank Network
↓
Webhook / Reconciliation
Idempotency Key
Idempotency key 用来防止重复支付。
POST /payments
Idempotency-Key: abc123
第一次请求执行支付。
后续相同 key 的重试返回同一个结果。
Request Fingerprint
同一个 idempotency key 不能对应不同请求。
Key: abc123
Amount: $100
Retry:
Key: abc123
Amount: $200
这种应该被拒绝。
Payment State Machine
支付应该是明确状态机:
CREATED
↓
AUTHORIZED
↓
CAPTURED
↓
SETTLED
失败或后续状态:
FAILED
CANCELED
REFUNDED
DISPUTED
REVERSED
Ledger
支付系统必须有账本。
推荐 double-entry ledger:
Debit Customer Balance -100
Credit Merchant Balance +100
每一笔钱的移动都要可审计。
External Processor Uncertainty
外部支付通道可能 timeout:
Capture request sent
↓
Processor timeout
↓
不知道是否真的成功
处理方式:
- 使用 processor idempotency
- 标记 pending / uncertain
- 等 webhook
- 主动查询状态
- 后续 reconciliation
Webhook
Webhook 不能盲目信任。
必须:
- verify signature
- deduplicate event ID
- handle out-of-order event
- apply valid state transition only
Reconciliation
对账用于比较内部账本和外部 processor 记录:
Internal Ledger
↓ compare
Processor Report
↓
Matched / Missing / Mismatch
这是支付一致性的最后安全网。
面试回答模板
A Stripe-like payment system handles consistency with idempotency keys, durable payment state machines, ledger correctness, webhook deduplication, and reconciliation.
Idempotency ensures client retries do not create duplicate charges.
The payment state machine ensures money movement only follows valid transitions.
The ledger records every debit and credit immutably for audit and reconciliation.
External processors can timeout or send duplicate webhooks, so the system must use processor idempotency, pending states, verified webhooks, and reconciliation jobs.
The key principle is that retries must be safe and money history must be immutable.
最终总结
Retries must be safe.
Money history must be immutable.
核心原则:
Idempotency + State Machine + Ledger + Webhook Dedup + Reconciliation
Implement