Learn

Stripe Subscription past_due: What It Means and How to Fix It

When a Stripe subscription enters past_due status, it means the latest invoice payment failed and the subscription is in limbo. If you do not handle this status correctly, Stripe will eventually cancel the subscription and your customer is gone. This guide explains exactly what past_due means, how to configure grace periods, and how to recover before cancellation.

What past_due Actually Means in Stripe's Subscription Lifecycle

Stripe subscriptions move through a series of statuses during their lifecycle: trialing, active, past_due, unpaid, canceled, or incomplete. Understanding past_due requires knowing where it sits in this flow.

A subscription enters past_due when Stripe creates an invoice for the next billing period, attempts to charge the customer's payment method, and the charge fails. At this point, the subscription is not canceled — it is still 'alive' in Stripe's system. The customer still has an active subscription object, and depending on your configuration, they may or may not still have access to your product.

The past_due status is essentially a grace period. It tells you: 'This customer's payment failed, but we have not given up yet.' Stripe will continue retrying the payment according to your Smart Retries configuration (or your custom retry schedule), and the subscription will remain past_due until one of three things happens: the retry succeeds (subscription returns to active), you manually mark the invoice as paid or void it, or the retry schedule is exhausted and the subscription moves to its configured terminal state.

The critical configuration point: In your Stripe Dashboard under Settings > Billing > Subscriptions and emails > Manage failed payments, you control what happens after all retries are exhausted. The options are: cancel the subscription, mark it as unpaid (keep the subscription object but stop service), or leave the invoice open (subscription stays past_due indefinitely). Each option has trade-offs.

Canceling is the cleanest from a data perspective but the most destructive for retention. Once canceled, the customer must re-subscribe entirely, and any usage history, plan grandfathering, or loyalty pricing may be lost. Marking as unpaid keeps the subscription recoverable but requires your application to check subscription status and enforce access restrictions. Leaving the invoice open is the least destructive but can create accounting complications if past_due invoices accumulate.

Most SaaS businesses that take passive churn seriously choose the 'mark as unpaid' option with a 7-14 day past_due window. This gives you maximum recovery time while maintaining a clear boundary between 'paying customer' and 'needs attention.'

Handling past_due with Webhooks

Proper webhook handling is the foundation of your past_due recovery strategy. There are several webhook events you need to listen for, and each one triggers a different action in your recovery flow.

customer.subscription.updated fires when a subscription's status changes. Listen for transitions from active to past_due. When you receive this webhook, you know a payment has failed and the grace period has started. This is your trigger to begin customer outreach — send the first recovery email, display an in-app banner, or both.

Here is the essential webhook handler pattern:

``` if event.type == 'customer.subscription.updated' subscription = event.data.object previous = event.data.previous_attributes if previous.status == 'active' AND subscription.status == 'past_due' // Payment just failed — start recovery flow send_recovery_email(subscription.customer) set_grace_period_flag(subscription.customer) end end ```

invoice.payment_failed fires every time a payment attempt fails, including retries. Use this to track how many retries have occurred and escalate your communication accordingly. First failure: gentle notification. Second failure: reminder with urgency. Third failure: final warning.

invoice.payment_succeeded fires when a retry (or customer-initiated payment) succeeds. This is your signal to end the recovery flow: remove in-app banners, stop the email sequence, and clear any grace period flags. Missing this webhook is a common mistake that results in customers receiving 'please update your card' emails after they have already paid.

customer.subscription.deleted fires when the subscription is canceled (either by your configuration or manually). If you receive this after a past_due period, the recovery window has closed. You are now in win-back territory.

Common webhook pitfalls: First, make your webhook handlers idempotent. Stripe may send the same event more than once. If your handler sends an email on each invocation, your customer might get duplicate recovery emails. Use the event ID to deduplicate. Second, process webhooks asynchronously. Do not make Stripe wait for your email to send or your database to update — acknowledge the webhook quickly and process in the background. Third, verify webhook signatures to prevent spoofing.

Configuring Optimal Grace Periods

Your grace period — the time between the first failed payment and subscription cancellation — is the most important business decision in your passive churn strategy. Too short and you cancel customers who would have recovered. Too long and you provide free service to customers who will never pay.

7 days is the minimum viable grace period. It allows for 2-3 retries and 1-2 recovery emails. Recovery data shows that about 60-70% of all recoverable payments are recovered within the first 7 days. If you are running a tight operation and want to minimize free service, 7 days captures most of the value.

14 days is the sweet spot for most SaaS businesses. It allows for 3-4 retries and a full 3-email recovery sequence. The incremental recovery between day 7 and day 14 is about 15-20% of total recoverable revenue. That is meaningful — for a business with $50K MRR and 5% failure rate, the difference between a 7-day and 14-day grace period is roughly $375-500/month in recovered revenue.

21-30 days makes sense for high-value subscriptions ($100+/month) where each recovered customer represents significant revenue. The incremental recovery in days 15-30 is smaller (5-10% of total recoverable), but when each customer is worth $100+/month, the math still works. The trade-off is that you are providing up to 30 days of free service to customers who may never pay.

Access restrictions during the grace period are a nuanced decision. Some businesses maintain full access during past_due to avoid disrupting the customer's workflow (and to avoid triggering cancellation because the customer got frustrated by a degraded experience). Others restrict access after a few days to create urgency. A middle approach: maintain full access for the first 7 days, then switch to read-only or limited access for the remainder.

Stripe's configuration for this lives in the Billing settings. You set the number of retry attempts and the spacing between them, and you set the terminal action (cancel, mark unpaid, or leave open). Stripe's Smart Retries feature also uses machine learning to pick optimal retry times based on the specific decline code and customer behavior patterns.

One often-overlooked configuration: proration behavior during past_due. If a past_due customer has a successful retry on day 10 of their billing period, you need to decide whether they owe for the full period or only from the recovery date forward. Stripe defaults to charging for the full period (since the subscription was never canceled), which is the right approach for most businesses — the customer had access to the product during the past_due window.

Preventing Auto-Cancellation: Keeping Subscriptions Alive

The worst outcome of a past_due subscription is automatic cancellation. Once Stripe cancels a subscription, recovering that customer requires them to go through your entire sign-up flow again. Any grandfathered pricing, accumulated usage data, or loyalty benefits may be lost. The customer has to actively choose to come back, and most will not.

Here are specific tactics to prevent auto-cancellation while still maintaining billing discipline.

Extend the retry schedule before the terminal action fires. Stripe's default retry schedule runs 4 attempts over about 3 weeks. If your terminal action is 'cancel subscription,' extending the retry schedule to 5-6 attempts over 4 weeks gives you more recovery opportunities before the irreversible action fires.

Use 'mark as unpaid' instead of 'cancel.' The unpaid status keeps the subscription object alive in Stripe. The customer's subscription ID, plan details, and billing history are preserved. Your application can check for the unpaid status and restrict access, but when the customer eventually updates their card, you can reactivate the subscription without them re-subscribing. This is the single most impactful configuration change for reducing passive churn.

Implement a manual review queue. Before a subscription reaches its terminal state, flag it for manual review. A human can look at the customer's value (LTV, engagement, plan level) and decide whether to extend the grace period, reach out personally, or let the automation proceed. For high-value customers, a personal email from the founder can recover subscriptions that automated emails cannot.

Offer plan downgrades as a retention tool. If a customer's payment fails repeatedly and their card might be permanently invalid, offer them a free or reduced plan as a bridge. 'We noticed your payment is not going through. We have temporarily moved you to our free plan so you do not lose access. Update your payment method when you are ready to resume your premium plan.' This keeps the customer in your ecosystem and makes the eventual recovery much easier.

Monitor your cancellation-to-recovery ratio. Track how many subscriptions reach terminal cancellation versus how many are recovered during the grace period. If more than 30-40% of past_due subscriptions reach cancellation, your grace period is too short or your recovery tactics are not aggressive enough. Healthy ratios are 15-25% reaching cancellation.

How Revive Manages past_due Subscriptions End to End

Revive is purpose-built for the past_due lifecycle. When you connect your Stripe account, Revive monitors for subscription status changes and implements the full recovery workflow described in this guide.

When a subscription enters past_due, Revive immediately reads the decline code from the failed invoice and routes the recovery through the optimal path. Soft declines trigger smart retries with payday-aligned timing. Hard declines trigger branded recovery emails with one-click payment update links. 3DS challenges trigger authentication payment links.

Revive coordinates retries and emails so they never conflict. If a retry succeeds, the recovery email sequence stops automatically. If a retry is pending, the email is held until the retry result is known. This prevents the common problem of customers receiving 'update your card' emails minutes after their payment was successfully retried.

The result: Revive recovers 30-60% of past_due subscriptions before they reach your terminal state configuration. No webhook code to write. No retry logic to implement. No email templates to design. Connect Stripe at [/api/connect](/api/connect) and Revive handles the rest.

Key Takeaways

  • past_due means a payment failed but the subscription is still alive — act quickly before it reaches terminal state
  • Configure Stripe to 'mark as unpaid' instead of 'cancel' to preserve subscription objects for recovery
  • 14 days is the optimal grace period for most SaaS businesses, balancing recovery time and free service
  • Handle customer.subscription.updated, invoice.payment_failed, and invoice.payment_succeeded webhooks for full coverage
  • Make webhook handlers idempotent — Stripe may send duplicate events
  • Personal outreach for high-value customers can recover subscriptions that automated emails miss

Automate Your Payment Recovery

Revive uses everything in this guide — smart retries, decline-code routing, and branded recovery emails — on autopilot. Connect Stripe in 30 seconds.