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.

48 of 48 codes

approve_with_idRetry may execute

The payment could not be authorized.

Next step: Attempt the payment again. If it keeps failing, the customer should contact their issuer.

authentication_requiredStripe will not retry

The card was declined because the transaction requires authentication such as 3D Secure.

Next step: Trigger an authentication flow. The customer can pay once authenticated.

On a subscription this is awkward, because authentication needs the customer present. It usually means moving them to an on-session payment.

call_issuerRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

card_not_supportedRetry may execute

The card does not support this type of purchase.

Next step: The customer should contact their issuer to enable the purchase type.

card_velocity_exceededRetry may execute

The customer has exceeded a balance, credit or transaction limit.

Next step: The customer should contact their issuer or use a different payment method.

currency_not_supportedRetry may execute

The card does not support the specified currency.

Next step: The customer should check with their issuer about currency support.

do_not_honorRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

Common and frustratingly vague. Often temporary, so it is generally worth a spaced retry before giving up.

duplicate_transactionRetry may execute

A transaction with identical amount and card details was submitted very recently.

Next step: Check whether a recent payment already succeeded before charging again.

expired_cardRetry may execute

The card has expired.

Next step: The customer needs to use a different card.

Not on Stripe’s hard decline list, so retries keep firing pointlessly. Treat this as an email trigger, not a retry.

fraudulentRetry may executeShow generically

Stripe suspects the payment is fraudulent.

Next step: Present as a generic decline. Do not disclose the reason.

generic_declineRetry may execute

The card was declined for an unknown reason, or was blocked by Radar.

Next step: The customer needs to contact their card issuer.

highest_risk_levelStripe will not retryShow generically

Stripe blocked the payment as highest risk.

Next step: Present as a generic decline. Do not disclose the reason.

incorrect_cvcRetry may execute

The CVC number is incorrect.

Next step: The customer should retry with the correct CVC.

incorrect_numberStripe will not retry

The card number is incorrect.

Next step: The customer should retry with the correct card number.

incorrect_pinRetry may execute

The PIN is incorrect. Card reader payments only.

Next step: The customer should retry with the correct PIN.

incorrect_zipRetry may execute

The postal code is incorrect.

Next step: The customer should retry with the correct postal code.

insufficient_fundsRetry may execute

The card does not have sufficient funds to complete the purchase.

Next step: The customer should use an alternative payment method.

Among the most recoverable declines. Retry when funds are likely present, around paydays, rather than a few hours later.

invalid_accountRetry may execute

The card or the account it is connected to is invalid.

Next step: The customer should contact their issuer to check the card works.

invalid_amountRetry may execute

The payment amount is invalid or exceeds the amount permitted.

Next step: The customer should check with their issuer about amount limits.

invalid_cvcRetry may execute

The CVC number is incorrect.

Next step: The customer should retry with the correct CVC.

invalid_expiry_monthRetry may execute

The expiry month is invalid.

Next step: The customer should retry with the correct expiry date.

invalid_expiry_yearRetry may execute

The expiry year is invalid.

Next step: The customer should retry with the correct expiry date.

invalid_numberRetry may execute

The card number is incorrect.

Next step: The customer should retry with the correct card number.

invalid_pinRetry may execute

The PIN is incorrect.

Next step: The customer should retry with the correct PIN.

issuer_not_availableRetry may execute

The card issuer could not be reached, so the payment could not be authorized.

Next step: Attempt again. If it persists the customer should contact their issuer.

Genuinely transient. A short backoff and retry recovers a good share of these.

lost_cardStripe will not retryShow generically

The card was reported lost.

Next step: Present as a generic decline. Do not disclose the reason.

merchant_blacklistRetry may executeShow generically

The payment matches a value on your Radar block list.

Next step: Present as a generic decline. Do not disclose the reason.

The card or account it is connected to is invalid.

Next step: The customer should contact their issuer.

Often means updated card details exist. Stripe’s Card Account Updater may pick these up automatically.

no_action_takenRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

not_permittedRetry may execute

The payment is not permitted.

Next step: The customer needs to contact their card issuer.

offline_pin_requiredRetry may execute

The card requires a PIN.

Next step: The customer should insert the card and enter a PIN.

online_or_offline_pin_requiredRetry may execute

The card requires a PIN.

Next step: Prompt for an online PIN if supported, otherwise the customer inserts the card and enters a PIN.

pickup_cardStripe will not retryShow generically

The card cannot be used, possibly because it was reported lost or stolen.

Next step: Present as a generic decline. The customer should contact their issuer.

pin_try_exceededRetry may execute

The allowable number of PIN attempts was exceeded.

Next step: The customer should use a different card or payment method.

processing_errorRetry may execute

An error occurred while processing the card.

Next step: Attempt the payment again. If it persists, retry later.

Transient by definition. Short backoff then retry.

reenter_transactionRetry may execute

The issuer could not process the payment for an unknown reason.

Next step: Attempt the payment again. If it persists the customer should contact their issuer.

restricted_cardRetry may executeShow generically

The card cannot be used, possibly because it was reported lost or stolen.

Next step: Present as a generic decline. The customer should contact their issuer.

revocation_of_all_authorizationsStripe will not retry

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

The customer has revoked all recurring authorizations. Retrying will not work, and continuing to try is a good way to attract a dispute.

revocation_of_authorizationStripe will not retry

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

The customer has revoked permission for this recurring charge specifically. Treat it as a cancellation signal, not a retry candidate.

security_violationRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

service_not_allowedRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

stolen_cardStripe will not retryShow generically

The card was reported stolen.

Next step: Present as a generic decline. Do not disclose the reason.

stop_payment_orderRetry may execute

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

The customer has instructed their bank to stop this payment. Functionally a cancellation.

testmode_declineRetry may execute

A Stripe test card number was used.

Next step: Use a real card.

If you see this in live mode, something in your integration is still pointing at test data.

transaction_not_allowedStripe will not retry

The card was declined for an unknown reason.

Next step: The customer needs to contact their card issuer.

try_again_laterRetry may execute

The card was declined for an unknown reason. Deprecated.

Next step: Attempt the payment again. If it persists the customer should contact their issuer.

withdrawal_count_limit_exceededRetry may execute

The customer has exceeded a balance or credit limit.

Next step: The customer should use an alternative payment method.

mobile_device_authentication_requiredRetry may execute

The transaction requires authentication on the customer’s mobile device.

Next step: The customer needs to re-tap their device.

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. Stripe also emits payment_intent.payment_failed for the same failure, and the two events differ in what they carry.

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.

Want to know what these are costing you? The retry waste calculator takes the counts from your last twenty failed invoices and works out how much of your failed revenue sits on codes no retry can ever collect. Runs in your browser.