Authorization and capture
Two steps, not one: the bank reserves the money on the card first, then you actually take it. The gap is why 'pending' charges appear and vanish.
See it
What it is
A card charge is two events, not one. Authorization asks the issuing bank to freeze an amount against the customer's credit line and hand back an approval code. No money has moved. Capture tells the network to actually collect it, after which it settles into your payout a day or two later. Most online stores fire both in one call and never think about it; hotels, car rentals, fuel pumps, and anything that ships later keep them apart on purpose.
Split them when the final amount or the fulfillment is uncertain: authorize when the order is placed, capture when it ships, capture less than you authorized if the order shrank, or raise the hold with an incremental authorization as a tab grows. Before capture, cancelling is a void: you submit the reversal the second you know, but the issuer decides when the hold actually disappears from the customer's available balance, which can take days and often still reads as 'pending' meanwhile. Whether a void costs you anything depends on your provider's pricing. After capture, it is a refund, which usually costs fees and shows up on the customer's statement as a second line.
Gotcha: authorizations expire, commonly around seven days for cards and sooner for some issuers and wallets. Capture after that and the hold may be gone, so you are re-charging a card that can now decline. The other one is a support problem: on debit cards a hold looks exactly like a real charge and the money is genuinely unavailable, so say so at checkout before the emails start.
Ask AI for it
Implement a two-step card charge in Stripe: create the PaymentIntent with capture_method set to 'manual' when the order is placed so it only places an authorization hold, then capture with the final amount when the item ships, allowing a partial capture if the order shrank. Capture only in response to a fulfillment event, never because an authorization is getting old. Cancel (void) the intent instead of refunding when the order is killed before shipping. Add a scheduled job that finds intents approaching expiry and, depending on order state, alerts ops, voids the ones that will not ship, or reauthorizes the ones that are fulfilled but past their hold. Show the customer a 'hold, not a charge' note at checkout with the held amount, and tell them a released hold can sit as pending on their statement for a few days.