Not every failed subscription charge is the same kind of failure. A soft decline is a temporary problem — the card is fine, but this particular attempt did not clear — while a hard decline is a permanent problem with the card itself. Treat them the same way and you either waste retry attempts on a card that will never work, or you hassle a customer about a glitch that would have quietly resolved on its own. Get the split right and recovery gets meaningfully easier on both sides.
Every payment recovery decision — retry now, retry later, or stop retrying and ask the customer to act — ultimately comes down to correctly answering one question about a failed charge: is the problem the timing, or is the problem the card? A soft decline says the timing was wrong. A hard decline says the card itself needs to change. This is a different question from "what does this specific decline code mean," which we cover exhaustively in our Stripe decline codes glossary — this guide is about the higher-level framework: how to classify any decline into one of the two buckets, and exactly what to do once you have.
Get this classification wrong in either direction and it costs you. Keep retrying a hard decline and you delay the moment a customer with a genuinely dead card finds out, sometimes long enough that they simply drift into cancellation without ever seeing an actionable message. Email a customer immediately over a soft decline that would have cleared on the next automatic retry, and you come across as nagging over something that was never really a problem — the kind of friction that erodes trust with an otherwise happy subscriber.
Key takeaways
- Soft decline = temporary, card is fine, the same charge will likely succeed on a later retry (insufficient_funds, processing_error, issuer_not_available).
- Hard decline = permanent, the card itself is the problem, retrying is pointless (expired_card, lost_card, stolen_card, restricted_card).
- Soft declines call for smart, timed retries; hard declines call for an immediate, specific ask for a new card — never the other way around.
- A few codes, most notably
do_not_honor, sit in an ambiguous middle and need a hybrid rule: retry once or twice, then treat continued failure as hard. - Revova’s Pro plan reads the decline code automatically and routes soft versus hard declines to different email copy — no manual rule-building required.
What is a soft decline?
A soft decline is a failed charge where the card itself is valid and in good standing, but this specific attempt did not go through for a reason that is likely to change on its own — often within days, sometimes within hours. Nothing about the card needs to be fixed; the problem is closer to bad timing than a bad card.
The most common causes behind a soft decline include:
- Insufficient funds. The account is temporarily low, most often right before a paycheck or deposit lands — a charge retried a few days later, near a typical payday window, frequently succeeds with zero customer effort.
- A temporary processing or network error. Something glitched between the processor and the issuing bank for a moment; the card was never actually the issue.
- The issuer was briefly unreachable. The customer’s bank could not be contacted to authorize the charge at that exact moment — a connectivity problem, not a card problem.
- A temporary risk hold or velocity block. Some banks briefly restrict a card after unusual activity or too many attempts in a short window, then lift the hold automatically once the pattern cools off.
The defining feature of every soft decline is that retrying the exact same card, at a better moment, has a real chance of working — which is exactly what Stripe Smart Retries and equivalent features on other processors are built to exploit. If you have not already, our guide to how Stripe Smart Retries works covers how that timing decision gets made without any code on your end.
What is a hard decline?
A hard decline is a failed charge where the card itself is the problem, permanently, for this transaction and every future one until the customer replaces it. No amount of retrying, no matter how well-timed, changes anything, because the failure has nothing to do with available balance or momentary bank conditions.
The most common causes behind a hard decline include:
- An expired card. The printed expiration date has passed — the single most common hard decline for subscription businesses, since it happens to every card eventually.
- A lost or stolen card. The cardholder reported the card lost or stolen, so the issuer has permanently deactivated it.
- A closed or restricted account. The bank account behind the card was closed, or the issuer placed a restriction that blocks this kind of charge outright, independent of balance.
- A fraud-pattern block. Codes like
do_not_honorcan sometimes reflect a bank-side fraud flag against the card or merchant that will not lift for that specific transaction pattern, effectively making it terminal even without an explicit "stolen" label.
The defining feature of every hard decline is that the customer must provide new payment details before the subscription can be charged successfully again — retrying only burns an attempt and delays the moment they actually see the problem and fix it.
Why the distinction actually matters
It is tempting to treat every failed charge as one undifferentiated problem — "a payment failed, send an email" — but that flattens two situations that call for opposite responses. Involuntary churn, where a subscription lapses because a payment failed rather than because the customer chose to leave, commonly makes up 20–40% of total SaaS churn. A large share of that is preventable, but only if the response matches the failure type. For the broader picture of how failed payments turn into churn if nothing intervenes, see our guide on what dunning is and how the whole recovery stack fits together.
Getting the classification wrong costs you in two distinct ways, depending on which direction you get it wrong:
- Retrying a hard decline repeatedly. Every attempt against an expired, lost, or stolen card is guaranteed to fail. Beyond wasting the attempt, it delays the one thing that actually fixes the problem — telling the customer, clearly, that their card needs to change — sometimes long enough that they quietly lapse before ever getting a useful message.
- Emailing immediately over a soft decline. If a customer gets a slightly alarming "your payment failed, please update your card" email over an insufficient-funds blip that a retry would have cleared two days later on its own, you have manufactured friction and mild anxiety out of a non-event — and repeat it enough times and it reads as a badly built product.
Failed or declined subscription charges commonly run 5–10% per billing cycle industry-wide — a meaningful share of monthly revenue moving through a process that either recovers cleanly or leaks slowly, largely depending on whether the soft/hard split is handled correctly at each step.
Common decline codes, classified: soft vs hard
Here is a practical reference for the codes you will see most often on Stripe (the same underlying concepts apply, with different code names, on Paddle, Braintree, Chargebee, and Recurly). For the exhaustive glossary with every code Stripe documents, see our full decline codes explainer — this table is the condensed soft-vs-hard cheat sheet.
| Code | Type | What it means | Retry? |
|---|---|---|---|
| insufficient_funds | Soft | Account temporarily short on funds | Yes — near payday |
| try_again_later | Soft | Bank asked to retry, no specific reason | Yes — after a delay |
| processing_error | Soft | Temporary network/processor glitch | Yes — shortly after |
| issuer_not_available | Soft | Bank unreachable at that moment | Yes — a bit later |
| expired_card | Hard | Past its printed expiration date | No — new card |
| lost_card | Hard | Reported lost by the cardholder | No — new card |
| stolen_card | Hard | Reported stolen by the cardholder | No — new card |
| restricted_card | Hard | Issuer-side restriction on this card | No — new card |
| card_not_supported | Hard | Card/transaction type not supported | No — new card |
| do_not_honor | Ambiguous | Generic bank refusal, no reason given | Once or twice, then escalate |
Notice how thin the soft column is compared with the hard column above — that is a function of which codes are common enough to be worth naming individually, not a claim about the overall share of declines that are soft versus hard. Soft failures like insufficient funds are generally considered common in day-to-day billing, and hard failures like an expired card eventually happen to nearly every customer relationship that runs long enough — but we are not aware of a single authoritative published ratio splitting all declines into soft versus hard across the industry, so we deliberately won't invent one here. The mix varies significantly by industry, price point, and customer base.
Soft decline codes, in detail
The card is valid in every one of these — the charge simply hit a passing condition that a later, well-timed attempt is likely to clear:
insufficient_fundsSoft · retryThe account does not currently have enough available balance to cover the charge — the card itself is perfectly valid.
What to do: Let the retry logic re-attempt over the coming days, ideally timed near a typical payday window.
try_again_laterSoft · retryThe issuing bank asked for the transaction to be retried later, without giving a more specific reason.
What to do: Retry after a delay. Avoid firing several attempts back-to-back in a short window.
processing_errorSoft · retryA temporary error occurred somewhere in the processing chain — the network, the processor, or the issuer — unrelated to the card itself.
What to do: Retry shortly. If it recurs across many unrelated customers at once, check for a broader processor incident before assuming it is card-specific.
issuer_not_availableSoft · retryThe card network could not reach the customer’s bank to authorize the charge at that moment.
What to do: Retry a bit later once the issuer is reachable again — this is a connectivity problem, not a card problem.
Hard decline codes, in detail
None of these resolve with time. Retrying wastes an attempt and, on some processors, repeated attempts against a flagged or closed card can draw unwanted scrutiny toward your account with the card networks:
expired_cardHard · needs new cardThe card on file has passed its printed expiration date.
What to do: Never retry the same card — email the customer to add a current one.
lost_cardHard · needs new cardThe cardholder reported this card lost. Some processors mask this behind a more generic decline to avoid signaling to a potential fraudster why it failed.
What to do: Do not retry under any circumstances — request a new payment method immediately.
stolen_cardHard · needs new cardThe cardholder reported this card stolen — functionally identical in outcome to lost_card.
What to do: Do not retry — request a new card and treat it with the same urgency as an expired one.
restricted_cardHard · needs new cardThe issuer has placed a restriction on the card that blocks this type of transaction outright, independent of available balance.
What to do: Do not retry — the restriction will not lift itself; ask for a different card.
card_not_supportedHard · needs new cardThe card, or the specific transaction type, is not supported by the issuer for this kind of charge.
What to do: Do not retry the same card — ask the customer for a different one.
The ambiguous middle: do_not_honor
do_not_honoris a bank's generic, unexplained refusal — no specific reason given — and it does not sort cleanly into either bucket. Sometimes it clears on a retry a day or two later, behaving like a soft decline. Sometimes it reflects a standing block the bank will never lift for that transaction pattern, behaving like a hard decline. The practical rule: treat it as soft for one, maybe two retries. If it keeps failing after that, stop retrying and treat it exactly like a hard decline — ask the customer to try a different card or contact their bank directly.
The decision framework: retry, or ask for a new card?
Once a decline lands, resist the urge to decide case by case from a support inbox — the whole point of the soft/hard split is that it turns a judgment call into a lookup you can automate. Reduced to its simplest form, every decline routes through the same three questions:
- Is the decline code soft? Let an automated retry system re-attempt it on a well-timed schedule — no customer message needed yet.
- Is the decline code hard? Skip retries entirely. Send a direct, specific email or SMS asking for a new card, today.
- Is the decline code ambiguous (do_not_honor, generic decline)? Allow one or two retries as a safety net, then treat any continued failure as hard.
Building this correctly into a live billing system is less about the classification itself — which is a lookup — and more about prioritizing which parts of your current setup to fix first. For most teams that have never split soft from hard, the highest-leverage change is routing authentication and clearly-hard codes to an immediate, specific email, since that is where silent retries are actively costing lapsed customers who were never going to be recovered by waiting:
Two response strategies, compared
In practice, most of the recovery-strategy debate collapses into a choice between two postures: recover quietly through retries first, or reach out to the customer right away. Neither is universally right — the correct posture depends entirely on which decline type you are looking at.
✓ Pros
- +No customer-facing friction at all if the retry succeeds — the subscription simply continues uninterrupted.
- +Matches how insufficient_funds and other soft declines actually resolve: given a few days, the card often just works.
- +Zero risk of nagging a customer over something that was never really broken.
✕ Cons
- –Wasted entirely on hard declines — waiting for a retry that structurally cannot succeed just delays the fix.
- –Needs a real timing strategy (like payday-aware Smart Retries) or it degrades into blind, low-value re-attempts.
- –Silent by design, so if the retry window runs out with no recovery, the customer never got a heads-up unless something else told them.
Approach: retry silently first, escalate to email only if it keeps failing — the right default for soft declines.
✓ Pros
- +Gets the actual fix in front of the customer immediately, instead of losing days to a retry that was never going to work.
- +Lets the message be specific — "your card ending in 4242 has expired" — which converts far better than a vague, generic prompt.
- +Signals competence: customers generally respond well to a business that clearly knows what went wrong with their payment.
✕ Cons
- –Wasted, and mildly annoying, if fired on a soft decline that would have cleared on its own within a day or two.
- –Requires reliably reading the decline code correctly — a misclassified soft decline treated as hard creates unnecessary friction.
- –Needs a genuinely well-written, non-alarming template, or it can read as pushy for what is, from the customer’s side, a minor blip.
Approach: email immediately, no retry attempted first — the right default for hard declines, and the wrong default for soft ones.
Building the split into your dunning sequence
Classification only pays off once it changes what the customer actually receives. A dunning sequence that sends the identical email regardless of decline type is treating soft and hard declines the same in the one place it matters most — the customer-facing message. Our guide to setting up a dunning email sequence walks through the day-by-day cadence in full; the soft/hard split changes two things within it:
- Tone and urgency. A soft-decline email can be light — reassuring the customer that a retry is already in motion, with an easy option to update their card if they would rather not wait. A hard-decline email needs to be direct from the first line, since there is no silent retry quietly working in the background to soften the ask.
- Specificity. Hard-decline emails convert better when they name the exact reason — expired, lost, or restricted — rather than a generic "there was a problem with your payment." Soft-decline emails can stay vaguer, since the precise cause (a momentary balance issue) is rarely something the customer needs spelled out.
The timing matters too. Layering a decline-reason-aware dunning sequence on top of automatic retries is commonly what pushes combined recovery into the 40–60% range industry-wide, well above what retries alone typically achieve. Dunning emails themselves commonly see open rates around 30–40% and click rates around 10–15% — figures that generally hold up better when the message actually matches the failure the customer is experiencing, rather than reading as a generic template fired at every decline alike.
Soft and hard declines beyond Stripe
The soft-versus-hard framework is not a Stripe-specific mechanic — it reflects how card networks and issuing banks respond to charges everywhere, so the same underlying split shows up on every major processor Revova supports: Paddle, Braintree, Chargebee, and Recurly, in addition to Stripe. What changes from one processor to the next is the exact vocabulary and the retry defaults, not the concept itself.
- Paddle exposes its own decline reasons through its checkout and subscription events, and runs its own configurable retry schedule for failed renewals rather than Stripe’s specific Smart Retries model.
- Braintree surfaces processor response codes from the underlying gateway (often Visa/Mastercard-style codes depending on region and card network), which need their own soft/hard mapping rather than reusing Stripe’s exact code names.
- Chargebee and Recurly, as subscription management layers sitting on top of a processor, typically pass through a decline reason from the underlying gateway along with their own dunning and retry configuration.
If your business runs more than one processor at once — common for companies selling in multiple regions or migrating between platforms — the practical implication is that a soft/hard mapping tuned for Stripe’s codes will not automatically transfer. Each processor’s decline vocabulary needs to be classified on its own terms, which is exactly the kind of cross-processor consistency problem a tool with native, read-only connections to all of them is built to absorb rather than leaving it to a hand-maintained rule per platform.
Common mistakes teams make with soft and hard declines
- Retrying every decline on a fixed schedule, regardless of code. A blind daily retry burns attempts on hard declines that will never clear and can undershoot the ideal payday timing on soft ones.
- Sending one generic "payment failed" email for every failure. It underserves hard declines (too vague to convert well) and overserves soft ones (unnecessary alarm over something self-resolving).
- Treating do_not_honor as permanently hard from the first failure. That forfeits the real chance it clears on a quick retry, since the code alone does not distinguish the two cases.
- Never revisiting the classification as processors update their own retry logic. A code that behaved one way a year ago may be handled differently by your processor’s own automatic retry system today.
- Ignoring the difference across processors. If you run more than one of Stripe, Paddle, Braintree, Chargebee, or Recurly, each has its own vocabulary and retry defaults — a rule tuned for Stripe’s codes will not automatically translate.
How Revova handles soft vs hard declines
Revova connects, read-only, to Stripe, Paddle, Braintree, Chargebee, and Recurly — it never touches raw card data — and reads the decline code on every failed charge as part of building its recovery sequence. On the Pro plan ($79/month), that reading directly drives smart soft/hard routing: soft declines feed into the retry-aware side of the 5-email AI sequence (Day 1/3/7/14/21) with lighter, reassuring copy, while hard declines trigger a direct, specific ask for a new card without waiting on a retry that structurally cannot succeed. Pro also adds SMS recovery, 8 languages, an in-app cancel-flow with retention offers, and Day 3/14/30 win-back campaigns for subscriptions that lapse anyway.
The Starter plan ($29/month) runs the same core 4-email AI sequence (Day 1/3/7/14) for up to 50 recoveries a month, without the automatic soft/hard routing — a solid default for smaller volumes, with room to grow into Pro as decline volume and the value of precise routing both increase. Both plans include the free Lost Revenue Finder, which scans your payment history (90 days on Starter, a full 12 months on Pro) to surface what has already been lost to failed charges before you ever send a recovery email. For the scale of what that history typically reveals, see our guide on how much revenue is commonly lost to failed payments.
Both plans ship with a 14-day free trial, no credit card required, and a 30-day money-back guarantee. Stripe documents its own decline reasons in full in its decline codes reference, which is the authoritative source for the exact wording and network status behind each code; our Stripe decline codes explained guide translates that reference into plain language with recovery actions for each one.
Frequently asked questions
What is the simplest way to tell a soft decline from a hard decline?
Ask one question: if I charge the exact same card again in a few days, is there a real chance it works? If yes — the account might just be low on funds right now, or the bank had a temporary hiccup — it is a soft decline and worth retrying. If the answer is no because the card itself is expired, closed, lost, stolen, or blocked, it is a hard decline, and no amount of retrying changes that. The card, not the timing, is the problem.
Is "soft decline" and "hard decline" official Stripe or card-network terminology?
No. Stripe and the card networks publish specific decline reasons and decline codes (insufficient_funds, expired_card, do_not_honor, and so on), but "soft" and "hard" are an industry-common shorthand that payment recovery and dunning tools use to group those codes by whether retrying makes sense. You will see the same soft/hard framing used by most subscription billing platforms, but treat it as a practical mental model layered on top of the processor’s own codes, not a category Stripe itself assigns on the charge.
Should I ever retry a hard decline, even once?
Generally no. A hard decline like expired_card, lost_card, stolen_card, or restricted_card describes a permanent state of that specific card — it did not expire a little, or get reported stolen only sometimes. Retrying wastes a processing attempt, delays the moment the customer actually fixes the problem, and on some processors repeated retries against a flagged card can quietly hurt your account’s standing with the networks. The one narrow exception is a generically-worded code like do_not_honor, which behaves more like an ambiguous middle case than a clean hard decline — see the section on that below.
How many times should a soft decline be retried before switching to an email?
There is no single universal number, which is exactly why most teams lean on an automated system — like Stripe Smart Retries or a dedicated recovery tool — rather than picking a fixed count by hand. A common pattern is a handful of attempts spread across one to three weeks, timed around when the customer is statistically more likely to have funds available (often near typical paydays), with a dunning email running in parallel rather than only after retries are exhausted.
What should the recovery email say differently for a soft decline versus a hard decline?
A soft-decline email can afford to be light and reassuring, since the system is often already quietly retrying in the background — something like "your last payment didn’t go through, we’ll try again automatically, but you’re welcome to update your card now if you’d like." A hard-decline email needs to be direct and specific about the actual problem — "your card ending in 4242 has expired" — with one clear action and no vague promise that the same card will eventually work, because it will not.
Does Stripe Smart Retries already know the difference between soft and hard declines?
Yes, functionally. Smart Retries uses a machine learning model trained across Stripe’s network to decide which charges are worth re-attempting and when, which in practice means it is far less likely to keep retrying a charge with a clearly permanent decline reason than one with a temporary one. But Smart Retries only handles the retry side — it never emails the customer, so even when it correctly identifies a hard decline as not worth retrying further, something else still has to tell the customer to fix their card.
What is a decline code that behaves like both soft and hard depending on the situation?
do_not_honor is the classic example. It is a catch-all decline a bank issues without specifying a reason, so it sometimes clears on its own within a day or two (behaving like a soft decline) and sometimes represents a persistent, effectively permanent block the bank will never lift for that transaction pattern (behaving like a hard decline). The practical answer is to treat it as soft for one or two retries, then treat continued failures as hard and move straight to asking for a new card.
Do soft and hard declines matter for processors other than Stripe?
Yes — the underlying concept applies to Paddle, Braintree, Chargebee, Recurly, and effectively any card processor, because it reflects how banks and card networks respond to charges everywhere, not a Stripe-specific mechanic. Each processor has its own vocabulary and its own retry logic, so the exact code names differ, but the same soft-versus-hard split, and the same "retry versus ask for a new card" decision, holds regardless of which processor is running the charge.
What happens if I treat every decline the same way, without splitting soft from hard?
You lose recovered revenue on both ends. Retry every decline blindly and you burn attempts on cards that will never work, delaying the moment a customer with a genuinely dead card finds out and fixes it — sometimes long enough that they simply churn instead. Email every decline immediately and you nag customers over glitches that would have quietly resolved on their own, which reads as sloppy and can push otherwise-happy subscribers to cancel out of irritation rather than a real payment problem.
How does Revova decide whether to retry or email a customer?
On the Pro plan, Revova reads the decline code returned by your processor and automatically routes it — soft declines get folded into the retry-aware side of the AI email sequence with lighter, reassuring copy, while hard declines trigger a direct, specific message asking for a new card right away, without waiting on a retry that was never going to succeed. Starter runs the same core 4-email sequence without that automatic soft/hard routing.
Stop treating every decline the same way
Revova reads the decline code on every failed charge and routes soft versus hard declines to the right recovery action automatically on Pro — retry-aware copy for the temporary ones, an immediate new-card ask for the permanent ones. Start free and see what's already recoverable in your last 90 days.
Start my 14-day free trial →No credit card · Free Lost Revenue scan · 30-day money-back guarantee




