← Back to blog
stripedecline-codesfailed-paymentsrecoverydunning
13 min readRecova

Stripe Decline Codes: What They Mean and How to Fix Them

Stripe decline codes tell you exactly why a card payment failed and what to do about it. This guide covers every major code, whether it is recoverable, and the right response for each one.

Contents

Stripe decline codes are short identifiers that tell you why a card payment failed. When a charge fails, Stripe returns a decline_code field in the API response , not just a generic "card declined" , and that code determines what you should do next.

This guide covers every major Stripe decline code, what it means, whether it is recoverable, and the right response for each one.


What is a Stripe decline code?

When a customer's card is declined, the card's issuing bank sends a response code back through the payment network. Stripe translates those raw network codes (ISO 8583 two-digit codes) into its own named identifiers: generic_decline, insufficient_funds, do_not_honor, and so on.

The translation matters because it standardizes dozens of bank-specific codes into a consistent set you can act on programmatically. The tradeoff is some specificity is lost , multiple bank codes can map to the same Stripe code, which is why generic_decline and do_not_honor cover such a wide range of situations.

You find the decline_code on the Charge object in the API response, or in the Stripe Dashboard under the failed payment detail. It is separate from the error code field, which indicates an API-level problem rather than an issuer decision.


Soft declines vs hard declines

Before going code by code, the most important distinction in payment recovery is soft vs hard.

Soft declines are temporary. The card is valid, the account exists, but something prevented the charge right now , a temporary hold, a bank system outage, a fraud flag that will clear. Retrying after a delay often succeeds.

Hard declines are permanent. The card is blocked, closed, stolen, or the account does not exist. Retrying the same card will not work. The only path forward is getting new payment details from the customer.

Treating a hard decline like a soft one , retrying a stolen card repeatedly , wastes API calls, risks triggering card network penalty fees, and signals to Stripe Radar that you have a high-risk merchant account. It makes things worse.


The four decline categories

Stripe's decline codes group into four practical categories that determine your recovery approach:

1. Soft declines

Temporary failures. The card is valid; something situational blocked the charge. Retry with a short delay (24 to 72 hours) before emailing the customer.

Stripe generic_decline: What It Means and How to Recover It The most common code. The issuing bank declined without providing a specific reason. This is a catch-all , it covers everything from a temporary hold to a bank system blip to a fraud flag the customer does not know about. Despite the name, most generic_decline failures are recoverable. Retry once within 24 hours silently. If that fails, send a payment update email.

Stripe insufficient_funds: What It Means and How to Recover It The customer does not have enough funds in their account to cover the charge right now. This is the most straightforward recovery: time the retry near typical payroll dates (the 1st and 15th of the month in the US, end of month for many international customers). Do not email immediately , a retry 2 to 3 days later succeeds in a meaningful percentage of cases without bothering the customer.

Stripe do_not_honor: What It Means and How to Recover It A generic bank refusal. Despite the alarming name, do_not_honor is frequently temporary. Banks use it for anything from insufficient funds to multiple back-to-back declines to a travel flag the customer has not cleared. Treat it like generic_decline: one silent retry, then email if that fails.

processing_error A technical error during processing , a bank system outage, a network timeout, or a processing issue on Stripe's side. Not the customer's fault and not a card problem. Retry within a few hours.

try_again_later Similar to processing_error. The bank is indicating a temporary block, not a permanent one. Wait 24 hours and retry.

no_action_taken The bank did not take action, usually because the charge attempt was incomplete or because of a processing system issue. Retry.

2. Card data errors

These indicate something is wrong with the card information itself , usually a typo, an expired card, or a mismatch between what the customer entered and what the bank has on file. The card may still be valid; the data is wrong.

Stripe expired_card: What It Means and How to Recover It The card's expiration date has passed. Stripe's Account Updater catches some of these automatically before the charge fails by fetching updated card details from card networks. When it does not, you need new card details from the customer. Email them before the charge fails if possible , proactive expiry emails sent 30 days out recover a meaningful portion of these before they become failures at all.

incorrect_cvc / invalid_cvc The CVC entered does not match the bank's record. Usually a typo in a subscription update flow. Email the customer to update their payment details. Do not retry , the card itself is not the problem, the data is.

incorrect_number / invalid_number The card number entered is wrong or does not pass the Luhn check. Same response: email for updated card details, do not retry.

invalid_expiry_month / invalid_expiry_year The expiry date entered is not a valid date. Data entry error in your checkout or update flow. Email for corrected card details.

incorrect_pin PIN entered does not match. Uncommon for card-not-present transactions (subscriptions), more common for in-person payments. Do not retry.

3. Hard declines

Permanent. Do not retry. The only recovery path is new payment information from the customer.

card_declined (with fraud signals) When Stripe Radar blocks a charge due to high fraud risk, the decline code comes back as card_declined with a risk_level of highest. Do not retry. Do not email the customer with a standard recovery flow , if the card is actually stolen, emailing only alerts the fraudster that you detected the failure.

Stripe lost_card: What It Means and How to Handle It The card has been reported lost by the cardholder. Hard decline. Stop all retries. You can email the customer on their account email asking them to update their payment method, but confirm the email address belongs to the legitimate account holder before doing so.

Stripe stolen_card: What It Means and How to Handle It The card has been reported stolen. Hard decline. Same response as lost_card. Flag the account for review before emailing.

pickup_card The bank is requesting the card be physically picked up , a signal used in in-person fraud scenarios. Extremely rare for online subscription payments. Hard decline.

fraudulent Stripe Radar blocked the charge. Hard decline. Do not retry. Review the account before taking any action.

do_not_try_again An explicit instruction from the network that retrying will not help. Hard decline. Treat as permanent and email for new payment details.

4. Account and restriction errors

These indicate a restriction on the account or card type that is specific to the transaction, not a temporary situation.

Stripe card_velocity_exceeded: What It Means and How to Recover It The card has hit a usage frequency limit the bank has set. This is a soft decline for subscription billing , it usually clears within 24 hours once the bank's velocity window resets. Retry the next day. If it persists across multiple billing cycles, the customer may have a spending limit on their card that prevents recurring charges.

transaction_not_allowed The card or account does not permit this type of transaction. This can mean the cardholder has blocked online transactions, or the card type does not support recurring charges. Email the customer to update to a card that allows recurring billing.

card_not_supported The card does not support this type of purchase. Common with some prepaid cards and certain international cards. Email for an updated payment method.

currency_not_supported The card does not support the currency you are charging in. Hard to recover from without changing the charge currency. Email the customer.

duplicate_transaction Stripe or the bank detected this as a duplicate of a recent charge. Usually a system error on the merchant side , a double-triggered webhook, a retry that overlapped with a pending charge. Fix the integration issue; do not retry immediately.

call_issuer The bank wants the cardholder to call them before the charge can proceed. The customer needs to contact their bank. Email them with instructions to call their card issuer and then update their payment method.

restricted_card The card has a restriction that blocks this transaction. Similar to transaction_not_allowed. Email the customer to update their payment method.

revocation_of_authorization The cardholder has revoked authorization for recurring charges on this card. This is a direct signal that the customer has asked their bank to stop charges from you. Treat this carefully , continuing to attempt charges after an explicit revocation creates chargeback risk. Pause retries and reach out to understand whether the customer wants to cancel or wants to update their payment method.


How Stripe Smart Retries fit in

Stripe Billing includes Smart Retries, an ML-powered retry system that automatically retimes failed payment attempts based on signals like the cardholder's payment history, the decline code, and patterns across Stripe's merchant base. Stripe's billing data shows that recovery tools helped merchants recover $6.5 billion in revenue in 2024, with Smart Retries recovering 9% more revenue than fixed-schedule retries.

Smart Retries handle soft declines well. What they do not do:

  • Send personalized emails to customers explaining what happened
  • Handle hard declines (they correctly skip retrying these)
  • Classify decline codes for your own routing logic
  • Provide per-code visibility into your recovery performance
  • Sequence follow-up communication across 30 days

Smart Retries are a starting point, not a complete recovery system. The 56% average recovery rate Stripe cites blends B2B and B2C merchants , independent data from Recurly's State of Subscriptions report puts B2C SaaS invoice recovery at 53.5% and B2B at 75%, reflecting that B2B customers with dedicated finance teams resolve payment issues faster.

For the 44% that do not recover through retries alone, a dunning sequence, with personalized emails timed to the decline code and retry attempts coordinated, is where most of the additional recovery happens.


Recovery by decline code: quick reference

Decline code Type Retry? Email customer?
generic_decline Soft Yes, after 24h If retry fails
insufficient_funds Soft Yes, near payroll dates If retry fails
do_not_honor Soft Yes, after 24h If retry fails
processing_error Soft Yes, after a few hours If retry fails
try_again_later Soft Yes, after 24h If retry fails
card_velocity_exceeded Soft Yes, after 24h If persists
expired_card Card data No Yes, request new card
incorrect_cvc Card data No Yes, request correction
incorrect_number Card data No Yes, request correction
lost_card Hard No Yes, with care
stolen_card Hard No Yes, with care
fraudulent Hard No Review first
do_not_try_again Hard No Yes, request new card
revocation_of_authorization Hard No Pause, reach out carefully
transaction_not_allowed Restriction No Yes, request new card
card_not_supported Restriction No Yes, request new card
call_issuer Restriction No Yes, ask them to call bank

What good recovery looks like

The gap between 56% (Stripe's average) and the top performers in the Recurly and Churn Buster data , who reach 70% to 94% , is not more retries. It is better sequencing.

The pattern that works:

  1. Decline code classification on the webhook. When invoice.payment_failed fires, read the decline_code immediately. Route soft declines to a retry-first sequence and hard declines to an email-first sequence. Do not treat them the same.

  2. Silent retry within 24 hours for soft declines. No email, no friction. Many soft declines clear on their own.

  3. Day 3 email if the retry did not work. A brief, direct email , not a template that looks like a form letter , explaining the payment did not go through and asking the customer to update their card. The tone matters. Customers who get an email that reads like it came from a person respond at higher rates than customers who get a dunning template.

  4. Day 7 retry and follow-up. Another retry attempt coordinated with a second email.

  5. Days 14 and 30 follow-up. For higher-value subscriptions, the sequence continues. Many recoveries happen later than merchants expect , Recurly's 2024 State of Subscriptions report found a 141-day median post-recovery lifetime, meaning customers who do recover stay for a long time.

  6. Hard decline immediate email. No retry wasted. Email on day 1 asking for a new card.

Recova automates this entire sequence per decline code category , soft, network, expired, fraud , with AI-generated emails tailored to the merchant's brand voice and the customer's history. The retry timing and email sequence run automatically from the moment the invoice.payment_failed webhook fires.


Running a free Stripe audit

If you want to see exactly how many failed payments are currently sitting in your Stripe account by decline code , and what the estimated recovery value is , Recova's free audit pulls this directly from your Stripe data in about two minutes. No account required.

What is the most common Stripe decline code?
`generic_decline` and `do_not_honor` together account for the majority of card declines. Both are catch-all codes that issuing banks use when they decline without providing a specific reason. Most are soft declines and recoverable with a properly timed retry.
What is the difference between a soft decline and a hard decline on Stripe?
A soft decline is temporary , the card is valid but something situational blocked the charge, like insufficient funds or a bank system issue. Retrying after a delay often works. A hard decline is permanent , the card is blocked, stolen, or closed. Retrying will not work and risks penalty fees from card networks.
Should I email a customer every time their payment fails?
No. For soft declines like `insufficient_funds` or `generic_decline`, retry silently first. Emailing immediately for a temporary issue creates unnecessary friction and can feel alarming to the customer. Only email if the retry also fails, or if the decline code is a hard decline that requires new card details.
Does Stripe Smart Retries handle all decline codes automatically?
Smart Retries handles soft declines by retiming retry attempts using machine learning. It correctly skips retrying hard declines. What it does not do is send personalized customer emails, give you per-code visibility into recovery performance, or run a multi-week dunning sequence. It is a good starting point but not a complete recovery system.
What should I do if I get a `revocation_of_authorization` decline code?
Stop retrying immediately. This code means the cardholder has explicitly asked their bank to block recurring charges from you. Continuing to charge creates chargeback risk. Reach out to the customer to understand whether they want to cancel or simply want to update their payment method.
How long should a dunning sequence run?
Most of the recovery happens in the first 14 days. A well-structured sequence runs through day 30 for higher-value subscriptions. Recurly's data shows recoveries continue beyond day 30 in a meaningful number of cases, so cancelling the subscription immediately after the first failure leaves money on the table.
Further reading
Recova
Published by
Recova

Recova recovers failed Stripe payments, fights chargebacks, and surfaces revenue intelligence for subscription businesses. 20% of what we recover, nothing until then.

Run your free Stripe audit

See exactly what your account is leaking. Free, no account required.

Start free audit →