Why Payment Systems Are Distributed Systems
A payment is never one service's job: basket, stock, provider gateway, and ledger all have to agree. Here's why the synchronous chain breaks down.
A payment is never one service's job: basket, stock, provider gateway, and ledger all have to agree. Here's why the synchronous chain breaks down.
Payment.Succeeded does not mean Checkout.Completed. If you don't separate checkout and payment lifecycles, two truths collide in production.
The PSP taking the money is one step. Finishing the order is a saga that needs stock, finance, notifications, and cleanup to all succeed.
Re-reading the live basket during payment leaves amount and currency undecided. Without a snapshot frozen at intent time, finalization can't be trusted.
Idempotency isn't one header. It's a defense stack that has to be built separately across five layers, from the API key down to the step marker.
Webhooks repeat, disappear, arrive out of order, and show up late. Verify the signature, ACK fast, and never run the heavy work synchronously.
If a database write and an event publish aren't in the same transaction, one can vanish or duplicate. Outbox publishes; inbox dedups on the consumer.
Evidence is what the PSP told you. State is what you decided. Conflate the two, and recovery leaves you unsure which one to trust.
How the provider gateway owns the PSP SDK while the checkout orchestrator only ever sees a semantic interface — and why card and wallet flows share a…
Should the webhook the provider gateway receives reach downstream consumers under the PSP's own event name, or as a semantic event like…
A timeout, a 429, a 5xx, a business decline, and an infrastructure fault are not the same failure. Each category needs its own retry policy.
Exponential backoff, jitter, caps, the difference between retry and defer, and circuit breakers — turning the previous part's taxonomy into working code.
Acquiring a lease with a conditional UPDATE, the stuck-job watcher that rescues abandoned work, and why a broker's Nack alone isn't enough.
How sweepers heal drift: the PSP says succeeded while the local record says expired, and how aged FinalizePending records get resolved.
An incident playbook: the customer was charged but no order exists; the multi-intent cart problem; and why dedup must be cleaned up carefully.
When a webhook and a synchronous response touch the same payment at once, how do a version token and a lease resolve the race — and why can a stale read…
How to correlate every log, metric, and trace by payment id — and why a step event log plus deferred finalize metrics save operations.
Automation first: the reconciliation worker and recovery pipeline. When uniqueness walls block replay, evidence-driven human runbooks take over.
Exactly-once messaging is a lie. How defense in depth — idempotency, dedup, outbox, and reconciliation — produces an effectively-once business outcome.
The synthesis of a 22-part series: an architectural checklist for a production payment engine built around a checkout orchestrator and provider gateway.
Career perspective: fintech companies aren't looking for Stripe SDK skills — they want failure thinking, reconciliation, idempotency, and evidence-driven…