Stripe Payment Failure Codes Explained: What Each One Means and How to Fix It
Your Stripe payment failed. But why? This complete reference explains every major Stripe decline code, what causes it, and the optimal retry strategy for each.
Understanding Stripe Decline Codes
When a payment fails on Stripe, you don't just get "payment failed" โ you get a specific decline code that tells you why it failed. Understanding these codes is critical because:
- ๐ฏ Different codes require different strategies โ retrying an expired card won't work, but retrying insufficient funds might
- โฑ๏ธ Timing matters โ some failures should be retried immediately, others need days
- ๐ง Customer communication varies โ your dunning email should match the decline reason
Bookmark This Page
This is a reference guide. Keep it handy when debugging payment failures.
Every SaaS founder dealing with Stripe should understand these codes to minimize revenue loss from failed payments.
How Stripe Decline Codes Work
When Stripe attempts to charge a card, it communicates with the customer's bank (the issuing bank). The bank either approves or declines the charge, sending back a decline code that explains why.
Stripe surfaces these codes in:
- โ Your Stripe Dashboard (Payments โ Failed)
- โ
Webhook events (
charge.failed) - โ
API responses (in the
decline_codefield)
Each code falls into one of three categories:
- 1. Retriable Failures โ Temporary issues that might succeed if retried later (e.g., insufficient funds, processing errors)
- 2. Non-Retriable Failures โ Permanent issues that won't succeed without customer action (e.g., expired card, card reported stolen)
- 3. Fraud/Risk Failures โ Security blocks that require verification or alternative payment methods
The Most Common Stripe Decline Codes (And What to Do About Each)
1. card_declined โ Generic Decline
What it means: The bank declined the charge, but didn't provide a specific reason. This is the most common decline code.
Why it happens:
- ๐ฐ Insufficient funds (but the bank didn't specify this)
- ๐จ Fraud detection triggered by unusual activity
- ๐ Daily spending limit reached
- ๐ International transaction blocked
Optimal retry strategy:
Retry schedule: 4 hours โ 1 day โ 3 days โ 7 days
Email customer? Yes, after 2nd retry failure
Likelihood of recovery: 45-50% if retried strategically
What to tell the customer: "Your bank declined the charge. This can happen for several reasons โ try contacting your bank or using a different payment method."
2. insufficient_funds โ Not Enough Money
What it means: The cardholder doesn't have enough funds available to cover the charge.
Why it happens:
- ๐ธ Low account balance at billing time
- ๐ Billing date hit before payday
- ๐ณ Credit limit reached
Optimal retry strategy:
Retry schedule: 2 days โ 5 days โ 10 days โ 15 days
Email customer? Yes, but gently (don't embarrass them)
Likelihood of recovery: 60-70% if you wait for payday (usually 1st or 15th)
What to tell the customer: "We had trouble processing your payment. We'll automatically retry in a few days, or you can update your payment method now."
Pro Tip
Time your retries around common paydays (1st, 15th, last day of month). This can increase recovery rates by 20-30%.
3. expired_card โ Card Expired
What it means: The card on file has passed its expiration date.
Why it happens:
- ๐ Customer didn't update their card info after receiving a new one
- ๐ณ 20-40% of cards expire annually โ this is extremely common
Optimal retry strategy:
Retry schedule: Don't retry โ it will fail every time
Email customer? Yes, immediately with a card update link
Likelihood of recovery: 70-80% if you email within 24 hours
What to tell the customer: "Your card ending in [last 4] expired on [date]. Update your payment method to keep your subscription active."
Prevention: Enable Stripe's Card Account Updater to automatically refresh expired cards (reduces expired card failures by 30-40%).
4. lost_card / stolen_card โ Card Reported Lost or Stolen
What it means: The cardholder reported the card as lost or stolen to their bank.
Why it happens:
- ๐จ Card was genuinely lost or stolen
- ๐ณ Customer got a new card and deactivated the old one
Optimal retry strategy:
Retry schedule: Never retry โ this will trigger fraud alerts
Email customer? Yes, immediately
Likelihood of recovery: 60-65% if customer receives new card
What to tell the customer: "We can't process payments with the card ending in [last 4]. Please add your new card to keep your account active."
5. do_not_honor โ Bank Refused (No Specific Reason)
What it means: The bank declined the transaction but didn't provide a specific reason. Often related to suspected fraud.
Why it happens:
- ๐จ Fraud detection system flagged the transaction
- ๐ Unusual purchase pattern (e.g., international charge)
- ๐ Bank's internal risk rules
Optimal retry strategy:
Retry schedule: 1 day โ 3 days โ 7 days
Email customer? Yes, ask them to contact their bank
Likelihood of recovery: 30-40% (often requires customer to call bank)
What to tell the customer: "Your bank declined the charge for security reasons. Please contact your bank to authorize the payment, or use a different card."
6. incorrect_cvc โ Wrong CVV Code
What it means: The CVV (card security code) provided doesn't match the card.
Why it happens:
- ๐ข Customer typo when entering CVV
- ๐ณ Using a saved card with incorrect CVV on file
Optimal retry strategy:
Retry schedule: Don't retry โ same CVV will fail again
Email customer? Yes, ask them to re-enter card details
Likelihood of recovery: 80-85% if they re-enter correctly
What to tell the customer: "We couldn't verify your card's security code (CVV). Please re-enter your card details."
7. processing_error โ Temporary Technical Issue
What it means: A temporary error occurred while processing the payment (usually on Stripe's or the bank's side).
Why it happens:
- โก Network timeout or connectivity issue
- ๐ฆ Bank's payment system temporarily down
- ๐ง Rare Stripe infrastructure issue
Optimal retry strategy:
Retry schedule: 1 hour โ 6 hours โ 24 hours
Email customer? Only if retries fail after 24h
Likelihood of recovery: 85-90% (usually resolves on its own)
What to tell the customer: "We had a temporary technical issue processing your payment. We'll retry automatically โ no action needed."
8. incorrect_number โ Invalid Card Number
What it means: The card number provided is invalid or doesn't exist.
Why it happens:
- ๐ข Typo when entering card number
- ๐ณ Fake or test card number used
Optimal retry strategy:
Retry schedule: Never retry
Email customer? Yes, immediately
Likelihood of recovery: 75-80% if customer corrects the typo
What to tell the customer: "The card number you provided appears to be incorrect. Please double-check and re-enter your card details."
9. card_velocity_exceeded โ Too Many Charges Too Fast
What it means: The card has been used too many times in a short period, triggering velocity limits.
Why it happens:
- ๐จ Anti-fraud mechanism (too many charges in 24h)
- ๐ Multiple retry attempts in quick succession
Optimal retry strategy:
Retry schedule: Wait 24-48 hours, then retry once
Email customer? Yes, explain the situation
Likelihood of recovery: 50-60% after waiting period
What to tell the customer: "Your bank flagged this charge due to multiple recent transactions. We'll retry in 24 hours, or you can use a different payment method."
Warning
Don't retry velocity errors immediately โ you'll trigger further blocks. Wait at least 24 hours.
10. fraudulent / card_not_supported โ Fraud Block
What it means: Stripe's fraud detection system (Stripe Radar) blocked the charge as potentially fraudulent.
Why it happens:
- ๐จ High-risk transaction pattern
- ๐ Mismatch between card country and IP address
- ๐ณ Card linked to previous fraudulent activity
Optimal retry strategy:
Retry schedule: Never retry โ fraud blocks are permanent
Email customer? Yes, ask for identity verification or alternative payment
Likelihood of recovery: 20-30% (requires manual review)
What to tell the customer: "This transaction was flagged for security reasons. Please contact us to verify your identity or use a different payment method."
Quick Reference: Stripe Decline Codes Cheat Sheet
| Code | Should You Retry? | Recovery Rate |
|---|---|---|
card_declined | Yes (4h โ 1d โ 3d โ 7d) | 45-50% |
insufficient_funds | Yes (2d โ 5d โ 10d) | 60-70% |
expired_card | No โ email customer | 70-80% |
lost_card | No โ email customer | 60-65% |
do_not_honor | Yes (1d โ 3d โ 7d) | 30-40% |
incorrect_cvc | No โ email customer | 80-85% |
processing_error | Yes (1h โ 6h โ 24h) | 85-90% |
incorrect_number | No โ email customer | 75-80% |
card_velocity_exceeded | Wait 24h, then retry once | 50-60% |
fraudulent | No โ manual review | 20-30% |
How to Implement Smart Retry Logic Based on Decline Codes
Now that you know what each code means, here's how to build (or choose) a retry system that adapts to decline codes:
Option 1: Build Custom Retry Logic (Developer Route)
Use Stripe webhooks to listen for charge.failed events:
// Example webhook handler (Node.js)
stripe.webhooks.constructEvent(request.body, sig, webhookSecret);
if (event.type === 'charge.failed') {
const charge = event.data.object;
const declineCode = charge.outcome?.decline_code;
// Route to appropriate retry strategy
if (declineCode === 'insufficient_funds') {
scheduleRetry(charge.id, { days: 2 });
} else if (declineCode === 'expired_card') {
sendDunningEmail(customer, 'expired_card');
} else if (declineCode === 'processing_error') {
scheduleRetry(charge.id, { hours: 1 });
}
// ... handle other codes
}Option 2: Use a Payment Recovery Tool (No-Code Route)
Tools like Revive automatically handle decline-code-specific retry logic without any code:
- โ Reads Stripe decline codes automatically
- โ Schedules retries based on best practices for each code
- โ Sends personalized dunning emails matching the decline reason
- โ Shows recovery metrics by decline code type
Advanced: Less Common Decline Codes
Here are a few more decline codes you might encounter:
generic_declineโ Similar tocard_declined, no specific reason givencall_issuerโ Bank wants cardholder to call them (often fraud-related)pickup_cardโ Bank wants to physically retrieve the card (rare, serious fraud indicator)restricted_cardโ Card is restricted by the bank (e.g., region-locked)currency_not_supportedโ Card doesn't support the charge currencyduplicate_transactionโ Identical transaction attempted twice in short window
For a complete list, see Stripe's official decline codes documentation.
Best Practices for Handling Stripe Declines
- 1. Log every decline code โ Track which codes you see most often to identify patterns (e.g., if 50% are expired cards, prioritize Card Account Updater)
- 2. Don't retry indiscriminately โ Retrying expired cards wastes resources and annoys banks
- 3. Customize dunning emails per decline reason โ An email about an expired card should look different than one about insufficient funds
- 4. Monitor retry success rates by code โ If
insufficient_fundsretries aren't working, adjust timing - 5. Offer backup payment methods โ When a card fails repeatedly, let customers add ACH, PayPal, or other options
Automate Decline Code Handling
Revive automatically reads Stripe decline codes and applies the optimal retry strategy for each failure type โ no code required. Connect your Stripe account and start recovering more payments in 3 minutes.
Try Revive Free for 14 DaysNo credit card required โข 14-day free trial
Key Takeaways
- ๐ก Not all payment failures are equal โ each Stripe decline code requires a different strategy
- ๐ก Expired cards, lost cards, and incorrect CVVs should NOT be retried โ email the customer immediately
- ๐ก Insufficient funds failures recover best when retried around payday (1st, 15th, end of month)
- ๐ก Processing errors usually resolve on their own โ retry quickly (1h โ 6h โ 24h)
- ๐ก Generic declines (
card_declined) benefit from spaced-out retries (4h โ 1d โ 3d โ 7d) - ๐ก Track which decline codes are most common to optimize your prevention and recovery strategies
The bottom line: Smart retry logic based on decline codes can increase your payment recovery rate by 40-60%. Stop treating all failed payments the same โ adapt your strategy to the specific reason each one failed.
About Revive: We automatically handle Stripe decline codes with optimized retry schedules and personalized dunning emails. Connect your Stripe account in one click and start recovering more failed payments today.