Subscriptions and Recurring Billing: What Happens When a Card Fails or a Plan Changes Mid-Month
Back to blog
automation·September 6, 2026·6 min read·By Yehonatan Saadia

Subscriptions and Recurring Billing: What Happens When a Card Fails or a Plan Changes Mid-Month

Five subscription states, what triggers each transition, mid-cycle proration worked through with real numbers, and the open invoice an upgrade must never erase.

Key takeaways

  • Five states cover most businesses, and two of them differ only in who is acting. `past_due` is the period where the system retries by itself; `grace` is the period where a person does. Without that split, nobody retries.
  • Service switches off on the move to `suspended`, not on the move to `past_due`. Cutting access at the first decline cancels subscriptions over a temporary gateway fault.
  • Stripe documents a retry policy bounded to one week, two weeks, three weeks, one month or two months, after which the subscription moves to `canceled` or `unpaid` depending on configuration. That choice is a business decision, not a default to inherit.
  • A mid-cycle plan change is two lines, not one: a credit for the unused remainder of the old plan and a charge for the same remainder on the new plan. The difference is what the customer pays.
  • An upgrade does not clear an open invoice. If proration credit is netted against an earlier debt, you have lost both the ability to collect it and the record that it existed.

A subscription is a state machine, not an active/inactive flag. Five states - active, past due, grace, suspended and cancelled - and every transition between them is driven by one defined event: a failed charge, a retry that succeeded, a grace window ending, or a plan change. Without that map, each declined card triggers a fresh human decision.

The five states and what each one permits

A subscription's state decides three things at once: whether the service runs, whether the system will retry a charge, and whether a plan change is allowed. Conflating the three is where the confusion starts.

  • active - the service runs, a valid payment method exists, the next charge is scheduled. This is the only state in which a plan change is straightforward.
  • past_due - a renewal charge failed and the system is working through a retry schedule. The service still runs. The customer usually does not know yet.
  • grace - automated retries are exhausted and the money has not arrived. The service still runs, but from here it is a human task with a deadline: contact the customer, update the card, send a payment link.
  • suspended - the service is off, the data is retained, the debt still exists and is still collectible. This state is reversible.
  • cancelled - terminal. The subscription does not come back to life; a returning customer gets a new subscription with a new identifier.

The distinction most often missed is between past_due and grace. To the customer they look identical - the service works and the money has not been paid - but in the first the system owns the next action and in the second a person does. A business carrying a single "overdue" flag discovers that retries stopped two weeks ago and nobody noticed.

Why is "payment failed" not a state?

Because a failed charge is an event in time, and a state is what is true right now. An event happens once and belongs in a log; a state persists until another event replaces it. When a system stores payment_failed in the status field, it cannot answer the basic question: how long has this customer been overdue, and how many attempts remain?

The practical separation is one event log holding charge_attempted, charge_failed, charge_succeeded, plan_changed, card_updated and state_changed, alongside a single state field on the subscription record. The state is always derived from the last event that justified it, and a state_reason field carries the code the gateway returned. Separating a soft decline from a hard one changes behaviour entirely - Stripe states explicitly that it does not retry when no payment method is available or when the issuer returned a hard decline. Common decline codes in the Israeli market are broken down in the code 12 declined transaction checklist.

The transition table

FromTrigger eventToEffect on service
activerenewal charge failspast_duekeeps running
past_duea retry succeedsactiveunchanged
past_dueretry schedule exhaustedgracekeeps running, human task opens
gracepayment received manuallyactiveunchanged
gracegrace window endssuspendedswitches off
suspendeddebt settledactiveswitches on, reactivation invoice issued
suspendedretention window endscancelledterminal
activecustomer requests cancellationcancelled at period endruns to current_period_end

Two rows in that table are the expensive decisions. The length of the grace window sets how much revenue you lose against how many customers you lose, and the length of the retention window sets how long data survives after shutoff. Both belong in a configuration file as numbers, not in a conversation held again every time.

What does a mid-cycle plan change actually cost?

Proration is two lines: a credit for what was not used on the old plan and a charge for the same window on the new one. Worked through with numbers, on a 30-day cycle running 1 to 30 September:

  • Basic at 240 ILS per month was charged on 1 September.
  • On 11 September the customer upgrades to Pro at 600 ILS per month. Twenty days remain in the cycle.
  • Credit for unused Basic: 240 x 20/30 = 160 ILS.
  • Charge for Pro over the remaining window: 600 x 20/30 = 400 ILS.
  • Net amount billed immediately: 400 minus 160 = 240 ILS.
  • The next invoice, on 1 October, is a full 600 ILS.

Sanity check: the customer paid 240 at the start of September and another 240 mid-month, 480 in total. Ten days of Basic is 80 ILS and twenty days of Pro is 400 ILS, which is 480. If that check does not close, the calculation basis is wrong.

An upgrade produces a charge, but a downgrade produces a credit, and that needs a decision. The same customer moving from Pro to Basic on 21 September, ten days before the end: a credit of 600 x 10/30 = 200 ILS against a charge of 240 x 10/30 = 80 ILS, leaving 120 ILS in credit. Two defensible policies exist: carry the credit onto the next invoice, which then issues at 240 minus 120 = 120 ILS, or issue a document immediately. Stripe names those two behaviours create_prorations and always_invoice, alongside none which disables proration entirely. Pick one and write it into your terms, because a customer who sees a 120 ILS invoice with no explanation opens a ticket.

One detail that is easy to miss is the calculation basis. A system that prorates by day and one that prorates by second produce different numbers for the same change. Neither is wrong, but there has to be one answer in the code and the same answer in the documentation. The other half of this process, issuing a document for every successful charge, is covered in automating recurring billing in Israel.

The open invoice that survives an upgrade

An upgrade is not a collection event. If a customer has an unpaid invoice from last month and upgrades today, that invoice stays exactly as it was. Three common mistakes quietly erase it:

  1. Netting proration credit against the older debt. The two lines belong to different periods and different documents, and netting destroys the trail that the debt existed.
  2. Creating a new subscription instead of changing the plan. The old subscription closes, and its collection position closes with it.
  3. Resetting dunning_attempt because the proration charge succeeded. The card worked just now, but the old invoice is still unpaid.

The rule that prevents all three: an invoice is an independent document with its own lifecycle, and a plan change modifies only the subscription. That also decides whether to block upgrades while a subscription is past_due. Blocking is operationally cleaner; allowing the upgrade grows revenue but requires the old debt to stay visible in the collection report. When collection runs on bank mandates rather than cards, the failure timeline is entirely different - the comparison is set out in direct debits versus card payments.

The subscription record: fields that make the state recoverable

FieldExample valueWhy it is needed
subscription_idSUB-2026-004812stable identifier that survives a plan change
statepast_duethe current state, one of five values
state_reasoncard_expiredthe reason for the last transition, from the gateway code
plan_codepro-monthlythe plan in force now
current_period_start2026-09-01cycle start, the basis for proration
current_period_end2026-09-30cycle end
next_payment_attempt2026-09-05T09:00:00+03:00when the system will retry
dunning_attempt2how many attempts have run
grace_until2026-09-14when the state moves to suspended
open_invoice_ids["INV-2026-11907"]invoices not yet paid

next_payment_attempt is the field that makes collection monitorable. Stripe exposes it on the invoice for exactly this purpose. Without it you cannot answer "which subscriptions will suspend this week", which is the only question anyone cares about on a Sunday morning.

Where the money leaks without anyone noticing

  • A subscription sitting in grace with no assigned task. Nobody calls, the window closes, the customer disappears without speaking to a human.
  • Retries hitting the same permanent decline code repeatedly. Five attempts against an expired card are five guaranteed failures.
  • An upgrade recorded as a new plan, so the recurring revenue report counts an existing customer as new and the closed subscription as churn.
  • A cancellation applied immediately rather than at period end, when the customer has already paid for the month. That is a refund you did not intend to give.
  • A plan change made by hand in an admin screen without writing an event. A month later there is no way to explain the amount on the invoice.
  • A subscription restored from suspended to active without refreshing the cycle dates, so the next charge lands on the wrong day.

Sources

#subscription billing#recurring billing#dunning#proration#Stripe#אוטומציה

Frequently asked questions

How many retry attempts should I configure?

The count matters less than the window and the reason. Stripe lets you set a number of attempts inside a window of one week to two months, and skips an attempt when no payment method exists or a hard decline was returned. Retries against a permanent decline never succeed, so separating decline types is worth more than adding an attempt.

Should the service switch off the moment a charge fails?

No, because a large share of failures are temporary: a replaced card, an exhausted limit, a gateway fault. Shutoff belongs to the move into `suspended`, after automated retries are exhausted and the grace window has also closed. The gain from waiting two weeks almost always exceeds the cost, except where usage itself is expensive.

What is the difference between immediate cancellation and cancellation at period end?

Cancelling at period end leaves the subscription active until `current_period_end` and prevents a further charge, which is the sensible default once the customer has paid. Immediate cancellation stops service now and raises a pro-rata refund question. Both are legitimate, but they must be two separate states on the record rather than one button.

How do I confirm invoices match what was actually charged?

With a daily reconciliation across three sources: charge events from the gateway, the documents issued, and the lines on the subscription record. A discrepancy is presented with the charge id and the document id, not as a summary number. A successful charge with no document and an invoice with no charge are two different faults with two different fixes.

Keep reading

Related service

Business Automation

I build custom automations that remove repetitive work end to end.

Learn more →←

About the author

Yehonatan Saadia

Freelance automation, web & MVP developer

I'm Yehonatan Saadia, a senior developer who builds business automation, custom websites, and MVPs for small and mid-sized companies across the US, Europe, and Israel. These guides come from real client work, not theory.

Work with me

Have a project like this?

Tell me what you're trying to automate or build. I reply within 24 business hours with a few targeted questions, then we walk through it on a free 30-minute call, with no commitment. You come away with a scope, a timeline and a fixed price - or a straight answer that it isn't worth building.