A decline response carries three codes, not one. How to read the network code, the advice code and the gateway code, and what to check before you retry.
Key takeaways
- A decline response usually carries three distinct codes, not one: the network decline code, the network advice code, and the gateway's own normalised code.
- The same number can mean different things on different card networks. Mastercard calls the advice code a Merchant Advice Code.
- The advice code is what decides the next move: do not use this card again, retry later, or ask the customer to confirm their card details.
- Retrying against the advice can breach card-scheme rules and trip fraud controls. The permitted number of attempts is set by the network rules and your acquirer agreement.
- Without the full response body stored at the moment of decline, there is no way to diagnose it afterwards.
A decline response has three layers: the decline code the issuer returned through the card network, the advice code that accompanies it, and the normalised code your gateway adds on top. The number alone is not enough, because its meaning changes between card networks. What decides whether a retry is allowed is the advice code, not the message your customer saw.
What is actually in a decline response
A decline is not one field. It is a stack of fields produced by different parties, and only one of them is designed to tell you what to do next. Stripe, which documents this structure publicly, separates network_decline_code from network_advice_code, and states that each is a 2-4 digit code supplied by the issuing bank whose meaning depends on the card network.
| Layer | Who produces it | What you can conclude from it |
|---|---|---|
| Network decline code | The issuing bank, via the card network | The raw reason. Network-specific, and sometimes absent entirely |
| Network advice code (Mastercard: MAC) | The issuing bank | What you are and are not allowed to do next |
| Gateway's normalised code | Your acquirer or gateway | A readable name such as insufficient_funds or expired_card |
| The message shown to the customer | Your own code | Nothing. It is a string somebody wrote in the UI |
That last row derails more investigations than any other. "Your payment was declined, please try another card" is text you wrote. It carries no information about what happened.
Why isn't the numeric code enough on its own?
Because the same number is not the same thing on two different networks. Stripe's documentation says it plainly: the meaning of a code differs based on the card network, so the card's brand has to be taken into account when interpreting it. A code returned on a Visa card and an identical code returned on a Mastercard are not necessarily the same problem.
Two practical consequences follow:
- An internal lookup table that maps a number to text without considering the card brand will produce a wrong diagnosis some of the time.
- The code field can come back empty. Stripe notes that when no response code is received from the network, the field is returned as null. An empty code is not "no problem" - it is "no information".
The three categories that decide what happens next
The most useful code in the response is the advice code, because it was designed to answer exactly the question "and now what". In Stripe's normalisation layer it appears as an advice_code field with three documented values:
do_not_try_again- the card was declined and should not be used again for the same transaction. The customer contacting their issuer is the only route forward.try_again_later- the issuer declined, but a retry is possible. This is the only category where charging again is a reasonable step.confirm_card_data- the decline was caused by information that was submitted incorrectly. You do not resubmit the same values; you ask the customer to verify their card.
Notice what that means. Two of the three categories say explicitly that resubmitting the same data will not produce a different result. That is precisely why a system that retries automatically after every decline works against itself.
What should you check before charging the same card again?
- The advice code, not just the decline code. If no advice code came back, treat the decline as final until proven otherwise.
- Whether the decline was caused by a value you submitted incorrectly - number, expiry or CVC. If so, the action is to correct the value, not to attempt again.
- Whether a successful charge for the same amount on the same card already exists in the last few minutes. Stripe defines
duplicate_transactionfor exactly this case, and its guidance is to check whether the payment already exists. - How many attempts have already been made against this transaction, and when. Without a persistent counter there is no way to know.
- Whether the customer is present. Somebody at the checkout can be shown an error and asked for another method; a background charge has no such option.
- Whether the decline is clustered across many customers in the same window. That pattern points at the acquirer or terminal configuration, not at cards.
- Whether the transaction required 3D Secure authentication that never ran. The fix there is to run the authentication flow, not to repeat the charge.
- What your acquirer agreement says about reattempts, and what each attempt costs you.
Where the limit on retrying comes from
Card networks cap how many times a declined transaction may be resubmitted, and exceeding that cap carries commercial consequences. Stripe states in its own documentation that card networks limit the number of times a single charge can be reattempted, and that excessive retries can look like potential fraud to issuers, which raises the decline rate on legitimate charges too.
The rules that actually bind you are the card networks' and those in your acquirer agreement, and they differ by network and by decline type. This is a technical description, not legal or contractual advice - confirm your retry policy with your acquirer before you implement it in code.
What to log so the next decline takes two minutes
- The gateway's transaction identifier, not only your internal one.
- The full response body exactly as received, including every code field - even the ones you do not interpret today.
- The card brand and last four digits, so attempts can be linked to each other.
- A precise timestamp and the attempt number in the sequence.
- Whether the customer was present, and which flow the charge came from.
Without the first four, every conversation with your acquirer starts with a question you cannot answer. The difference between a business that resolves a decline in two minutes and one that gives up on it is almost always the decision to store the response body rather than only the word "failed".
What this looks like implemented properly
A charge flow that handles declines well is not more complex. It simply separates three decisions that usually get tangled together: what happened, what the customer is told, and what happens next.
- The diagnosis layer reads the response, stores it verbatim, and sorts it into one of the three categories. It is the only layer that knows about codes.
- The presentation layer receives a category, not a code, and decides what to say. Wording can then change without touching any logic.
- The decision layer determines whether and when another attempt happens, based on the category, the attempt counter, and the policy agreed with your acquirer.
That separation prevents the most common defect in payment code: one long condition that mixes the customer message, the retry decision and the interpretation of a code, which nobody dares touch six months later.
Related: Handling decline codes from Israeli gateways, Israeli payment gateways compared, Automating invoicing and payment reminders.
Sources
Frequently asked questions
Why doesn't the message my customer saw match the decline reason?
The on-screen message is text written in your own interface, and it often withholds the reason deliberately. For suspected fraud or a card reported lost, gateways explicitly recommend showing a generic message rather than the real cause, which means the actual reason exists only in your logs.
I received an empty decline code. What does that mean?
That no response code was received from the network for that transaction. It does not mean the payment was fine, and it does not mean it failed for a known reason - there is simply no information. Rely on the transaction status at the gateway rather than interpreting the empty field.
Can I just retry automatically after every decline?
No. A large share of declines are explicitly flagged as ones you should not reattempt with the same data, and retrying those burns permitted attempts while also looking suspicious. Retry policy has to be derived from the advice code and from your acquirer agreement, not applied uniformly.
How do I tell a card problem from a provider outage?
By the spread. A decline on one card is almost always the issuer. A sharp rise in declines across many customers, in a short window and with similar codes, points at the acquirer or the terminal configuration - and in that case retrying only makes the damage larger.
Keep reading
Related service
Integrations
Make the systems you already pay for talk to each other.
About the author
Yehonatan Saadia
Freelance automation, web & MVP developer
I'm Yehonatan Saadia, a senior developer who builds business automation, custom websites, and MVPs for small and mid-sized companies across the US, Europe, and Israel. These guides come from real client work, not theory.
Work with meHave a project like this?
Tell me what you're trying to automate or build. I reply within 24 business hours with a few targeted questions, then we walk through it on a free 30-minute call, with no commitment. You come away with a scope, a timeline and a fixed price - or a straight answer that it isn't worth building.
