Learn
Stripe Failed Payment Reasons: Every Decline Code Explained
When a Stripe charge fails, it returns a decline code that tells you exactly what went wrong. Understanding these codes is the first step to recovering lost revenue. Some declines are permanent — the card is stolen or the account is closed. But the majority are temporary and recoverable with the right approach. This guide covers every major Stripe decline code, explains what it means, and tells you what to do about it.
How Stripe Decline Codes Work
When you create a charge through Stripe, the request travels from Stripe to the card network (Visa, Mastercard, etc.) to the issuing bank. If the bank rejects the charge, it sends back a two-part response: a generic decline code (like 'card_declined') and often a more specific reason (like 'insufficient_funds').
Stripe normalizes these into a consistent set of decline codes you can access via the API or Dashboard. The charge object includes an outcome.reason field and a failure_code field that together tell you why the payment failed.
Not all decline codes are created equal. Some mean 'try again later' while others mean 'never try this card again.' Knowing the difference determines whether you should retry the charge, email the customer, or accept the loss.
Recoverable Decline Codes (Retry These)
insufficient_funds — The card has insufficient balance. This is the most common recoverable decline, accounting for roughly 25% of all failures. Retry after 24-72 hours, ideally aligned with common payday cycles.
processing_error — A temporary error on the bank or network side. Retry in 1-2 hours. These almost always succeed on the next attempt.
card_declined (generic) — The bank declined without a specific reason. This catch-all code often resolves on retry within 24 hours, especially if the first attempt triggered an automated fraud check that the bank subsequently cleared.
authentication_required — The charge requires 3D Secure authentication. Send the customer a payment link that includes the authentication flow. This is increasingly common in European markets under SCA requirements.
approve_with_id — The bank needs the cardholder to verify the charge. A retry after 24 hours often succeeds once the cardholder confirms via their banking app.
try_again_later — Explicit instruction from the bank to retry. Wait 2-4 hours and try again.
Non-Recoverable Decline Codes (Do Not Retry)
stolen_card / lost_card — The card has been reported stolen or lost. Do not retry. Email the customer to provide a new payment method.
expired_card — The card's expiration date has passed. Do not retry the same card. Email the customer to update their card on file.
card_not_supported — The card type is not supported for this transaction. The customer needs to provide a different card.
do_not_honor — A firm decline from the issuing bank with no specific reason. While occasional retries may work, repeated attempts can flag your merchant account. Best to contact the customer.
fraudulent — The bank has flagged the charge as potentially fraudulent. Do not retry. Contact the customer through a separate channel to verify their intent.
invalid_account — The card account is closed or invalid. The customer must provide a new payment method.
The Most Common Decline Codes by Frequency
Based on aggregate data from Stripe merchants, the most frequent decline codes are:
1. generic_decline / card_declined — 30-35% of all failures 2. insufficient_funds — 20-25% of all failures 3. expired_card — 15-20% of all failures 4. authentication_required — 10-15% (growing due to SCA) 5. processing_error — 5-8% of all failures 6. do_not_honor — 5-7% of all failures 7. All other codes — remaining 10-15%
Notably, roughly 60-70% of all declines fall into categories that are partially or fully recoverable through retries and customer communication. This is why payment recovery tools exist — the majority of failed payments should not be accepted as final.
Building a Decline Code Recovery Strategy
An effective recovery strategy treats each decline code differently. For insufficient_funds, schedule retries at 24 hours, 3 days, and 5 days — hitting payday windows. For processing_error, retry within hours. For expired_card, skip retries entirely and send a payment update email immediately.
This decline-code-aware approach is exactly what Revive automates. When a Stripe charge fails, Revive reads the decline code, routes the charge to the appropriate recovery flow, and executes the right combination of retries and emails without any manual intervention.
Manually building this logic into your own billing system requires webhook handlers for every decline code, a retry scheduling system, an email sender, and ongoing maintenance as Stripe adds new codes. Or you can connect Revive in 30 seconds and let it handle the entire matrix automatically.
Key Takeaways
- 60-70% of Stripe decline codes are recoverable through retries or customer outreach
- insufficient_funds is the single most recoverable decline — time retries around payday
- expired_card and stolen_card should never be retried — email the customer instead
- A decline-code-aware recovery strategy outperforms generic retry logic by 20-30%
Automate Your Payment Recovery
Revive uses everything in this guide — smart retries, decline-code routing, and branded recovery emails — on autopilot. Connect Stripe in 30 seconds.