The Card Authorization Lifecycle Engineers Actually Need
Listen to this article
Preparing audio…
FinTech Engineering
A card payment is not one transaction moving neatly from “pending” to “complete.” It is a set of related financial events—authorization, presentment, clearing, settlement, reversal, refund, and sometimes dispute—created by different actors on different clocks. My design rule is to correlate those events without collapsing them into one mutable status; the purchase scenarios below are synthetic.

Start with two timelines, not one status
At authorization time, the merchant sends an amount and card context through its acquirer and the card network to the issuer. The issuer approves or declines and returns identifiers that help later messages refer to the decision. Approval normally causes the issuer to reserve available funds; it does not prove that money has settled to the merchant.
Presentment happens later, commonly in a batch. Its amount can differ legitimately from the authorization because of tips, estimated amounts, partial fulfilment, currency conversion, or multiple shipments. Clearing calculates obligations among participants; settlement moves funds according to the network arrangement. A refund is a new credit transaction after capture, while a reversal tells the issuer that an authorization is no longer needed. Those are not interchangeable operations.
That distinction matters to customers. A stale authorization can leave funds unavailable even though the merchant will never capture them. Visa’s merchant guidance explains that an authorization reversal should carry matching transaction information so the issuer can identify and release the hold. Exact fields and deadlines vary by network, region, merchant category, and processor contract; the guidance is an example, not a universal clock.
Available balance and ledger balance should therefore remain separate concepts. The issuer may expose a pending hold immediately while the settled ledger changes later. On the merchant side, an approved authorization is not yet revenue or cash. Product screens may simplify these views, but their labels and support tools must preserve the distinction.
Model correlation without collapsing events
Use a stable internal payment_id, but give every network-facing event its own identifier and immutable record. A practical model separates:
authorization: requested amount, approved amount, decision, network references, expiry policy;presentment: presentment identifier, related authorization, amount, currency, sequence, received time;reversal: full or partial amount, reason, related authorization, acknowledgement state;refund: a new movement linked to the captured payment, with its own lifecycle;dispute: case identifier, disputed amount, condition, evidence deadline, and outcome.
Store both event time and ingestion time. The former says when the network says something happened; the latter explains when your platform learned it. Never overwrite an authorization amount with a clearing amount merely to make a single row “current.” Derive a customer-facing projection from the event history and retain the facts required to rebuild it.
The same rule applies to state. authorized, partially_presented, fully_presented, reversed, expired, and disputed may coexist across related records. A payment aggregate can summarize them, but its state machine must reject impossible transitions and expose uncertainty when a provider outcome is unknown.
Design for asynchronous and imperfect delivery
Processors frequently report later changes through webhooks. Stripe’s official webhook guidance documents duplicate delivery, asynchronous retries, and the absence of ordering guarantees. Treat that as a representative operational constraint, not as a rule for every processor.
Verify signatures, persist the raw notification, acknowledge quickly, and process from a queue. Deduplicate by the provider’s event identifier, while also making the domain handler idempotent. An event saying “payment updated” is a notification to query or apply a specific change; it is not automatically an accounting posting.
Unknown outcomes deserve an explicit state. If an authorization request times out, do not immediately route it to another acquirer: the first issuer may already have approved it. Query using the provider reference or wait for a definitive callback. Escalate aged unknowns to reconciliation instead of guessing.
Treat disputes as a separate case workflow
A dispute can begin weeks or months after authorization and settlement. It has reason-specific evidence, response deadlines, provisional financial effects, and an outcome. Visa’s Dispute Management Guidelines for Merchants, June 2024 illustrate why a dispute is not simply a terminal payment status.
Keep case management separate from the payment state machine. Link the case to the original authorization and presentment, then post fees, provisional credits, reversals, or final losses as distinct ledger transactions. This preserves both the operational history and the accounting explanation.
Controls engineers can test
Test more than the happy path:
- an approved authorization followed by no presentment and an explicit reversal;
- one authorization followed by two partial presentments;
- presentment received before a delayed authorization notification;
- duplicate reversal and dispute webhooks;
- a timeout followed by a late approval;
- refund requested during an open dispute;
- currencies or amounts that do not match within the permitted scheme rules.
For every test, assert the hold projection, customer-visible status, ledger entries, reconciliation result, and audit trail. Monitor authorization-to-presentment age, unmatched presentments, unreleased holds, unknown outcomes, duplicate notifications, and dispute deadlines.
The architecture decision
Do not build a card platform around one mutable payment_status. Build it around correlated, immutable events with explicit ownership and separate clocks. The aggregate is useful for product experiences, but authorization, presentment, reversal, refund, settlement, and dispute must remain independently explainable. That is what lets support answer a customer, finance reconcile a processor, and engineering recover safely when messages arrive late or twice.
Related reading
- Double-Entry Ledger Architecture for Product Engineers
- ISO 20022 as a Domain Model, Not an XML Problem
What decision would you make?
Add a question, a field note, or a respectful counterpoint. Comments are for signed-in members so the discussion stays useful and professional.