Your Customer Has Two Cards on File. Stripe's Smart Retries Only Ever Tries One of Them.
Stripe Billing retries a failed invoice against exactly one saved payment method, no matter how many a customer has on file. Here's the fallback logic that isn't built in.
Ask most SaaS teams what happens when a subscriber's payment fails and they have a second card on file, and you'll get a confident wrong answer: "Stripe tries the other one." It doesn't. Stripe Billing's retry logic, Smart or custom, is built to keep hammering on exactly one payment method until you tell it to look somewhere else. If your customer has a backup Visa sitting in their Stripe customer object right now, unused, that's not an oversight on their end. It's the default behavior working as documented.
This isn't a bug or an edge case Stripe forgot to handle. It's a deliberate design choice, and once you understand the priority order it uses, the fix is a straightforward webhook — but almost nobody builds it, because almost nobody realizes it's missing.
What Smart Retries actually retries against
When an invoice payment fails and a retry comes due, Stripe doesn't scan every payment method attached to the customer and pick the most promising one. It checks a fixed, four-level priority list and uses the first field that has a value:
| Priority | Field | Scope |
|---|---|---|
| 1 | subscription.default_payment_method | This specific subscription |
| 2 | subscription.default_source | This specific subscription (legacy) |
| 3 | customer.invoice_settings.default_payment_method | The whole customer, all subscriptions |
| 4 | customer.default_source | The whole customer, all subscriptions (legacy) |
Every retry, Smart or custom, walks this list top to bottom and stops at the first field that's set. A customer can have four cards attached to their Stripe customer object and it changes nothing — only the card sitting in whichever field wins the priority check gets charged. The other three are inert data, visible in the Dashboard, invisible to the retry engine.
The trap: fixing the wrong field
This is where most "we already handled it" support tickets go quietly wrong. A support agent sees a failed payment, asks the customer for a new card, and updates it — often through a flow that writes to customer.invoice_settings.default_payment_method, because that's the field most billing-portal integrations touch by default. If the subscription itself already has its own default_payment_method set — which happens automatically once a customer has successfully paid an invoice with save_default_payment_method enabled — Stripe's own documentation is explicit about what happens next: it keeps retrying the subscription-level field and ignores the customer-level update entirely.
The result is a subscriber who was told their payment is fixed, watching the same card fail a second and third time. By the time anyone traces it back to a field mismatch, the subscription has usually already hit the end of its retry window. This single mismatch — update the wrong object, retry the wrong card — is a quiet, mechanical cause sitting underneath cancellations that get logged as "customer gave up," when the actual failure was a webhook writing to the wrong path.
Hard declines don't change this either
You might assume a hard decline — lost_card, stolen_card, revocation_of_authorization — is exactly when Stripe would reach for a backup card automatically, since it already knows the current one is dead. It doesn't. Per Stripe's documentation, scheduled retries keep incrementing attempt_count in the background, but "retries only execute after detecting a new payment method" — and detecting one means you've updated the priority field yourself. Stripe waits. It doesn't go looking. If a customer's second card is sitting attached and untouched, a hard decline on the first card will sit unresolved indefinitely, generating zero charges and zero further signal, until you intervene.
Illustrative — decline-reason shares from our Stripe dunning guide (insufficient funds, expired card, lost/stolen ≈ card-specific; do-not-honor, fraud blocks, restricted card ≈ issuer or account-level) mapped by whether a second card, potentially on a different bank, would plausibly avoid the same failure. Exact splits vary by customer base and card mix.
The split matters for expectations: a backup card is not a universal fix. A fraud team that's flagged the customer's identity, not just one card number, can decline a second card from the same person just as readily as the first. But for the larger bucket — a card that's simply expired, been replaced, or is temporarily out of funds while a second card on a different account is fine — a fallback that Stripe won't build for you is sitting there unused on every customer who bothered to add a second card.
Building the fallback yourself
None of this requires a third-party recovery tool. It's a webhook handler and two Stripe API calls.
1. Collect a genuine second payment method
Prompt for a backup card somewhere low-friction — the billing portal, a post-signup nudge, or right after a first successful payment when the customer is already primed to trust you with a card number. Use a SetupIntent so the card is verified and reusable off-session, and store its PaymentMethod ID against the customer in your own database, separate from whatever Stripe considers the "default." Don't rely on Stripe's own default fields to track which card is the backup — you need to know that yourself before you can promote it.
2. Listen for the right moment on invoice.payment_failed
On each invoice.payment_failed event, read decline_code and attempt_count. Two triggers are worth acting on immediately rather than waiting out the retry window: a Category 1 hard decline (covered in more depth in our guide to decline code retry limits), where you already know the current card is permanently dead, and a soft decline that's failed two or three consecutive attempts, where the odds a fourth try on the same card succeeds are dropping fast.
3. Promote the backup and re-trigger collection
Update subscription.default_payment_method — not customer.invoice_settings.default_payment_method, unless you've confirmed the subscription doesn't already have its own field set — to the backup card's PaymentMethod ID. From there, either let the next scheduled Smart Retry pick up the new default automatically, or force an immediate attempt by voiding the failed invoice's draft state and creating a fresh one against the updated subscription. The second option recovers revenue days sooner than waiting for the existing retry schedule, which is often the entire point of having a backup card in the first place.
4. Swap it back once the primary card is fixed
If card account updater later refreshes the original card, or the customer manually updates it, decide whether to keep billing the backup or restore the original as primary. Most teams leave whichever card successfully cleared the most recent invoice in place rather than forcing a switch back — it's one fewer thing that can silently break.
How Stripe's approach compares to a platform that ships this natively
Stripe isn't the only subscription platform handling this differently. Recurly sells backup payment method as a native, toggleable feature: when a primary payment method declines, Recurly switches to a stored backup automatically, without a merchant-built webhook in between.
| Behavior | Stripe Billing | Recurly |
|---|---|---|
| Retries a second saved card on decline | Only if you build the fallback logic | Built in, toggle to enable |
| Priority order for which card gets charged | Fixed 4-level field lookup, developer-controlled | Backup flagged explicitly per customer |
| Requires a webhook handler for fallback | Yes | No, for the core switch |
| Still needs Smart Retries / dunning for the rest | Yes | Yes |
That's not an argument for switching platforms — migrating a billing system to get one feature is rarely worth the cost, and everything else in Stripe's dunning stack is genuinely strong. It's a reason to stop assuming Stripe already does this, and to budget the half-day of engineering it actually takes.
Where this fits in your recovery stack
Backup payment method fallback isn't a replacement for anything you already have. It sits alongside card account updater, which fixes a stale card before it ever fails, and Smart Retries and dunning emails, which handle timing and customer communication after a decline. What a backup card fallback catches is the specific gap those two miss: a card that's genuinely, permanently unusable, where the customer already gave you a second option and nothing in Stripe's default configuration ever reaches for it. If you're tracking how much of your involuntary churn is structurally preventable versus genuinely unrecoverable, our churn calculator is a reasonable place to model what closing this specific gap is worth before you build it.
It's also a gap that shows up nowhere in your dashboards until you go looking. A subscription that fails out after its retry window closes gets logged the same way whether the customer had one card on file or three — as a lost subscriber, not as a missed opportunity sitting in a field your webhook never touched. For a product built to catch subscribers at the moment they're about to leave, that's the same instinct that shapes CancelFlow's cancellation flow: don't let a fixable, mechanical failure get filed under "they decided to go."
Frequently asked questions
Does Stripe automatically retry a failed payment using a different card on file?+
No. Stripe's Smart Retries and custom retry schedules both retry against a single payment method, selected from a fixed priority order: the subscription's default_payment_method, then its default_source, then the customer's invoice_settings.default_payment_method, then the customer's legacy default_source. If a customer has three cards attached to their account but the first one in that order keeps declining, Stripe keeps retrying that same card until you change which payment method field it points to.
What's the difference between subscription.default_payment_method and customer.invoice_settings.default_payment_method?+
They're independent fields, and Stripe's retry logic checks the subscription-level field first. If a subscription has its own default_payment_method set, updating only the customer's invoice_settings.default_payment_method does nothing — Stripe keeps retrying the subscription's field. This is the most common reason a 'we already added their new card' fix doesn't actually change what gets charged: the update landed on the wrong object.
How do I build backup payment method fallback logic with Stripe?+
Collect a second payment method with a SetupIntent at signup or in the billing portal, and store both PaymentMethod IDs against the customer in your own database. On invoice.payment_failed, check the decline_code and attempt_count; once a threshold is reached (or immediately on a hard decline), update the subscription's default_payment_method to the backup card's ID and retry the invoice by voiding it and creating a new draft, or by waiting for the next scheduled Smart Retry attempt to pick up the new default.
Does card account updater make backup payment methods unnecessary?+
No, they solve different failures. Card account updater refreshes a card's number or expiry date when a bank reissues it — see our guide to card account updater — but it only works on the card that's already on file. A backup payment method covers a completely different card, useful for insufficient-funds declines, fraud holds on one specific card, or a bank that isn't enrolled in any updater program. Run both; they don't overlap.
Stop losing subscribers today
One script tag. One function call. A live cancellation flow in under 10 minutes.
Start free trial →