Payment Flow Diagram Guide
How to draw a payment flow diagram that survives contact with production — where the money actually moves, why the redirect back is not the answer, and three editable examples.
What is a payment flow diagram?
A payment flow diagram shows how one order turns into money in your account — and, more usefully, every point on the way where it stops being a straight line.
Most people draw this diagram once, get five boxes, and conclude it was not worth drawing: the customer pays, the provider approves, the order ships. That version is not wrong so much as it is a description of the two percent of the flow that never causes an incident. What causes incidents is that a payment is not one event. It is at least two — authorization, where the issuer agrees to hold the money, and capture, where the money actually moves — and they can be days apart. In between, the customer's bank may put a challenge screen in front of them, on a page you do not control, from which they may simply never return.
The other thing the five-box version hides is that "paid" is not the end. Money moves backwards, and it does so on a timescale set by card networks rather than by you: a refund next week, a partial refund when one item comes back, a chargeback filed up to 120 days after the sale. A payment state machine that ends at Paid is a state machine that will be edited under pressure, in production, by whoever is on call.
So the honest subject of this diagram is not the checkout. It is the gap between "the customer thinks they paid" and "we know we were paid" — and everything that can happen inside it.
What a payment flow diagram has to show
Six things. Miss the second one and the diagram will describe a system you do not have.
- Authorization and capture as two separate steps. Even if you capture immediately, draw both — because the day someone asks "can we only charge when it ships?", the answer is a change to one arrow rather than a redesign. Label what each one means in plain words: authorization is a hold with an expiry, capture is the transfer. An authorization that is never captured does not fail loudly; it lapses after about a week, silently.
- Where the result actually arrives. The browser coming back to your return page means the customer's session ended, nothing more. The authoritative answer arrives out-of-band from the provider, asynchronously, and it arrives whether or not the customer's browser survived. Draw both arrows, and mark which one you are allowed to believe. Treating the redirect as the answer is the single most common way a checkout ships with a hole in it.
- The step that leaves your process. 3-D Secure, a bank app switch, a wallet sheet — the customer goes somewhere you do not own and may not come back. Draw it as a branch with three outcomes, not two: approved, rejected, and abandoned. The third one has no arrow pointing back at you at all, which is exactly why it needs to be on the page.
- One idempotency key, chosen from something stable. A double-clicked button, a retried request and a refreshed tab are all the same charge to your customer and three charges to their card. The key has to come from the order, not from a timestamp or a random value generated per attempt — a key that changes on retry is not a key. Draw where it is created, and it will be obvious whether it survives a retry.
- Everything after "paid". Full refund, partial refund, dispute, chargeback, and the chargeback you win. This is where the money goes backwards, and it is the half of the state machine that gets left out because nobody is thinking about it during checkout week. A useful test: if your diagram has no state a payment can enter three months after the sale, it is missing one.
- The amount, at each point it can differ. Authorized, captured, refunded and settled are four numbers, and they are not always the same one. Partial capture, partial refund, currency conversion and provider fees each pull them apart. You do not need all of this on the main diagram, but you do need to know which number your
orders.totalcolumn is holding — and the diagram is where that question gets asked out loud.
Here is the skeleton almost everyone draws first, and it contains the bug. Every arrow is individually correct. The problem is that the whole thing is one synchronous request: the order is marked paid inside the same call that charged the card.
That shape only describes a payment where the issuer approves instantly with no challenge and nothing goes wrong on the way back — a minority of real outcomes, and in Europe not even a legal default for most transactions. It has no place to put a bank challenge screen, and nowhere for an answer that arrives four seconds after the customer closed the tab.
View the Mermaid source
sequenceDiagram
participant U as Customer
participant App as Your App
participant PSP as Payment Provider
U->>App: submit the payment form
App->>PSP: charge the card
PSP-->>App: approved
App->>App: mark the order as paid
App-->>U: redirect to the success pageHow to draw a payment flow diagram
Three steps. The first one decides what the diagram is about, and it is easy to get wrong in a way that feels productive.
Step 1 · Draw the money, not the screens
The tempting first move is to walk through the checkout as a user sees it: cart, address, payment method, review, confirm. Four of those five screens have nothing to do with whether you get paid, and putting them on the diagram pushes the part that matters into a corner.
Pick participants by a single test: can this box hold the money, or refuse to release it? For a card payment that gives you the customer, your application, your payment provider, and the issuing bank. The bank is the one people leave out, and it is the one that says no, asks for a challenge, or reverses the transfer three months later. Without it on the page, every decline is an unexplained arrow coming out of the provider.
Everything upstream of the payment method — cart, shipping, tax — belongs on a different diagram, if it belongs on one at all. This diagram starts at the moment an amount is fixed and someone is about to be charged it.
Step 2 · Mark the arrow you are allowed to believe
On the finished diagram there will be two arrows that both look like "the payment succeeded". One is the customer's browser landing on your return page. The other is the provider telling your server, out of band, that the intent succeeded. Only the second one is evidence. Mark it on the diagram, in words, so that nobody has to work it out from the arrow directions.
The reason is not subtlety, it is that the browser is not a participant in the payment. It is a bystander that happened to be present for part of it. It can be closed at the challenge screen, lose signal in a lift, be a mobile app that was killed by the OS, or arrive at your return page having been given the URL by someone who never paid at all. In every one of those cases the money still moved, and the only thing that knows it is the provider's asynchronous message.
The practical consequence is a shape most first drafts do not have: the return page reads current state and says "we are confirming your payment" if it does not yet see a result, while fulfilment hangs off the out-of-band message. Those are two arrows on the diagram and about fifteen lines of code, and the version without them fails in the way that is hardest to reproduce and most expensive to discover — money taken, order never created, and nobody knows until the customer writes in.
That out-of-band message is a webhook, so the usual rules apply to it — verify the signature on the raw body, deduplicate on the event id, acknowledge before doing the work. On this diagram it is one arrow; its internals are a diagram of their own, linked at the bottom of this page.
Step 3 · Draw it
Describe it in sentences and let text2diagram lay it out — "the customer places an order, we create a payment intent with the order id as the idempotency key, the customer enters card details with the provider, the issuing bank may ask for a 3-D Secure challenge, then the provider notifies our server and we mark the order paid" comes back as an editable sequenceDiagram with the branch already nested.
Or open one of the three below and change the participant names. The branch structure is the part worth keeping.
Payment flow diagram examples
Three diagrams: one checkout drawn correctly, the whole life of a payment including the parts that happen months later, and the decision tree for a charge that did not go through.
1 · Card checkout, with the challenge and the confirmation in the right places
The Note at the bottom is the whole point of the diagram. Two arrows arrive near the end and both look like success; only one of them is one.
Three details are worth copying exactly. The idempotency key is the order id, created before anything is sent — so a double-click, a retried request and a refreshed tab all resolve to the same intent instead of three charges. A key generated per attempt would look identical on the diagram and protect against nothing.
The card details go from the customer straight to the provider and never touch your server, which is what keeps your compliance scope small. On the diagram this is visible as an arrow that skips a participant, and it is worth drawing precisely because the wrong version — details posted to your backend, forwarded on — also looks perfectly reasonable as a sequence.
And the order is marked paid on the arrow from the provider to your server, not on the redirect above it. Those two arrows are the difference between a checkout that survives a closed tab and one that quietly loses orders it was paid for.
View the Mermaid source
sequenceDiagram
autonumber
participant U as Customer
participant App as Your App
participant PSP as Payment Provider
participant Bank as Issuing Bank
U->>App: place the order
App->>App: create the order, status awaiting_payment
App->>PSP: create a payment intent, idempotency key is the order id
PSP-->>App: intent id plus a client secret
App-->>U: payment form bound to that intent
U->>PSP: card details, they never reach our server
PSP->>Bank: authorization request
alt the issuer wants a challenge
Bank-->>PSP: 3-D Secure required
PSP-->>U: challenge screen hosted by the bank
U->>Bank: approve in the banking app
Bank-->>PSP: authenticated
else no challenge needed
Bank-->>PSP: authorized
end
PSP-->>U: send the browser back to our return page
PSP->>App: payment_intent.succeeded
App->>App: mark the order paid, then fulfil it
Note over PSP,App: this arrow is the truth - the redirect above is only a hint2 · The whole life of one payment
A state diagram, because a payment is an object that ages rather than a conversation. This is the version to put in front of anyone who thinks the work ends at checkout — roughly half the diagram describes things that happen after the customer has forgotten about the order.
Authorized and Captured being two states is the part to keep even if you capture immediately. The note says why: an authorization has an expiry, and it lapses without telling anyone. A warehouse that takes nine days to ship does not get a failed payment, it gets an order that was never actually charged.
Expired is worth its own state rather than an arrow into Declined, because the two need different handling — one customer needs a new card, the other needs to be asked to pay again for something they already agreed to buy.
Disputed with an edge back to Captured when you win is the branch people forget, and it is the one that makes the diagram operationally useful: a payment can leave a state you thought was final, three months after the sale, on someone else's timetable. If nothing in your model can do that, your model is wrong about what a payment is.
View the Mermaid source
stateDiagram-v2
[*] --> RequiresPayment: order placed
RequiresPayment --> RequiresAction: the issuer asks for 3-D Secure
RequiresAction --> Authorizing: the customer approved it
RequiresPayment --> Authorizing: no challenge needed
Authorizing --> Authorized: funds held, not moved
Authorizing --> Declined: the issuer said no
Authorized --> Captured: we ship, or we charge straight away
Authorized --> Expired: never captured, the hold is released
Captured --> PartiallyRefunded: one item came back
PartiallyRefunded --> Refunded: the rest came back
Captured --> Refunded: refunded in full
Captured --> Disputed: chargeback filed, up to 120 days later
PartiallyRefunded --> Disputed: chargeback filed
Disputed --> Won: our evidence was accepted
Disputed --> Lost: the funds are pulled back plus a fee
Won --> Captured: the money stays with us
Declined --> [*]
Expired --> [*]
Refunded --> [*]
Lost --> [*]
note right of Authorized
an authorization is a promise with an expiry
seven days is typical and it lapses silently
end note3 · What to do when the charge does not go through
A flowchart, because this one is a decision rather than a sequence — and the decision is made by code that runs long after the customer has left.
The split between soft and hard declines is the whole diagram. Insufficient funds and a briefly unreachable issuer mean try again later, it may work. A stolen card, a closed account or a plain "do not honour" means this will fail identically next week. Retrying the second kind is not merely useless: card networks track your authorization success rate, and a stream of retries against dead cards is one of the ways a merchant account starts attracting attention.
Note that a subscription and a one-off checkout take different paths from the same decline. Nobody is watching a subscription renewal, so retrying on a schedule is the correct behaviour. Somebody is watching a checkout — silently retrying behind their back while they stare at a spinner is worse than telling them immediately and keeping the cart intact.
The branch that gets left out is the one where retries are exhausted. Cancel the subscription and email the customer is an unglamorous box, and without it the failure mode is an account that quietly keeps working for a customer who has not paid in four months.
View the Mermaid source
flowchart TD
A[A charge attempt comes back declined] --> B{What kind of decline}
B -->|Insufficient funds, issuer unavailable| C[Soft decline]
B -->|Stolen card, closed account, do not honour| D[Hard decline]
B -->|Authentication required| E[Send the customer to a challenge]
C --> F{Is this a subscription}
F -->|Yes| G[Retry on day 3, day 5 and day 7, then stop]
F -->|No| H[Tell the customer now and keep the cart]
G --> I{Did one of them go through}
I -->|Yes| J[Captured]
I -->|No| K[Cancel the subscription and email the customer]
D --> L[Never retry, ask for a different card]
E --> M{Did they finish the challenge}
M -->|Yes| J
M -->|No| HPut your finger on the challenge screen and close the tab
Take the finished checkout diagram, find the arrow where the customer leaves for the bank's challenge screen, and put your finger there. Now decide that the customer approved it and then closed the tab — approval succeeded, the browser never came back.
Trace what your system does from that point using only the arrows on the page. If the answer is "the provider's message arrives, we mark the order paid, we fulfil, the customer gets an email", the design holds and the tab close was irrelevant, which is the correct outcome. If tracing it requires you to say the words "and then the user would come back to the success page", you have found a real hole: the money moved and no arrow on your diagram creates the order.
That is not a rare case. It is a customer on a phone, on a train, who did exactly what you asked them to do. Run the same finger test at each of the three places the flow leaves your control, and every hole that exists will be one of them.
FAQ
What is the difference between authorization and capture, and should both be on the diagram?
Authorization is the issuer agreeing to hold an amount; capture is the money actually moving. Both belong on the diagram even when you capture immediately, because the arrow between them is where a whole class of requirements lands later — charge on shipment, adjust for an out-of-stock item, capture less than you authorized. The detail that surprises teams is that an authorization expires, typically in about seven days, and it does so silently: nothing fails, the hold just disappears. If your fulfilment can take longer than that, the diagram needs a path from
Authorizedto an expired state and a decision about what to do there, because the alternative is discovering it as an order that shipped and was never charged.Can I mark the order as paid when the customer is redirected back to my site?
No. That redirect tells you the customer's browser reached a URL, which is not the same claim as the money moved. The browser can be closed at the challenge screen, killed by the OS, lose signal, or land on your return page because somebody shared the link. In all of those the payment may have succeeded and your redirect handler never runs — and in the last one it runs with no payment behind it at all. Fulfil on the provider's asynchronous confirmation, verified by signature, and let the return page do nothing but read current state and say "confirming your payment" when it does not yet see a result. On the diagram this is two distinct arrows near the end; if you only have one, that is the bug.
How do I show 3-D Secure or SCA on a payment flow diagram?
As a branch with three outcomes, not two. The issuer may or may not require a challenge, so the first split is between challenge and no challenge; inside the challenge branch the customer may approve it, fail it, or abandon it, and the third one is the one that matters because it has no arrow coming back to you. Draw the challenge as happening on the bank's own screen — that is why your session may not survive it, and why the outcome has to reach you through the provider rather than through the browser. Two things fall out of drawing it this way: the return page cannot be the source of truth, and a payment needs a state meaning waiting on the customer's bank that is neither pending nor failed.
How many states should a payment state machine have?
Around eight to twelve, and the count is less useful than a shape test: if no state can be entered three months after the sale, states are missing — a chargeback can be filed up to 120 days out. Below eight you have usually merged authorization with capture, or dropped partial refunds. Above twelve, check whether steps have crept in disguised as states:
SendingReceiptis something the system is doing, not a condition the payment is in, and those belong in the sequence diagram instead. Keep the payment's states separate from the order's, too — an order can bedeliveredwhile its payment isdisputed, and one machine trying to hold both ends up with states likedelivered_but_refunded.Which failed payments should be retried, and how often?
Retry soft declines — insufficient funds, an unreachable issuer, a temporary hold — and never retry hard declines, meaning a stolen card, a closed account or an outright refusal, because those will fail identically next week. The distinction matters beyond politeness: networks watch your authorization success rate, and hammering dead cards is a way to get your merchant account looked at. For subscriptions, three attempts spread over about a week — day 3, day 5, day 7 — is a common shape, and what the diagram must show is where retrying stops and what happens then, because that branch is the one usually missing. For an interactive checkout, do not retry silently at all: the customer is present, so tell them immediately and keep the cart.
Is it free?
Yes. Anonymous users get 20 generations per day, logged-in users 500. Opening any example on this page in the editor costs nothing — that path does not call the model at all.