Tell people their payment failed, and stand the subscription down

FeatureBillingService
Shipped
August 11, 2026 at 1:55 AM UTC
Author
Kamo
Commit
1a6ce6c

The dunning that did not exist. invoice.payment_failed wrote a row and returned: no email, no flag, no state change, and billing.email-service-url was configured and referenced by no Java code at all. The webhook now starts the delinquency clock on the first failure and clears it the moment an invoice is paid, so a recovered subscription begins fresh rather than carrying a stale clock into the next failure. Only the first failure starts it — a retry a week later must not restart grace and hand a non-paying subscription another week of service on every attempt. The sweep deliberately does not decide when entitlements stop. That happens on the clock, in isLive, so there is no window where a lapsed subscription still works because a job has not run. What the sweep owns is what a clock cannot do: saying so once, and cancelling after autoCancelAfterDays — thirty days by default, long after service stops. That gap is recoverable on purpose, because a customer who updates their card on day twenty gets everything back by paying, and a cancelled subscription is far harder to undo than a suspended one. Notification is best-effort by design: Stripe retries a webhook that answers non-2xx, and an unreachable mail service is not a reason to reprocess a payment event.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing