The advice-code point is the one that saves the most money: a decline name alone rarely tells you whether a second attempt is worth the retry fee, while try_again_later versus do_not_try_again changes the whole dunning plan. The insufficient_funds case is interesting too, since the outcome often depends on when the customer gets paid rather than anything the merchant controls, so spacing retries around typical payday cycles usually beats aggressive same-day retries.
Agreed on both. The advice code is the closest thing to a direct answer from the issuer, so it should outrank the decline name when the two disagree. And with insufficient_funds, the timing of the retry does most of the work. One extra thing we'd add: when a retry is going to wait a few days for payday, send the customer a short note first so the failed charge doesn't come as a surprise.
Good addition, and it generalizes past insufficient_funds: any retry you've deliberately scheduled away from the failure moment deserves a heads-up, because the customer's mental model still says 'my card failed.' A one-line note ('we'll try again on the 1st') also catches the case where they've already fixed the underlying problem and would rather update the card than wait for your retry. That's often the cheapest save in the whole flow: the customer does your dunning for you. Thanks for the exchange, this thread covers the retry question from more angles than most.
"The customer does your dunning for you" is the best line in this thread. And it's a good test for the email itself: if someone reading it can't fix the problem in one click, the note isn't doing its job yet.
The one-click test is stricter for expiring-card notices than for a failed payment: an expiring card isn't a problem yet, so the update email competes with everything else in the inbox. A hosted update link is the closest thing to a genuine one click, and it matters most when the card on file was added through a wallet the customer can't edit inside your app. The notes that fail the test say "your card was declined" with no target: the reader opens billing settings, sees three cards and a plan selector, and closes the tab. Naming the exact card and what happens to the subscription if they do nothing is what turns the note into the fix.
Fair distinction. An expiring card isn't a problem for the customer yet, so the note has to do more work: name the exact card and say what happens on renewal day if they do nothing. Thanks again, this has been a really useful thread.
The expired-card nuance here is the one most teams get wrong in both directions, so worth adding a layer: the reason an expired_card retry sometimes succeeds isn't luck — it's the account updater. When the issuer has replaced the card, Visa/Mastercard updater services can silently substitute the new number, so the "retry" that clears is really a first attempt on a new credential. That's worth one or two attempts.
Once the updater has had its chance and the card still fails, though, every further retry is pure downside: it can't succeed on a dead number, and it feeds the decline-rate monitors the networks run per merchant account. So the practical rule is: expired card gets a short retry window for the updater to land, then it stops being a retry problem and becomes a card-update problem — the customer has to hand you a new card, and the email asking for it should go immediately, not after the retry schedule exhausts.
One more wrinkle for Shopify-side readers: on Recharge or Skio the platform owns the retry schedule, not Stripe Billing, so the same decline code gets different treatment depending on which layer runs your subscriptions. Worth checking which layer you're actually configuring.
(Disclosure: we build Swipe Again, which routes failures this way — updater window first, then straight to a branded card-update flow.)
We're a place where coders share, stay up-to-date and grow their careers.
The advice-code point is the one that saves the most money: a decline name alone rarely tells you whether a second attempt is worth the retry fee, while try_again_later versus do_not_try_again changes the whole dunning plan. The insufficient_funds case is interesting too, since the outcome often depends on when the customer gets paid rather than anything the merchant controls, so spacing retries around typical payday cycles usually beats aggressive same-day retries.
Agreed on both. The advice code is the closest thing to a direct answer from the issuer, so it should outrank the decline name when the two disagree. And with insufficient_funds, the timing of the retry does most of the work. One extra thing we'd add: when a retry is going to wait a few days for payday, send the customer a short note first so the failed charge doesn't come as a surprise.
Good addition, and it generalizes past insufficient_funds: any retry you've deliberately scheduled away from the failure moment deserves a heads-up, because the customer's mental model still says 'my card failed.' A one-line note ('we'll try again on the 1st') also catches the case where they've already fixed the underlying problem and would rather update the card than wait for your retry. That's often the cheapest save in the whole flow: the customer does your dunning for you. Thanks for the exchange, this thread covers the retry question from more angles than most.
"The customer does your dunning for you" is the best line in this thread. And it's a good test for the email itself: if someone reading it can't fix the problem in one click, the note isn't doing its job yet.
The one-click test is stricter for expiring-card notices than for a failed payment: an expiring card isn't a problem yet, so the update email competes with everything else in the inbox. A hosted update link is the closest thing to a genuine one click, and it matters most when the card on file was added through a wallet the customer can't edit inside your app. The notes that fail the test say "your card was declined" with no target: the reader opens billing settings, sees three cards and a plan selector, and closes the tab. Naming the exact card and what happens to the subscription if they do nothing is what turns the note into the fix.
Fair distinction. An expiring card isn't a problem for the customer yet, so the note has to do more work: name the exact card and say what happens on renewal day if they do nothing. Thanks again, this has been a really useful thread.
The expired-card nuance here is the one most teams get wrong in both directions, so worth adding a layer: the reason an expired_card retry sometimes succeeds isn't luck — it's the account updater. When the issuer has replaced the card, Visa/Mastercard updater services can silently substitute the new number, so the "retry" that clears is really a first attempt on a new credential. That's worth one or two attempts.
Once the updater has had its chance and the card still fails, though, every further retry is pure downside: it can't succeed on a dead number, and it feeds the decline-rate monitors the networks run per merchant account. So the practical rule is: expired card gets a short retry window for the updater to land, then it stops being a retry problem and becomes a card-update problem — the customer has to hand you a new card, and the email asking for it should go immediately, not after the retry schedule exhausts.
One more wrinkle for Shopify-side readers: on Recharge or Skio the platform owns the retry schedule, not Stripe Billing, so the same decline code gets different treatment depending on which layer runs your subscriptions. Worth checking which layer you're actually configuring.
(Disclosure: we build Swipe Again, which routes failures this way — updater window first, then straight to a branded card-update flow.)