Stripe Decline Codes Explained: Searchable Reference

Free reference

Stripe decline codes explained

Every card decline code Stripe returns, what it actually means, what to do about it, and the nine that Stripe will never successfully retry.

The nine codes Stripe will not retry

This is the part most people get wrong, so it is worth stating precisely. Stripe documents a specific set of hard decline codes. When one of these comes back, Stripe still schedules retries and still increments attempt_count, but the retry does not actually execute until a new payment method is attached.

In Stripe's own words: "For these failures, the scheduled retries continue but the payment only executes if you obtain a new payment method."

The practical consequence is that your retry count is not your recovery opportunity. If a chunk of your failures are these codes, no amount of retrying moves the number. Only getting a new card does.

The expired card trap

expired_card is not on Stripe's hard decline list. That means scheduled retries keep firing against a card that has expired.

They cannot succeed. An expired card needs a new number, not another attempt. So the retries burn through your schedule, increment the attempt count, and change nothing.

This is the clearest example of why decline codes matter more than retry volume. An expired card is an email problem, not a retry problem. The two things that actually fix it are prompting the customer to update their card, and Stripe's Card Account Updater refreshing it automatically where the issuer participates.

If you take one operational change from this page, make it this: route expired_card straight to a customer email rather than leaving it to the retry schedule.

Which declines are worth retrying

Outside the nine hard codes, the useful mental split is whether the reason is temporary.

A note on insufficient_funds. You will find sources that class this as a hard decline. It is not on Stripe's list of codes that block retries, and treating it as unrecoverable is a mistake. It is among the most recoverable declines there is, provided you retry when money is likely to be present rather than a few hours later.

Codes you should not explain to the customer

Stripe advises presenting certain declines generically rather than specifically. The reasoning is straightforward: if a card has been reported stolen, the person holding it may be the thief, and a precise error message is useful to them.

Present these as a plain "your card was declined, please try another payment method": fraudulent, lost_card, stolen_card, merchant_blacklist, pickup_card, restricted_card, highest_risk_level.

For benign codes such as expired_card, incorrect_cvc or incorrect_zip, being specific genuinely helps, so say what is wrong.

Finding your own decline codes

  1. In the Stripe dashboard, open Payments and filter to Failed.
  2. Open any failed payment. The decline code is on the payment detail page.
  3. Through the API, read decline_code on the charge outcome. It is more specific than failure_code, which is the broader category.
  4. For subscriptions specifically, listen for the invoice.payment_failed webhook and read the decline code off the attached charge.

What you are looking for is the distribution. If most of your failures are insufficient_funds, better retry timing will move real money. If most are expired_card or the hard codes, retry tuning will do nothing and your effort belongs in customer emails instead.

Frequently asked questions

Which Stripe decline codes cannot be retried?

Nine: incorrect_number, lost_card, pickup_card, stolen_card, revocation_of_authorization, revocation_of_all_authorizations, authentication_required, highest_risk_level, and transaction_not_allowed. Stripe still schedules retries for these, but they only execute once a new payment method exists.

Does Stripe keep retrying an expired card?

Yes. expired_card is not on the hard decline list, so retries keep firing. They cannot succeed without a new card number, which is why an expired card should trigger an email rather than another attempt.

What is the difference between a hard and a soft decline?

A soft decline is temporary and the same charge may work later. A hard decline means the issuer has rejected the card in a way retrying will not fix. Stripe's own definition of a hard decline code is one where the issuing bank has rejected the transaction and you cannot retry it.

Where do I find decline codes in my Stripe dashboard?

Payments, filtered to Failed. Open any failed payment and the code is on the detail page. Via the API it is the decline_code field on the charge outcome.

Should I show the decline reason to my customer?

Not for fraud-related codes, which Stripe advises presenting as a generic decline. For benign ones such as an expired card or a wrong CVC, being specific helps them fix it.

See your own decline mix

RecoverFlow scans your last 90 days of Stripe invoices and breaks your failures down by decline reason, so you can see whether retry timing or customer emails is where your money actually is. Free, no card required.

Run the free 90 day scan

Compiled from Stripe's published documentation on decline codes and revenue recovery as of 27 July 2026. Stripe occasionally adds or deprecates codes, so treat your own dashboard as the source of truth. Spotted something wrong? Email admin@recoverflow.org and it gets fixed.