A Stripe decline code is a short label — like insufficient_funds, expired_card, or do_not_honor — that tells you exactly why a card payment failed, and whether it is worth retrying. This guide explains every decline code that matters, whether each is a soft or hard decline, and how to recover it.
When a subscription charge fails, Stripe does not just say "declined" — it returns a specific reason on the charge's outcome object. That reason is the single most useful piece of information you have, because it decides your next move. Retrying the wrong code wastes attempts and can hurt your processing reputation; emailing for a new card when a simple retry would have worked annoys good customers. Read the code right, and recovery gets far more effective.
Key takeaways
- Decline codes fall into two groups: soft (temporary — retry) and hard (permanent for that card — get a new one).
- Retry
insufficient_fundsandprocessing_error; never retryexpired_card,lost_card, orstolen_card. do_not_honoris the most common and most ambiguous — retry once or twice, then ask for a new card.authentication_requiredis not a money problem — send the customer to re-authenticate, don't retry.
What is a Stripe decline code?
A decline code is a machine-readable string Stripe attaches to a failed charge to describe why the bank or network rejected it. You will see two related fields: outcome.reason, which is Stripe's own categorization, and decline_code, the more specific reason from the customer's bank when it is provided. Together they tell you whether the card itself is the problem (hard) or the timing is (soft).
Soft vs hard declines — the distinction that matters
Almost every recovery decision comes down to one question: is this a soft or a hard decline? A soft decline is temporary — the card works, but this particular charge failed for a passing reason, so a retry a day or two later often succeeds. A hard decline is permanent for that card — it is expired, wrong, closed, or blocked — and no number of retries will ever clear it.
Route every failure by its type, and never treat the two the same:
The most common Stripe decline codes (quick reference)
Here are the codes you will see most often, with whether to retry and how to fix each. Detailed explanations follow below.
| Code | Meaning | Type | Retry? | Fix |
|---|---|---|---|---|
| insufficient_funds | Not enough money | Soft | Yes | Retry near payday |
| do_not_honor | Generic bank decline | Ambiguous | Once or twice | Retry, then new card |
| expired_card | Card past expiry | Hard | No | New card |
| incorrect_cvc | Wrong security code | Hard | No | Re-enter card |
| card_declined | Generic / fraud decline | Hard-ish | Maybe once | New card |
| lost_card / stolen_card | Reported lost or stolen | Hard | No | New card |
| processing_error | Temporary processor error | Soft | Yes | Retry shortly |
| authentication_required | Needs SCA / 3D Secure | Auth | No | Re-authenticate |
| currency_not_supported | Card can’t use currency | Hard | No | Different card |
| card_velocity_exceeded | Too many attempts | Soft | Wait | Retry later |
Soft decline codes (retry these)
These are temporary. The card is valid, so a well-timed retry — especially around a payday — frequently succeeds without the customer doing anything.
insufficient_fundsSoft · retryThe account does not currently have enough money to cover the charge.
What to do: Retry over a few days, ideally around a payday window — this often clears on its own.
processing_errorSoft · retryA temporary error occurred while processing the card, usually on the network or processor side.
What to do: Retry shortly. If it repeats across many customers, check for a processor incident.
issuer_not_availableSoft · retryStripe could not reach the customer’s bank to authorize the charge.
What to do: Retry a bit later once the issuer is reachable again.
try_again_laterSoft · retryThe bank asked to retry the transaction later without giving a specific reason.
What to do: Wait and retry — do not hammer it repeatedly in a short window.
card_velocity_exceededSoft · retryThe card has been used too many times in a short period and the bank temporarily blocked it.
What to do: Wait, then retry later. Avoid rapid repeated attempts, which make it worse.
reenter_transactionSoft · retryThe bank could not process the transaction for an unknown reason and suggests re-submitting.
What to do: Retry once; if it fails again, treat it like a generic decline and email the customer.
Hard decline codes (get a new card)
These are permanent for the card on file. Retrying is pointless and can hurt your processing reputation — go straight to a personalized email asking the customer to update their card.
expired_cardHard · needs new cardThe card on file has passed its expiration date.
What to do: Do not retry — email the customer to add a current card.
incorrect_cvcHard · needs new cardThe CVC security code provided does not match the card.
What to do: Ask the customer to re-enter their card details correctly.
incorrect_numberHard · needs new cardThe card number entered is invalid.
What to do: Ask the customer to re-enter a valid card number.
card_declinedHard · needs new cardA generic decline from the bank; when the reason is fraud-related it is permanent for that card.
What to do: Retry once if the reason is unclear; if it persists, ask for a different card.
lost_cardHard · needs new cardThe card was reported lost. Stripe often masks this as a generic decline to avoid tipping off fraud.
What to do: Do not retry — request a new card.
stolen_cardHard · needs new cardThe card was reported stolen. Like lost_card, this is a permanent block.
What to do: Do not retry — request a new card.
pickup_cardHard · needs new cardThe bank has flagged the card and wants it retained; it will not authorize charges.
What to do: Do not retry — ask the customer to use a different card.
currency_not_supportedHard · needs new cardThe card cannot be charged in the currency of the transaction.
What to do: Ask the customer for a card that supports your billing currency.
invalid_accountHard · needs new cardThe card or account is invalid or closed.
What to do: Do not retry — request a new payment method.
The ambiguous ones (do_not_honor, SCA)
A few codes do not fit neatly into soft or hard and need judgment.
do_not_honorSoft · retryA catch-all decline from the bank with no reason given — the single most common and most ambiguous code.
What to do: Retry once or twice; if it keeps failing, email the customer to try another card or call their bank.
generic_declineSoft · retryThe bank declined without a specific reason. Similar to do_not_honor.
What to do: Retry cautiously; if it persists, treat it as a hard decline and ask for a new card.
authentication_requiredAuth · re-authenticateThe charge needs Strong Customer Authentication (SCA / 3D Secure) — common for European customers under PSD2.
What to do: Do not retry — send the customer a link to re-authenticate and approve the payment.
A note on do_not_honor
do_not_honor is both the most common decline and the least informative — the bank simply refuses without saying why. Treat it as soft once or twice (a short retry can clear it), but if it persists, stop retrying and email the customer to try another card or call their bank. Endless retries on a persistent do_not_honor just waste attempts.
How to recover payments by decline code
Reading the code is only half the job — the other half is doing the right thing with it:
- Soft declines → smart retries. Re-attempt the charge over several days, timed for when a card is likely to have funds (payday windows).
- Hard declines → a new-card email. Send a personalized message naming the exact reason (expired, incorrect, etc.) with one button to update the card. See our dunning email templates for copy.
- authentication_required → a re-auth link. Send the customer to a Stripe-hosted authentication page rather than retrying.
- Ambiguous → retry once, then escalate. Give it one or two retries, then treat it like a hard decline.
For the full setup — retries, emails, pre-dunning and SCA — see our guide on how to recover failed Stripe payments, or compare the tools that automate all of it in our roundup of the best payment recovery tools.
Where to find the decline code in Stripe
In the Dashboard, open any failed payment and read the decline reason in the payment details. Via the API, inspect the charge's outcome object: outcome.reason and outcome.network_statusgive Stripe's view, and the raw decline_codegives the bank's reason when available. Stripe documents the full list in its decline codes reference.
Frequently asked questions
What is a Stripe decline code?
A Stripe decline code is a short machine-readable string, like insufficient_funds or expired_card, that explains why a card payment failed. Stripe returns it on the charge in the outcome object (outcome.reason and, when the bank provides it, decline_code). It tells you whether the failure is worth retrying or needs the customer to take action.
What is the difference between a soft decline and a hard decline?
A soft decline is temporary — the card is fine but the charge failed for a passing reason like insufficient funds or a processor timeout, so a later retry often succeeds. A hard decline is permanent for that card — expired, incorrect details, lost, stolen, or blocked — so retrying never works and you need the customer to enter a new card.
What does the decline code do_not_honor mean?
do_not_honor is a generic decline from the customer’s bank with no specific reason given. It is ambiguous: sometimes it clears on a retry a day or two later, and sometimes it is effectively permanent. The best approach is to retry once or twice, and if it persists, email the customer to try a different card or contact their bank.
Should I retry a declined card?
It depends on the code. Retry soft declines (insufficient_funds, processing_error, issuer_not_available) — ideally around a payday window. Do not retry hard declines (expired_card, incorrect_cvc, lost_card, stolen_card); they will never succeed, and repeated attempts can hurt your processing reputation. For authentication_required, send the customer to re-authenticate rather than retrying.
Where do I see the decline code in Stripe?
In the Stripe Dashboard, open the failed payment and look at the payment details — the decline reason is shown there. Via the API, check the charge’s outcome object: outcome.reason gives Stripe’s categorization, and outcome.network_status plus the raw decline_code give the bank’s response when available.
How do I recover payments that failed with these codes?
Match the tactic to the code: smart retries for soft declines, a personalized "add a new card" email for hard declines, and a re-authentication link for SCA. A tool like Revova reads each decline code automatically and sends the right recovery action, then also scans your history to recover past failures.
Let Revova read the code and recover the payment
Revova reads every decline code automatically and takes the right action — retry, new-card email, or re-authentication — then scans your history to recover past failures too. Start free and see what you've already lost.
Start my 14-day free trial →No credit card · Free Lost Revenue scan · 30-day money-back guarantee




