Every failed subscription payment carries a specific decline code — and each code demands a different recovery strategy. For SaaS businesses running on Stripe, understanding these codes is the difference between silently retrying a temporary glitch and losing a customer forever. Failed payments cause 20–40% of all subscription churn, costing the industry an estimated $129 billion annually. Yet only 17% of subscription businesses actively track decline codes. This guide maps every Stripe decline code to its meaning, classification, and optimal recovery approach — with a focus on why SMS-first recovery outperforms traditional email dunning by 3–4x.
RecoverPing integrates with Stripe webhooks to detect failures in real time, classify the decline, and trigger the right recovery sequence — SMS, email, or intelligent retry — within minutes, not days.
How Stripe classifies payment failures
Stripe organizes every failed payment into exactly three categories, each surfaced through the outcome object on the Charge:
| Failure Type | outcome.type | network_status | What happened |
|---|
| Issuer declines | issuer_declined | declined_by_network | The cardholder's bank rejected the charge |
| Blocked payments | blocked | not_sent_to_network | Stripe Radar, custom rules, or Adaptive Acceptance blocked it before reaching the network |
| Invalid API calls | invalid | not_sent_to_network | Malformed request (wrong card format, missing params) |
Within issuer declines, Stripe provides an advice_code field that is the most reliable retryability signal per transaction:
try_again_later — The issuer says retry is permitted
do_not_try_again — The card should not be retried for this transaction
confirm_card_data — The card details provided are incorrect; customer must fix them
Stripe does not officially label each decline code as "soft" or "hard" in its documentation. Instead, it relies on advice_code per transaction. The soft/hard classifications in the tables below reflect industry-standard consensus from multiple payment recovery platforms and practical integration experience.
Generic declines versus specific declines
The most common — and most frustrating — code is generic_decline. This is a catch-all the issuer returns when it doesn't disclose a specific reason. It can represent anything from a temporary fraud flag to a spending limit. About 50–60% of all declines fall into this bucket, making it critical to retry these rather than treat them as permanent failures.
Specific codes like insufficient_funds or expired_card give you actionable intelligence. The recovery strategy should differ dramatically: insufficient funds is a timing problem (retry around payday), while expired card requires the customer to update their payment method.
Stripe-blocked payments versus issuer declines
When outcome.type is blocked, the charge never reached the card network. Stripe's Radar fraud system or Adaptive Acceptance engine intercepted it. The outcome.reason field reveals why:
highest_risk_level — Radar flagged the transaction as too risky
low_probability_of_authorization — Adaptive Acceptance blocked it to avoid unnecessary network decline fees
- Custom Radar rules configured by the merchant
These blocks appear as fraudulent or merchant_blacklist decline codes. Never reveal fraud-related decline reasons to the customer — always present them as a generic decline.
Every Stripe card decline code: soft vs. hard
The following is the complete list of 44+ card decline codes Stripe returns, organized by retryability. This classification drives whether you should retry silently, contact the customer, or request a new payment method.
Soft declines — temporary and retryable
These represent 80–90% of all declines. The underlying issue is often transient — insufficient funds, a temporary hold, network latency, or an overzealous issuer fraud filter.
| Decline Code | What It Means | Recovery Strategy |
|---|
insufficient_funds | Not enough money in the account | Most recoverable code (~68% recovery rate). Retry in 2–7 days, ideally around payday (1st/15th of month). If second retry fails, send SMS with payment update link. |
generic_decline | Issuer gave no specific reason | Retry once after 24 hours. If it fails again, SMS the customer — the issuer may require them to authorize the charge. |
do_not_honor | Blanket refusal from issuer | Retry after 24–48 hours. If persistent, customer must call their bank. SMS with clear instructions. |
processing_error | Temporary system error | Retry immediately or within a few hours. Usually resolves on its own. |
issuer_not_available | Card network couldn't reach issuer | Retry in 1–4 hours. Purely a connectivity issue. |
approve_with_id | Needs additional authorization | Retry; often succeeds on second attempt. |
call_issuer | Issuer wants the cardholder to call | SMS the customer immediately — they need to contact their bank before retry will work. |
card_velocity_exceeded | Hit spending/transaction limit | Customer may need to wait or call their bank. Retry in 24–48 hours. |
withdrawal_count_limit_exceeded | Balance or credit limit hit | Same as above — retry after a few days. |
reenter_transaction | Issuer asks for re-submission | Retry immediately. |
try_again_later (deprecated) | Temporary decline | Retry in a few hours. |
no_action_taken | Unknown reason | Retry; if persistent, customer contacts issuer. |
not_permitted | Payment type not allowed | Customer contacts issuer to enable this payment type. |
restricted_card | Card restricted (possibly lost/stolen flag) | Customer must contact issuer. Present as generic decline. |
security_violation | Security check failed | Customer contacts issuer. |
service_not_allowed | Card doesn't allow this service | Customer contacts issuer. |
stop_payment_order | Stop payment placed | Customer contacts issuer. |
transaction_not_allowed | Transaction type blocked | Customer contacts issuer. |
duplicate_transaction | Same charge submitted recently | Verify no duplicate — this is usually a system issue, not a customer problem. |
currency_not_supported | Card doesn't support this currency | May need alternative payment method. |
invalid_amount | Amount exceeds limit | Check with issuer about purchase limits. |
incorrect_cvc | Wrong CVC entered | SMS customer to re-enter card details. |
incorrect_zip | Wrong postal code | SMS customer to update billing address. |
incorrect_pin | Wrong PIN (in-person only) | Customer retries with correct PIN. |
invalid_cvc / invalid_pin | CVC or PIN format invalid | Customer re-enters correct info. |
invalid_expiry_month / invalid_expiry_year | Bad expiration date | Customer updates card details. |
invalid_number | Card number format invalid | Customer re-enters card. |
invalid_account | Account invalid | Customer contacts issuer. |
incorrect_address | Address mismatch | Customer updates billing address. |
card_not_supported | Card type not accepted | Customer uses different card. |
new_account_information_available | Card details changed | Card updater may resolve; otherwise customer updates. |
mobile_device_authentication_required | Needs mobile auth | Customer re-authenticates on device. |
offline_pin_required / online_or_offline_pin_required | PIN required | In-person only — customer inserts card. |
pin_try_exceeded | Too many PIN attempts | Customer uses different card. |
testmode_decline | Test card used in production | Developer error — use real card. |
do_not_try_again (deprecated) | Unknown reason | Customer contacts issuer. |
Hard declines — permanent, require new payment method
These represent 10–20% of declines. Retrying will not help. The customer must provide a new card or resolve the issue with their bank.
| Decline Code | What It Means | Recovery Strategy |
|---|
expired_card | Card has passed its expiration date | SMS immediately with a link to update their card. Stripe's card updater may auto-resolve this, but don't wait — proactive SMS recovers faster. |
lost_card | Reported lost to the bank | Present as generic decline. Customer needs a replacement card. SMS with update link. |
stolen_card | Reported stolen | Present as generic decline. Never reveal this code to the customer. SMS asking them to update payment method. |
pickup_card | Bank flagged for retrieval | Present as generic decline. Customer contacts bank. |
fraudulent | Stripe suspects fraud | Present as generic decline. Review in Radar dashboard. |
merchant_blacklist | On your Stripe block list | Present as generic decline. Review your Radar rules. |
incorrect_number | Card number is wrong | Customer must re-enter card details. |
authentication_required | 3D Secure / SCA needed | Trigger an on-session authentication flow. SMS customer with a link to complete 3DS. |
authentication_not_handled | Auth required but not performed | Must run the EMV 3DS / SCA flow. |
revocation_of_authorization | Cardholder revoked permission | Customer must re-authorize or use new card. |
revocation_of_all_authorizations | All authorizations revoked | Customer must use a completely new payment method. |
Local payment method decline codes
Stripe returns 18 additional codes for non-card payment methods (SEPA, BACS, ACH, iDEAL, etc.):
| Code | Meaning | Retryable? |
|---|
partner_generic_decline | Payment provider declined | Possibly |
invalid_customer_account | Can't charge this account | After customer fixes |
payment_limit_exceeded | Exceeds account limit | After customer adjusts |
invalid_billing_agreement | Agreement invalid | No |
compliance_violation | Violates terms/laws | No |
invalid_authorization | Authorization invalid or revoked | No |
invalid_payment_information | Bad payment data | No |
expired_payment_information | Underlying instrument expired | After customer updates |
partner_high_risk_customer | Provider flagged high risk | Unlikely |
payment_disputed | Active dispute | After resolution |
For ACH, SEPA, and BACS, Stripe maps network return codes (like ACH R01 for insufficient funds or SEPA AC04 for account closed) to its own standardized failure reasons. These bank debit methods are not retried by Smart Retries by default — you must opt in.
How decline codes surface in the Stripe API
Understanding where to find decline data in the API response is essential for building automated recovery logic. The information lives in three places: the PaymentIntent's last_payment_error, the Charge's outcome object, and the error response on a synchronous API call.
The PaymentIntent error object
When a PaymentIntent fails, the last_payment_error field contains:
{
"id": "pi_3MtwBwLkdIwHu7ix28a3tqPa",
"status": "requires_payment_method",
"last_payment_error": {
"type": "card_error",
"code": "card_declined",
"decline_code": "insufficient_funds",
"message": "Your card has insufficient funds.",
"doc_url": "https://stripe.com/docs/error-codes/card-declined"
}
}
The decline_code field (e.g., insufficient_funds) is the specific issuer reason. The code field (e.g., card_declined) is Stripe's broader error category. For your recovery logic, route on decline_code first, falling back to code.
The Charge outcome object
The Charge object (via payment_intent.latest_charge) provides deeper network-level data:
{
"outcome": {
"type": "issuer_declined",
"network_status": "declined_by_network",
"network_decline_code": "51",
"advice_code": "try_again_later",
"risk_level": "normal",
"risk_score": 24,
"reason": "insufficient_funds",
"seller_message": "The bank declined this charge."
}
}
The network_decline_code is the raw ISO 8583 code from the card network (e.g., 51 = insufficient funds on Visa/Mastercard). The advice_code is the single most reliable indicator of whether to retry. When advice_code is try_again_later, schedule a retry. When it's do_not_try_again, request a new payment method immediately.
Critical webhook events for payment recovery
Your integration should listen for these events to trigger recovery workflows:
| Webhook Event | When It Fires | Recovery Action |
|---|
invoice.payment_failed | Every failed payment attempt on an invoice | Primary trigger. Check attempt_count and decline_code. Route to retry or customer outreach. |
payment_intent.payment_failed | Any PaymentIntent failure | Access last_payment_error.decline_code for routing. |
charge.failed | A charge attempt fails | Access outcome for network-level detail. |
customer.subscription.updated | Subscription status changes | Watch for status: "past_due" to trigger escalated recovery. |
customer.subscription.deleted | Subscription canceled after all retries exhausted | Final notification — offer reactivation. |
invoice.payment_action_required | Payment needs 3DS authentication | SMS customer with authentication link immediately. |
The invoice.payment_failed event is the workhorse. It fires on every retry attempt, and the attempt_count field tells you which attempt just failed. The next_payment_attempt timestamp tells you when Stripe will try again — coordinate your SMS timing around this to avoid messaging a customer right before a successful retry.
Important behaviors: Events are not guaranteed in order. Design handlers idempotently. Stripe retries failed webhook deliveries for up to 3 days with exponential backoff.
Smart retry strategies that actually recover revenue
The data is clear: 50% of payment recovery comes from retries alone before any customer communication is needed. The other 50% requires the customer to take action — update a card, add funds, or call their bank. Getting the retry strategy right is foundational.
Stripe Smart Retries versus custom logic
Stripe's built-in Smart Retries uses a stacked ensemble ML model trained on billions of transactions across the entire Stripe network. It analyzes 500+ signals including cross-merchant payment patterns, time-of-day success rates by issuer, whether updated card data is available, and even debit-card payday patterns (e.g., debit cards in certain countries succeed more at 12:01 AM local time).
The numbers are compelling: Smart Retries recovers 57% of failed recurring payments on average and delivers $9 in revenue for every $1 spent on Stripe Billing. The recommended default configuration is 8 retries within 2 weeks.
However, Smart Retries has limitations. It won't retry hard declines until a new payment method is detected. It doesn't send customer communications. And it doesn't retry bank debit methods (ACH, SEPA, BACS) by default. This is where third-party tools like RecoverPing add value — by layering SMS outreach on top of Stripe's retry engine to recover the 50% of failures that require customer action.
When to retry silently versus contact the customer
The optimal approach separates retry logic from customer communication:
- First 1–3 attempts (Day 0–3): Retry silently. Don't email or text the customer about soft declines — many resolve automatically. A first retry succeeds 25–35% of the time.
- After 2–3 failed retries (Day 3–7): Send the first SMS. By now, the easy recoveries are done. The customer likely needs to take action.
- Day 7–14: Escalate messaging urgency. Second SMS plus email. Emphasize what they'll lose access to.
- Day 14–28: Final warnings via SMS. Clear deadline for service cancellation.
For hard declines (expired card, stolen card, authentication required), skip straight to customer outreach. Retries won't help — the customer must update their payment method. Speed matters here: PYMNTS research shows 27% of subscribers cancel immediately after receiving a payment failure notification. Reaching them in minutes via SMS, not hours via email, is the difference.
Card network retry limits
Visa allows 15 reattempts within 30 days for soft declines and zero for hard declines. Mastercard permits 10 retries within 24 hours. Exceeding these limits can result in penalties from the card networks. Stripe's Smart Retries respects these limits automatically, but custom retry logic must account for them.
The data behind payment recovery
How much revenue is actually at risk
Failed payments affect every subscription business, but the scale is often underestimated. 7.9% of all recurring transactions fail on average, reaching 14.7% in some industries. For a SaaS company with $10M ARR, that puts $790,000 in revenue at risk every year.
The breakdown of who recovers and who doesn't is stark:
| Recovery Approach | Recovery Rate |
|---|
| No dunning (passive processor retries only) | 10–20% |
| Single retry attempt | 23% |
| Automated email dunning (fixed schedule) | 40–60% |
| Smart/ML-powered retries | 57–68% |
| AI-powered multi-channel (retries + email + SMS) | 70–85% |
B2B SaaS companies recover at higher rates (53.5%) than B2C (34.6%), likely because higher contract values justify more aggressive recovery and because business customers have stronger intent to maintain service. The median recovery across all subscription businesses is 47–53%, meaning roughly half of failed payments go unrecovered with standard approaches.
Recovery rates by decline type
Not all declines are equally recoverable. Insufficient funds has the highest recovery rate at ~68% — it's fundamentally a timing problem. Generic declines recover well within short timeframes. Fraud and call-issuer codes have the lowest recovery rates and longest resolution times.
Recovered subscribers aren't just a one-time win. They continue paying for an average of 7 additional months after recovery, with 38% of their total customer lifetime occurring post-recovery. This makes every recovered payment worth far more than its face value.
The ROI of systematic recovery
Top-performing subscription businesses recover ~61% of failed payments and use an average of 3.1 recovery methods (retries + email + SMS + in-app). They are 12x more likely to use dedicated third-party recovery tools. The ROI is consistently 10–15x for effective dunning systems, with some platforms reporting 67x returns for individual customers.
Why SMS-first recovery outperforms email dunning
The channel you use to reach customers about failed payments matters enormously. The data overwhelmingly favors SMS as the primary recovery channel.
The engagement gap is massive
| Metric | SMS | Email |
|---|
| Open rate | 98% | 20–30% |
| Time to read | 90 seconds | 90 minutes |
| Click-through rate | 19–20% | 0.8–4.4% |
| Response rate | 45% | 10% |
95% of SMS messages are read within 3 minutes of delivery. Early pilot data from Churnkey's SMS Payment Recovery feature showed 3–4x more recoveries from SMS compared to equivalent email campaigns. Pairing email with SMS increases recovery rates by an additional 15–20%.
Beyond engagement, SMS solves a critical problem that plagues email dunning: deliverability. Nearly half of dunning email senders report spam filtering as their top challenge. Payment failure emails from automated systems routinely land in promotions tabs or spam folders. SMS bypasses this entirely — there is no spam folder for text messages.
The speed advantage compounds
The first hours after a payment failure are the most critical window for recovery. Baremetrics data shows that Day 0 communications achieve a 13.25% recovery rate — the highest of any touchpoint. That rate decays steadily: by Day 30, it drops to 4.2%. SMS delivers the notification in seconds versus hours for email, compressing the entire recovery timeline.
For a payment declined due to insufficient funds, the customer may have the money the same day — they just need to know the charge failed. An SMS at 10 AM gets acted on by noon. An email sent at 10 AM might not be opened until the next day, by which time the customer may have spent those funds elsewhere.
The optimal multi-channel sequence
SMS works best as the primary channel with email as reinforcement:
| Stage | Timing | Channel | Message Tone |
|---|
| Immediate alert | Day 0 (within minutes) | SMS | Friendly, factual: "Your payment didn't go through" |
| First reminder | Day 3 | SMS | Helpful: one-tap link to update card |
| Follow-up | Day 7 | Email + SMS | Slightly more urgent |
| Escalation | Day 14 | SMS | "Your access will be paused" |
| Final notice | Day 21–28 | Email + SMS | Clear deadline, loss framing |
Pre-dunning is also powerful: sending an SMS before a card expires achieves a 47% open rate and 14.4% recovery rate — higher than even Day 0 post-failure messages.
TCPA compliance for SMS payment recovery
Sending automated SMS for payment recovery in the US requires careful compliance with the Telephone Consumer Protection Act (TCPA), state-level regulations, and carrier requirements. The good news: payment failure notifications occupy a legally favorable position.
Payment failure SMS qualifies as transactional
Failed payment notifications are generally classified as transactional/informational messages — not marketing. This is a significant compliance advantage. Transactional messages require only prior express consent (PEC), which can be obtained through a customer providing their phone number during signup. Marketing messages require the stricter prior express written consent (PEWC) with an explicit signature.
The critical caveat: this classification holds only if the message contains zero promotional content. Adding "Upgrade to annual billing for 20% off" or "Check out our new features" instantly reclassifies the entire message as marketing, triggering the higher consent standard. Every payment recovery SMS must be purely informational.
Core compliance requirements
Consent: When a customer provides their phone number during Stripe subscription signup, this can constitute implied consent for transactional SMS. Best practice is to include explicit language at checkout: "By providing your phone number, you consent to receive account-related text messages including payment notifications. Message and data rates may apply. Reply STOP to opt out."
Opt-out handling: Every SMS must include opt-out instructions. As of April 2025, the FCC requires businesses to accept consent revocation "in any reasonable manner" — not just the keyword STOP. Natural language opt-outs like "please stop texting me" must be honored within 10 business days (immediately is best practice).
Time-of-day restrictions: Federal TCPA allows messages between 8 AM and 9 PM in the recipient's local time. Florida and several other states restrict this further to 8 AM–8 PM. Apply the most restrictive standard (8 AM–8 PM) when the recipient's state is uncertain.
10DLC registration: As of February 2025, all US carriers block unregistered A2P 10DLC traffic. Every business sending SMS through RecoverPing must register their brand and campaign with The Campaign Registry (TCR) through the SMS provider (Twilio). Register campaigns under "Account Notifications" or "Customer Care" — not "Marketing."
State-level considerations
Florida (FTSA) imposes the strictest rules: maximum 3 contact attempts per 24 hours, 8 AM–8 PM quiet hours, and a private right of action with $500–$1,500 per violation. California requires CCPA privacy disclosures. Connecticut restricts hours to 9 AM–8 PM. TCPA litigation surged 95% in 2025, with Florida, California, and Texas as the highest-risk jurisdictions.
The safest approach: treat all payment recovery SMS as requiring explicit consent, never include promotional content, apply the most restrictive state rules universally, and maintain a comprehensive audit trail of consent (timestamp, method, exact language shown) for at least 4 years.
Where RecoverPing fits in the competitive landscape
The payment recovery space includes several established players, each with a distinct approach — and a shared blind spot around SMS.
Churn Buster (premium, strategic-partnership model) separates retries from customer communication and offers SMS as an optional secondary channel. Strong thought leadership content but no comprehensive decline code reference. Baremetrics Recover (email-only dunning add-on to their analytics platform) publishes dunning email guides but offers no SMS capability. Gravy Solutions ($997–$8,000/month) uses human agents who manually text and email customers — effective but expensive and inaccessible to SMBs. Paddle Retain (formerly ProfitWell Retain) uses algorithmic retries and email but requires Paddle platform lock-in. Churnkey is the closest competitor on SMS, recently launching SMS recovery with early results showing 3–4x more recoveries than email, but positions SMS as an add-on to their multi-product retention platform rather than a primary channel.
The content gap RecoverPing can own
No competitor has published a comprehensive Stripe decline code guide paired with SMS-specific recovery strategies. Churnkey publishes individual decline code explainer posts, but no one maps every code to an SMS recovery action with message templates. This represents a major SEO opportunity: developers and SaaS operators actively search for "[decline code] + how to fix" queries.
The decline-code-to-SMS-template approach is particularly powerful. For example:
insufficient_funds: "Hi [Name], your $[amount] payment for [Product] didn't go through — looks like a temporary issue. We'll retry in a few days, or you can update your card here: [link]. Reply STOP to opt out."
expired_card: "Hi [Name], your card ending in [last4] has expired. Update it in 10 seconds to keep your [Product] subscription active: [link]. Reply STOP to opt out."
authentication_required: "Hi [Name], your bank needs you to verify your $[amount] payment for [Product]. Complete verification here: [link]. Reply STOP to opt out."
No true SMS-first player exists in this market. Every competitor treats SMS as secondary to email. RecoverPing can own the "recover in minutes, not weeks" narrative backed by the 98% open rate data and the 3–4x recovery multiplier. The underserved $5K–$200K MRR segment — too small for Gravy's human agents or Churnkey's mid-market pricing — is where transparent, affordable SMS-first recovery can win.
Conclusion: building a decline-code-aware recovery engine
The most effective payment recovery systems treat decline codes as routing logic, not just error messages. A insufficient_funds decline on Day 1 should trigger a silent retry schedule aligned with paydays. An expired_card should fire an immediate SMS with a one-tap card update link. An authentication_required should push a 3DS verification link within minutes.
Three insights stand out from this research. First, the advice_code field (try_again_later, do_not_try_again, confirm_card_data) is more reliable than any static soft/hard classification — use it as your primary routing signal. Second, the first 5 minutes after a decline are the highest-leverage window for recovery, and SMS is the only channel fast enough to exploit it. Third, the 50/50 split — half of recoveries come from retries, half from customer action — means that Smart Retries alone will always leave half of recoverable revenue on the table. The customer communication layer is not optional; it's where the remaining revenue lives.
For RecoverPing, the strategic play is clear: own the intersection of Stripe decline code intelligence and SMS-first outreach. No competitor occupies this position today. The data supports it, the compliance framework permits it, and the $129 billion involuntary churn problem demands it.