Real-world scenarios that require the gap
The gap between authorization and capture is not a workaround; it exists because the moment a customer agrees to pay is frequently not the moment the merchant knows the final, correct amount to charge, or is even certain the service will be delivered at all.
- Hotels and car rentals authorize an estimated total (room rate plus an incidentals buffer) at check-in, then capture the actual amount — which may be lower, or higher after a minibar charge — at checkout, once the true total is known.
- Marketplaces frequently authorize at order time but capture only once a seller confirms the item shipped, so a payment is never taken for an order that turns out to be unfulfillable.
- Preorders authorize when the customer commits, months before the product exists, and capture only when it is ready to ship — charging up front for something that might never arrive would be a worse failure mode than a slightly delayed charge.
- Capture at shipment is the general form of the marketplace case: any merchant that ships physical goods can authorize at checkout to confirm the funds are actually available, then capture only when the order leaves the warehouse.
In every case, collapsing the two operations into one “charge the card” step either takes money the merchant is not yet entitled to, or forces the merchant to re-authorize repeatedly while it waits for a fact it does not have yet.
Where the money is, and what the customer sees
At authorization, no money moves. The issuer places a hold against the customer’s available balance or credit limit for the authorized amount, which is why an authorization is also called a hold. The customer typically sees this as a pending line on their account — reserved, but not yet a posted transaction, and it can disappear entirely if it is never captured and its hold expires.
At capture, money actually moves from the customer’s issuer toward the merchant’s payment processor, and the transaction becomes a posted charge the customer sees as final. This is also the point at which the amount is fixed: capturing for a different amount than was authorized is the “partial capture” or “over-capture” case described below, not a correction you make after the fact to the authorization itself.
The practical consequence for an application’s data model is that “the customer has agreed to pay” and “the merchant has been paid” are two different facts, true at two different times, and a data model that only records one of them cannot answer honest questions about either.
Authorization expiry
An authorization does not last forever. Because it reserves a customer’s available funds without moving them, an issuer or network limits how long that reservation can sit uncaptured before it is released back to the customer — otherwise a merchant could hold money hostage indefinitely without ever completing the sale.
The general rule an application must design around: every authorization has a finite lifetime, and an application that tries to capture an authorization after it has expired must handle that as a real failure mode — typically by re-authorizing, if the customer’s payment method and consent still allow it, rather than assuming the original hold is still good.
The exact length of that lifetime is provider- and network-dependent, and this page deliberately does not state one as an industry-wide fact. Finxture’s own authored successful-payment flow uses a seven-day expiry window for its authorization, which is a reasonable illustrative default for local testing — not a claim about what any real card network or provider enforces. Confirm the actual window against current provider documentation before relying on it in production.
Partial capture, over-capture, and void versus refund
Real capture is rarely “capture the exact authorized amount, once.” Three related but distinct behaviors sit alongside the basic flow:
- Partial capture — capturing less than the authorized amount, typically because the final order total came in lower than the estimate, and releasing the uncaptured remainder back to the customer.
- Over-capture — some providers allow capturing slightly more than the authorized amount, within a small tolerance, to cover a final total that came in marginally higher than the original estimate without requiring a second authorization.
- Multicapture — capturing one authorization through more than one successful capture operation over time, useful when a single order ships in several parts.
Neither of these is implemented as a runnable scenario in Finxture today —
partial-capture and multicapture currently exist only as planned catalog
entries — but this section is the concept those two future scenarios will be
built against, so their eventual behavior is defined here once rather than
reinvented per scenario.
Voiding an authorization and refunding a capture are different operations with different customer-visible effects, and the difference matters. Voiding (also called reversing) an uncaptured authorization releases the hold before it expires on its own; because no money ever moved, the customer never sees a posted transaction at all — at most a pending hold disappears sooner than it otherwise would have. Refunding, by contrast, only applies to money that has already been captured: it returns funds after they moved, which the customer sees as a distinct posted credit, often on a different statement cycle than the original charge. An application that “refunds” an authorization that was never captured is describing an operation that has no funds to act on; the correct operation in that case is a void.
The data model: why four entities, not one status field
The temptation, especially early on, is to model a payment as a single row with
a status column that walks through values like pending, authorized, and
paid. This collapses under the very first case above: a hotel that authorizes
once and might need to retry authorization on a declined card, then captures a
different amount than it authorized, has history that one status column cannot
represent — you can tell where the payment ended up, but not how it got there,
and you cannot tell which specific authorization a given capture belongs to once
there has been more than one attempt.
The data model needs four distinct kinds of entity, not one:
- The payment — the durable record of what the customer owes, identified independently of any single attempt to collect it.
- The payment attempt — one attempt to complete that payment. A payment can have more than one attempt (a declined card followed by a retry with a different payment method is still one payment, but two attempts), so the attempt needs its own identity, separate from the payment it belongs to.
- The authorization — a hold placed during one attempt, carrying its own status, its own requested and captured amounts, and its own expiry.
- The capture — money actually moved against one specific authorization, with its own status and amount, distinct from the authorization it draws against.
This mirrors the canonical model: a payment resource references the
payment_attempt resources attempting to complete it, and each attempt carries
its own arrays of authorization and capture operations (plus authentication
operations, for flows like 3-D Secure, which are outside this article’s scope).
An authorization can have more than one capture against it (the multicapture
case above), and a capture always references exactly the one authorization it
draws against — never the payment or attempt directly.
The standard failure is collapsing the payment and the payment attempt into one entity. Once that happens, there is no way to represent “this specific attempt’s authorization was declined” without it looking like the whole payment failed, and no way to represent a successful retry without either losing the record of the earlier failed attempt or inventing a second payment for what is, to the customer, one purchase. Keeping the payment and its attempts as separate entities is what lets an application answer “did the customer pay?” (a property of the payment) and “what actually happened when we tried to collect it?” (a property of its attempts) as two different, both correct, questions.
What the notification stream looks like
A payment moving through authorization and capture produces four canonical state
transitions, each with its own event: authorization.succeeded and
payment.authorized when the hold is placed, then capture.succeeded and
payment.succeeded when the funds move. Two events per stage because the
transition changes two resources at once — the attempt’s nested authorization or
capture operation, and the payment’s own status — and each resource gets its own
event so a consumer watching either resource in isolation still sees a complete,
self-consistent history.
The one thing an integration must not assume is that a provider reports this one-for-one. A provider is free to fold more than one canonical transition into a single event it emits, or to omit an event a different provider would send for the same underlying change, and that grouping is a provider-specific fact rather than a canonical one — it belongs on the provider switcher of a page describing a specific scenario, not here. The practical rule: build a handler around “what changed on the resource,” derived from whatever events actually arrive, rather than around counting events and assuming a fixed number always arrive per business transition.
The same at-least-once delivery guarantee that makes duplicate webhook delivery a normal fact of life for any of these events also means their arrival order is not guaranteed — a fact this page deliberately does not go further into, since it is a delivery concern rather than an authorization-and-capture one.
What to test
Whatever the data model above, a payment integration’s automated tests should specifically exercise:
- Capture days after authorization, not just immediately afterward, so a test suite that only ever captures synchronously does not hide a bug that only shows up once real time passes between the two operations.
- Ordering between the authorization stage and the capture stage, since both are asynchronous notifications and nothing guarantees a consumer processes them in the order they occurred.
- An authorization that expires uncaptured, which is a real failure mode a customer can trigger simply by taking longer than expected, not an edge case that only matters in theory.