🎉 Early access offer — 50% off your first year on any annual plan. Auto-applied at checkout. →

ReferenceApril 2026 · 9 min read

Stripe Decline Codes: The Complete List + Recovery Playbook (2026)

When a Stripe payment fails, the decline_code field tells you exactly why. Most SaaS teams treat all failures the same way — they shouldn't. The right retry timing and email copy depend entirely on which code fired. This guide covers every major Stripe decline code, what causes it, whether to retry, and what to say to your customer.

~62%

of payment failures come from just 3 decline codes

25–30%

of declines are expired cards — fully preventable

40–60%

recovery rate with a proper dunning sequence

72h

optimal retry window for most soft declines

What is a Stripe decline code?

When a card payment fails, Stripe receives a response from the customer's issuing bank. That response contains two pieces of information: an error code (the category of the failure) and a decline code (the specific reason). The decline code lives in the last_payment_error.decline_code field of a PaymentIntent or in charge.failure_code on a Charge object.

In a subscription context, Stripe surfaces the decline code on the invoice.payment_failed webhook event. This is the event your dunning system (or MRRescue) listens to — and the decline code it contains determines the entire recovery strategy.

From the invoice.payment_failed webhook

{
  "type": "invoice.payment_failed",
  "data": {
    "object": {
      "last_payment_error": {
        "code": "card_declined",
        "decline_code": "insufficient_funds",  ← this is what matters
        "message": "Your card has insufficient funds."
      }
    }
  }
}

Most teams log the error and send the same generic "your payment failed" email regardless of which code fired. That's a mistake — because the right action after insufficient_funds is completely different from the right action after expired_card.

Soft declines vs. hard declines

Before diving into individual codes, understand the fundamental split: soft declines are temporary failures that can resolve on their own — the customer's situation changes, or the bank's rules relax. Hard declines are permanent: the card is invalid, reported stolen, or blocked indefinitely. Retrying a hard decline is wasteful at best and damaging to your Stripe account health at worst.

Soft decline

Temporary failure. The card is valid but the transaction couldn't be processed right now. Retry after an appropriate waiting period.

insufficient_fundsdo_not_honorgeneric_declinetry_again_later

Hard decline

Permanent failure. The card is invalid, stolen, expired, or blocked. Retrying will always fail and can trigger Stripe account flags.

expired_cardlost_cardstolen_cardfraudulent

The 6 most common decline codes

These six codes account for roughly 90% of all subscription payment failures on Stripe. For each one: what it means, whether to retry, and what to write in your recovery email.

insufficient_fundsSoft~30% of failures

What it means

The customer's card or bank account doesn't have enough funds to cover the charge at this moment.

Retry strategy

Yes — retry in 3–5 days (payday cycle). Do not retry immediately.

Email copy approach

Keep it casual and blame-free. Say something like "We tried to process your renewal but the payment didn't go through — this happens sometimes. Your access is safe for the next 3 days, and we've set a reminder to retry." Include a direct link to update their card as a secondary option.

do_not_honorSoft/Hard~18% of failures

What it means

The issuing bank declined without a specific reason. Usually a temporary bank-side rule — fraud prevention, international block, or card spending limit reached.

Retry strategy

Retry once after 48–72 hours. If it fails again, treat as hard decline.

Email copy approach

Ask the customer to call their bank to approve the charge, or to try a different card. Be specific: "Your bank declined the payment — this is usually a temporary block. Please call the number on the back of your card and ask them to approve future charges from [your company name]."

card_declinedSoft~14% of failures

What it means

Generic decline from the issuer — the bank didn't provide a more specific reason. Similar to generic_decline.

Retry strategy

Retry once after 24–48 hours.

Email copy approach

Same approach as do_not_honor — ask for a card update or to contact their bank. Keep the tone light and solution-focused.

expired_cardHard (but recoverable)~25–30% of failures

What it means

The card's expiration date has passed. The card is permanently invalid — retrying will always fail.

Retry strategy

Never retry the same card. Ask for a new payment method immediately.

Email copy approach

This is the easiest recovery — the customer just needs to update their card. Be direct: "Your card ending in XXXX expired in [month/year]. Add your new card in 30 seconds and your subscription will continue without interruption." Link directly to the payment update page.

generic_declineSoft~8% of failures

What it means

The issuer declined for an unspecified reason. Often a fraud prevention rule, spending limit, or international block that the bank doesn't disclose.

Retry strategy

Retry once after 24–48 hours.

Email copy approach

Same as do_not_honor — bank contact + card update option.

fraudulentHard — do not retry~5% of failures

What it means

The card has been flagged for suspected fraud — either by the bank, by Stripe Radar, or because it was reported stolen. This is a hard block.

Retry strategy

Never retry. Retrying flagged cards can trigger Stripe account review.

Email copy approach

Send a gentle suspension notice. Ask the customer to reach out and add a new payment method. Do not reference fraud explicitly — say "We had a problem processing your card" and offer a direct line to your support team.

Full decline code reference table

Quick-reference for every Stripe decline code your subscription business is likely to see. Bookmark this page or copy it into your internal runbook.

CodeTypeRetry?Action
insufficient_fundsSoft✓ YesRetry in 3–5 days
do_not_honorSoft✓ YesRetry once after 48–72h
card_declinedSoft✓ YesRetry once after 24–48h
expired_cardHard✗ NoRequest new card immediately
generic_declineSoft✓ YesRetry once after 24–48h
fraudulentHard✗ NoSuspend + request new card
pickup_cardHard✗ NoSuspend immediately
stolen_cardHard✗ NoSuspend immediately
lost_cardHard✗ NoSuspend immediately
card_velocity_exceededSoft✓ YesRetry after 24–48h
currency_not_supportedHard✗ NoContact customer
not_permittedHard✗ NoRequest new card
transaction_not_allowedSoft✓ YesRetry after 24h
try_again_laterSoft✓ YesRetry after 1–4h
withdrawal_count_limit_exceededSoft✓ YesRetry next billing cycle
processing_errorSoft✓ YesRetry after 1–4h
call_issuerSoft✓ YesAsk customer to call bank, then retry
card_not_supportedHard✗ NoRequest different card type
duplicate_transactionSoft✗ NoCheck for duplicate charges
incorrect_numberHard✗ NoRequest new card details
incorrect_cvcSoft✗ NoAsk customer to update card
invalid_expiry_monthHard✗ NoAsk customer to update card
invalid_expiry_yearHard✗ NoAsk customer to update card

Retry strategy by decline type

The optimal retry timing isn't arbitrary — it's based on why the card failed. Stripe's Smart Retries algorithm accounts for some of this, but it treats all soft declines similarly. Pairing Smart Retries with decline-code-aware logic significantly improves recovery rates.

Insufficient funds

insufficient_fundswithdrawal_count_limit_exceeded

Wait 3–5 days. Many customers get paid on the 1st or 15th of the month — retry around those dates. If the initial failure was mid-month, a retry at month-end often succeeds. Limit to 3 retries total.

Issuer declined (no specific reason)

do_not_honorgeneric_declinecard_declined

Retry once after 48–72 hours. If the second attempt fails, stop automatic retries and send an email asking for a new card or a bank call. More than 2 retries on these codes risks increasing your Stripe decline rate.

Temporary network / processing error

processing_errortry_again_later

Retry after 1–4 hours. These are often infrastructure glitches on the network or bank side, not customer issues. A quick retry usually succeeds.

Expired card

expired_cardinvalid_expiry_monthinvalid_expiry_year

Do not retry. The card is dead. Send an update-card email immediately with a direct link. If the customer hasn't updated after 7 days, send a final warning before suspending.

Fraud / stolen / lost

fraudulentstolen_cardlost_cardpickup_card

Never retry. Suspend the subscription and send a support-focused email. Flag the customer for manual review if you're on the Pro tier.

What to say in your recovery email

Most failed payment emails say the same thing regardless of why the card declined. That's a missed opportunity. Customers respond better when the email addresses their actual situation — especially for declines they can act on immediately.

insufficient_funds

Subject

We'll try again in a few days — no action needed

Body (edit to match your tone)

Hi [Name], we tried to process your renewal but your card had insufficient funds. No worries — we've set a reminder to retry in 3 days. If you'd like to use a different card in the meantime, you can update it here: [link]. Your access continues as normal.

Why this works: Blame-free. Gives the customer time and an easy out. The 'no action needed' subject kills anxiety.

expired_card

Subject

Your card expired — update it in 30 seconds

Body (edit to match your tone)

Hi [Name], your card ending in XXXX expired in [month/year]. Add your new card here: [link]. It takes under a minute, and your subscription will continue without interruption.

Why this works: Direct and specific. The customer knows exactly what's wrong and how to fix it. No ambiguity.

do_not_honor / generic_decline

Subject

Your bank declined — a quick fix

Body (edit to match your tone)

Hi [Name], your bank declined our payment request — this is usually a temporary block, not a problem with your card. The fastest fix: call the number on the back of your card and ask them to approve future charges from [company name]. Alternatively, add a backup card here: [link].

Why this works: Gives a clear next action (bank call) that actually works for these declines.

For the full 6-email sequence with decline-code-aware copy for each step, see our failed payment email templates guide.

How to automate decline-code-aware recovery

Handling decline codes correctly at scale requires automation. There are two approaches:

Build it yourself: Listen to the invoice.payment_failed webhook. Read the decline_code. Build routing logic (if/else trees) that sends a different email and schedules a different retry for each category. Implement retry scheduling, sequence stopping, idempotency, and unsubscribe handling. Budget 3–6 weeks of engineering time and ongoing maintenance.

Use a dedicated tool: MRRescue's failed payment recovery reads the decline code from every invoice.payment_failed event and automatically sends the right recovery email with the right messaging. No code required — connects to your Stripe account via OAuth in 2 minutes.

See decline-code-aware recovery in action →

Frequently asked questions

What is a Stripe decline code?

A Stripe decline code is a machine-readable string returned by the card issuer when a payment is refused. It lives in the last_payment_error.decline_code field of a PaymentIntent. It tells you exactly why the bank said no — which determines the right retry strategy and recovery email.

What is the most common Stripe decline code?

For subscription businesses, the most common are insufficient_funds (~30%), do_not_honor (~18%), and expired_card (~25–30%). Together they account for roughly 60–70% of all subscription payment failures.

Should I retry a payment after a do_not_honor decline?

Yes, but only once and after 48–72 hours. do_not_honor is often a temporary bank decision. More than two retries on this code can escalate to a hard block or trigger Stripe account flags.

What does generic_decline mean in Stripe?

generic_decline is a catch-all for declines the bank won't explain — usually a fraud prevention rule or spending limit. Treat it like do_not_honor: retry once after 24–48 hours and send an email asking the customer to contact their bank.

Which Stripe decline codes should never be retried?

Hard codes that should never be retried: fraudulent, stolen_card, lost_card, and pickup_card. Retrying these risks Stripe account flags. Immediately ask the customer to add a new payment method.