Stripe decline codes, in plain English
Last updated 12 October 2026
When Stripe can’t charge a card, it records why on the payment: a decline_code that says what went wrong, and usually an advice_code that says what to do next. Most failed-payment emails ignore both and send everyone the same “your payment failed”. But no money in the account, a bank block and an expired card are three different problems, and each one has its own fix.
Where Stripe puts the reason
On the PaymentIntent behind the failed invoice, under last_payment_error. A subscription reaches it through its latest invoice:
subscription.latest_invoice.payments.data[0].payment.payment_intent
→ payment_intent.last_payment_error.decline_code // why
→ payment_intent.last_payment_error.advice_code // what nextinvoice.charge no longer exists on current API versions; invoice.payments replaced it. Stripe also stops expanding at four levels, so the PaymentIntent is one more request per failing customer.
Start with the advice code
Stripe sorts every decline into one of three next steps, and it keeps that sorting up to date. That makes it the safest thing to decide on. The decline code is for wording.
| advice_code | Means | Tell the customer |
|---|---|---|
try_again_later | A retry may work | Tell them when the retry is, and give them the invoice’s payment link in case they’d rather pay now. |
confirm_card_data | Card details need re-entering | Ask them to re-enter their card details on the payment page. Nothing is wrong with their bank. |
do_not_try_again | Needs a different card | Ask for a different card, or for a call to their bank. Don’t promise a retry, because it won’t happen. |
Two catches:
- A Radar block has no advice code at all. A charge Radar stops comes back as
fraudulent, with noadvice_code. Falling back to “try again later” for those promises a retry that Stripe blocks every time. Any code that Stripe never retries (listed below) means “don’t try again”. - The advice code is a plain string, not a fixed list. If a fourth value turns up, give it your safest email. Never use the cheerful retry email as the default.
Then word it with the decline code
Stripe gives insufficient_funds and generic_decline the same advice code. If you only look at the advice code, both get the same email, so the decline code is what lets you tell the customer what actually happened:
- No money:
insufficient_funds. Timing is the message here. Stripe runs the retry schedule and you can’t move a charge to payday, but you can send the email near payday with the invoice’s payment link. - A limit at the bank:
card_velocity_exceeded,withdrawal_count_limit_exceeded. These look like no money, but Stripe’s own advice is to call the bank or switch cards. A retry hits the same ceiling. - The card needs replacing:
expired_card,incorrect_number,invalid_number,invalid_expiry_month,invalid_expiry_year. The customer can fix these alone on the payment page. - The card was reissued:
new_account_information_available,invalid_account. They need the new card’s details. - The bank blocked it:
call_issuer,do_not_honor,transaction_not_allowed,card_not_supported,restricted_card. Only a call to the number on the back of the card, or another card, moves these. - No reason given:
generic_decline. Stripe says banks file most declines here, so write this email first and make it good. Exact reasons are a bonus.
Codes Stripe never retries
For these codes, Stripe keeps a retry on the calendar and keeps counting attempts, but never runs the retry until the customer adds a new payment method. The invoice shows a next retry date that will never come:
incorrect_numberlost_cardpickup_cardstolen_cardauthentication_requiredtransaction_not_allowedrevocation_of_authorizationrevocation_of_all_authorizationsfraudulentmerchant_blacklist
Never send these customers “we’ll try again on…”. Only a new card helps. Why Stripe isn’t retrying a failed payment covers what that does to your past-due list.
Four you must not repeat to the customer
Stripe is explicit: tell the customer these were a plain decline, never the real reason. You should still read them yourself, though. merchant_blacklist means your own block list stopped the charge, and a card reported stolen isn’t worth the chase an ordinary decline is.
fraudulentlost_cardstolen_cardmerchant_blacklist
Every code
| decline_code | What it means | Stripe retries |
|---|---|---|
fraudulentdon’t tell the customer | Blocked as suspected fraud | Never: needs a new card |
merchant_blacklistdon’t tell the customer | Your own block list stopped it | Never: needs a new card |
lost_carddon’t tell the customer | Card reported lost | Never: needs a new card |
stolen_carddon’t tell the customer | Card reported stolen | Never: needs a new card |
pickup_card | Bank asked for the card back | Never: needs a new card |
insufficient_funds | Not enough money in the account | Can |
withdrawal_count_limit_exceeded | Hit their withdrawal limit | Can |
card_velocity_exceeded | Too many charges on this card | Can |
expired_card | Card has expired | Can |
incorrect_number | Card number is wrong | Never: needs a new card |
invalid_number | Card number is wrong | Can |
invalid_expiry_month | Expiry date is wrong | Can |
invalid_expiry_year | Expiry date is wrong | Can |
incorrect_cvc | Security code is wrong | Can |
invalid_cvc | Security code is wrong | Can |
new_account_information_available | Card was reissued | Can |
invalid_account | Card was reissued | Can |
call_issuer | Their bank blocked it | Can |
do_not_honor | Their bank blocked it | Can |
transaction_not_allowed | Their bank blocked it | Never: needs a new card |
card_not_supported | Card not supported here | Can |
restricted_card | Card is restricted | Can |
processing_error | Error at the bank, not the card | Can |
generic_decline | Declined, no reason given | Can |
authentication_required | Authentication required | Never: needs a new card |
revocation_of_authorization | Revocation of authorization | Never: needs a new card |
revocation_of_all_authorizations | Revocation of all authorizations | Never: needs a new card |
Before you send anything
- Turn off Stripe’s own failed-payment emails in Billing settings if you write your own, or the customer gets two.
- Not every past-due invoice was declined. A payment waiting on 3-D Secure has no decline code, because nothing was declined. Its PaymentIntent is at
requires_action, and it needs the customer to approve the payment, not a new card. Check the PaymentIntent’s status before you read a decline code. - Don’t retry on your own past eight attempts. Stripe recommends at most eight per charge. More can look like fraud and get legitimate charges declined.
Gradsey’s Failed payments report does all of this for every failing card in your account. It shows each customer with their decline code, Stripe’s advice, the next retry (only if one will really run) and an email worded for their situation, ready to send from your Gmail.