Playbook
Why Payment Capture Is Easy but Finalization Is Hard (Why Payment Capture Is Easy But Finalization Is Hard)
The PSP taking the money is one step. Finishing the order is a saga that needs stock, finance, notifications, and cleanup to all succeed.
Distributed Payment Engine
Part 3 of 22
A series on distributed payment architecture — the gap between capture and complete.
One step, six steps
When you say “payment received”, you usually mean one thing: the provider gateway sent a request to the PSP, and the PSP said “I took the money.” That's one call, one response, one check. But when you say “order completed”, you mean something much bigger: stock was decremented, a ledger entry was opened, the order was confirmed, the customer was notified, the basket was cleaned up, and any loyalty points were processed.
Capture: Checkout Orchestrator → Provider Gateway → PSP → "captured"
Finalization: Decrement stock + Ledger entry + Order confirmation + Notify + Cleanup
(six independent steps, each one able to fail on its own)
This part covers the most defining question in this series: why is capture easy, and why is finalization hard?
Concepts, defined where they first appear
📦 Capture
The PSP confirming it actually collected a previously authorized or directly requested amount; a single external-system fact.
📦 Finalization
The sum of all internal steps needed for the work to actually be done after capture: stock, finance, confirmation, notification, cleanup.
📦 Saga
A workflow pattern that manages multiple steps end-to-end, each with its own failure and compensation logic.
📦 Compensating Action
A reverse operation run to offset the effect of earlier steps when a saga step can't simply be undone.
📦 Step Marker
A durable record marking a saga step as complete, so a re-run doesn't repeat it.
Capture's simplicity comes from depending on a single participant (the PSP) and a single response. Finalization's difficulty comes from depending on many participants that can each fail independently.
Why capture is simple
Capture has a one-sentence success criterion: did the PSP say “collected” or not. That fact arrives synchronously or via webhook, its signature gets verified, and the related payment record moves to Captured. There's no writing to multiple databases, no calling multiple dependent services in sequence — just one external system's yes/no answer.
Provider Gateway --request--> PSP
Provider Gateway <--"captured"-- PSP
↓
Payment.Status = Captured
(one write, one decision)
Why finalization is a saga
When capture finishes, the work isn't done — the genuinely complex part starts now. For the order to count as “actually finished”, all of the following steps need to run reliably, in some order, until every one of them completes:
Finalization Saga
1. Convert the stock reservation into a firm decrement
2. Open the revenue entry in finance/ledger
3. Mark the order lines as confirmed
4. Notify the customer
5. Clean up the basket / active intent
6. (If applicable) process loyalty points or campaign effects
Each of these six steps has its own failure mode: the stock service might be temporarily unreachable, the finance service might reject a validation, the notification service might time out. Capture had one yes/no; finalization has six independent yes/nos, and none of them guarantees the others.
Partial finalization: the most dangerous intermediate state
The hardest scenario is when half the saga ran and half didn't. Say stock was decremented but the finance entry couldn't be opened; the process crashed, and the worker restarting needs to know exactly which steps already finished.
Finalization saga running
✓ Stock decremented
✓ Order confirmed
✗ Finance entry — worker crashed here
? Notification — never attempted
Worker restarts: which steps should it REPEAT, which should it SKIP?
You can't answer that question without step markers. Every step needs to durably record its own completion; otherwise a restarting worker either re-runs the whole saga and decrements stock twice, or does nothing and leaves the order stuck forever.
Why this distinction gets underestimated
Most teams, when they say “payment integration”, mean capture, and they plan it as a week of work. The finalization saga usually gets treated as “details” and ships to production without proper design. In reality, capture — as parts one and two showed — is talking to a single external system; finalization requires your own system to be resilient against its own failures. The latter demands a far bigger engineering investment.
The mappings that get confused most often
❌ Payment integration = implementing capture
✓ Payment integration = capture + the entire finalization saga
❌ If capture succeeded, the work is done
✓ Capture is the starting trigger for the finalization saga, not its end
❌ Saga step order doesn't matter, it's all “the same transaction”
✓ Each step can fail independently; each needs its own retry and compensation logic
❌ If the worker crashes, re-running the saga from scratch is safe
✓ Without step markers, re-running from scratch repeats completed steps and produces duplicate side effects
A checklist for testing your finalization saga
- Write out every step in your finalization saga individually: how many steps are there, and which ones call independent services?
- Test whether each step is idempotent on its own: does running the same step twice change the outcome?
- Deliberately kill the worker mid-saga (a chaos test). On restart, which steps does it skip, and which does it repeat?
- Does every step have a compensation or retry plan for its failure case, or was it written assuming “this step always succeeds”?
- If capture succeeds but the finalization saga never starts, how many minutes does it take you to notice?
If you can't pass two of these five tests, your finalization saga was probably written for the happy path, not the failure path.
What to take away from this part
- Capture is a single external system's (the PSP's) yes/no answer; that's where its simplicity comes from.
- Finalization is a saga requiring multiple independent steps to all complete; that's where its difficulty comes from.
- Partial finalization — some steps done, some not — is the most dangerous intermediate state, and it can't be recovered safely without step markers.
- If “payment integration” only covers capture, the riskiest part of the project was left out of the plan.
Capture is the moment the PSP agrees with you. Finalization is the moment your own system agrees with itself — and that's usually the harder side.
FAQ
Frequently asked questions
What is Capture?
The PSP confirming it actually collected a previously authorized or directly requested amount; a single external-system fact.
What is Finalization?
The sum of all internal steps needed for the work to actually be done after capture: stock, finance, confirmation, notification, cleanup.
Is it true that "Payment integration = implementing capture"?
Payment integration = capture + the entire finalization saga
What does this part lock in?
This part covers the most defining question in this series: why is capture easy, and why is finalization hard? Capture is a single external system's (the PSP's) yes/no answer; that's where its simplicity comes from. When you say “payment received”, you usually mean one thing: the provider gateway sent a request to the PSP, and the PSP said “I took the money.” That's one call, one response, one check. But when you say “order completed”, you mean something much bigger: stock was decremented, a ledger entry was opened, the order was confirmed, the customer was notified, the basket was cleaned up, and any loyalty points were processed.
Engineering Principles Learned
- Capture is a single external system's yes/no answer; finalization is a saga requiring multiple independent steps to all complete.
- Partial finalization is the most dangerous intermediate state, and it can't be recovered safely without step markers.
- The real engineering cost of payment integration isn't in capture — it's in the failure paths of the finalization saga.
Continue reading
Continue reading
Next in series
Immutable Payment Snapshot Design: Freezing the Cart at Intent Time
Re-reading the live basket during payment leaves amount and currency undecided. Without a snapshot frozen at intent time, finalization can't be trusted.
Next in series
Payment State Machine Design: Checkout vs. Payment Lifecycles
Payment.Succeeded does not mean Checkout.Completed. If you don't separate checkout and payment lifecycles, two truths collide in production.
Same series
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.