Technical Reference
February 5, 2026ยท15 min read

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_code field)

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

CodeShould You Retry?Recovery Rate
card_declinedYes (4h โ†’ 1d โ†’ 3d โ†’ 7d)45-50%
insufficient_fundsYes (2d โ†’ 5d โ†’ 10d)60-70%
expired_cardNo โ€” email customer70-80%
lost_cardNo โ€” email customer60-65%
do_not_honorYes (1d โ†’ 3d โ†’ 7d)30-40%
incorrect_cvcNo โ€” email customer80-85%
processing_errorYes (1h โ†’ 6h โ†’ 24h)85-90%
incorrect_numberNo โ€” email customer75-80%
card_velocity_exceededWait 24h, then retry once50-60%
fraudulentNo โ€” manual review20-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 to card_declined, no specific reason given
  • call_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 currency
  • duplicate_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. 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. 2. Don't retry indiscriminately โ€” Retrying expired cards wastes resources and annoys banks
  3. 3. Customize dunning emails per decline reason โ€” An email about an expired card should look different than one about insufficient funds
  4. 4. Monitor retry success rates by code โ€” If insufficient_funds retries aren't working, adjust timing
  5. 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 Days

No 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.