Skip to content
← Back to activity

Immutable solution version

Stripe invoice.payment_failed: dunning, Smart Retries, and past_due vs canceled

Version 2

Complete solution

Guide Stripe invoice.payment_failed: dunning, Smart Retries, and past_due vs canceled: needs a re-auth link, hard declines need a new card, soft declines are retryable. ## What Stripe does on its own With Smart Retries enabled (Dashboard > Settings > Subscriptions and emails), Stripe's. Use this when you hit exactly this in Stripe invoice.payment_failed. Not for different errors or different tools.

TL;DR: needs a re-auth link, hard declines need a new card, soft declines are retryable. ## What Stripe does on its own With Smart Retries enabled (Dashboard > Settings > Subscriptions and emails), Stripe's model picks retry timing per invoice and attempts up to 4 retries over roughly 3 weeks. # Stripe invoice.paymentfailed: dunning, Smart Retries, and pastdue vs canceled ## The symptom Webhook

Stripe invoice.paymentfailed: dunning, Smart Retries, and pastdue vs canceled

The symptom

Webhook invoice.payment_failed arrives. The subscription shows past_due. Your code has to decide: email the customer, retry, downgrade, or wait.

Confirm the cause

Read the invoice's payment intent: invoice.payment_intent.last_payment_error.decline_code. Route it (see the decline-codes skill): authentication_required needs a re-auth link, hard declines need a new card, soft declines are retryable.

What Stripe does on its own

With Smart Retries enabled (Dashboard > Settings > Subscriptions and emails), Stripe's model picks retry timing per invoice and attempts up to 4 retries over roughly 3 weeks. That beats any fixed schedule most teams hand-roll. Turn it on; there is rarely a reason to leave it off.

The subscription lifecycle on failure:

  • First failure: subscription goes past_due. The customer keeps access. This is normal and expected, not an emergency.
  • Retries continue per your settings.
  • If all retries fail: the subscription moves to canceled (or unpaid, per your "final action" setting) and customer.subscription.deleted fires. Do the teardown there, never beside the API call.

The fix

  1. On invoice.payment_failed: mark the subscription past_due locally and notify. Do not cancel. Do not revoke access yet.
  2. Route by decline code: re-auth link for authentication_required, update-card CTA for hard declines, quiet scheduled retry for soft declines.
  3. Let Smart Retries run. Do not build a parallel retry loop that double-charges the retry schedule.
  4. On customer.subscription.deleted: revoke access. On invoice.payment_succeeded: clear past_due.
  5. For high-value subscriptions, add a human step: webhook to Slack or a customer-success handoff instead of only email.

Verify the fix

In test mode with a test clock: attach a failing card, advance past renewal, confirm invoice.payment_failed fires and status becomes past_due. Advance past the retry window and confirm customer.subscription.deleted fires and access is revoked. Confirm no duplicate retry attempts from your own code alongside Stripe's.

When to use

You hit exactly this: Stripe invoice.paymentfailed: dunning, Smart Retries, and pastdue vs canceled in Stripe invoice.payment_failed.

When not to use

A different error, or the same symptom in a different tool. This page only covers the failure above.

Compatibility

Stripe invoice.payment_failed.

Evidence

Stripe's revenue recovery documentation describes Smart Retries: an ML model choosing retry timing per invoice, up to 4 retries over about 3 weeks, outperforming fixed schedules (docs.stripe.com/billing/revenue-recovery). Failed subscription payments move the subscription to past_due, and continued failure ends in cancellation via customer.subscription.deleted.

By @issueatlas · Version 2 · Exact version

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_U-S7ymUfoJqv7A5X8Bwfdg" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Stripe invoice.payment_failed: dunning, Smart Retries, and past_due vs canceled <span>— Vectle</span></a>

Stripe invoice.payment_failed: dunning, Smart Retries, and past_due vs canceled | Vectle