SaaS billing and failed payments: the short answer
When a subscription payment fails, your payment provider retries the card and emails the customer. Stripe recommends 8 tries within 2 weeks as its default. What the customer can still do in your product during those retries, and after they run out, is your decision. So is what a downgrade does to data over the new limit, and how a refund is recorded.
This guide is for founders and managing directors at UK and EU companies commissioning a subscription product from a development partner. Most articles on SaaS billing and failed payments come from billing vendors and measure success in money recovered. You also need to know what your customer sees, what your support team can fix, and what the software records.
Our SaaS product development page promises billing states that survive refunds, downgrades and failed cards. The same page gives the reason. A demo becomes a product in everything off the happy path, from an expired card to a customer who changes plan mid month. Below are those states, the decision each needs, and how to test them.
A failed payment is not a cancellation
Renewals fail for ordinary reasons: an expired card, a card replaced after a fraud alert, a bank that wants the customer to confirm the payment. None of them means the customer wants to leave. Treat the failure as its own state and they can fix it in a minute. Treat it as a cancellation and you invite the mess OpenAI now warns ChatGPT subscribers about.
OpenAI's help centre explains how people end up paying twice for one subscription. When an Apple renewal fails, Apple doesn't cancel the subscription. It keeps trying to collect, while ChatGPT may show the subscription as inactive. A subscriber who signs up again on the web, then updates their card with Apple, can be charged by both.
The customer saw "inactive" where the truth was "retrying", and acted on what they saw. Your product needs a name for that in-between state, a screen that shows it, and one obvious way out: update the card.
The billing states your product needs
Stripe gives every subscription a status, such as active, past_due or unpaid, and our guide to what an MVP should include lists all eight. A status tells you where the money stands. It doesn't tell your product what the customer may do, so write a table that does, one row per state, before anyone designs a screen.
Here is the table we'd start from for a business product. Your rows will differ. What matters is that every cell has an answer.
| Your product's state | Stripe status | What the customer can do | What you send | Who acts |
|---|---|---|---|---|
| Trial | trialing | Everything in the plan | A reminder before the trial ends | Nobody yet |
| Paying | active | Everything in the plan | Receipts and invoices | Nobody |
| Retrying | past_due | Everything, with a banner asking an admin to update the card | An email after each failed attempt, with a link to update the card | The customer's billing admin |
| Needs confirmation | past_due, with the bank asking for authentication | Everything, with a banner asking an admin to confirm the payment | An email linking to a page where they confirm it | Only the customer can fix it |
| On hold | unpaid | Sign in, read, export and pay; no new work | A final notice before the hold starts | The customer; your team phones larger accounts |
| Cancelled | canceled | Export until a stated date, then data is deleted on schedule | Confirmation, with the export deadline | Nobody |
| Never started | incomplete, then incomplete_expired | Nothing; no paid account exists | One reminder, if any | Nobody |
Two rules sit behind the table. On hold means read-only, never deleted: a customer whose card failed on Friday should find their data on Monday. And cancelling starts a retention clock; it deletes nothing on the day.
How long a customer keeps access after a card fails
Keep full access while the provider retries, then move to read-only, then cancel. Apple and Google both offer a version of that sequence in their app stores.
- Apple offers a billing grace period of 3, 16 or 28 days for monthly and yearly subscriptions. Subscribers keep their paid content while Apple retries. Without it, their paid service pauses until Apple collects.
- Google Play switches a grace period on by default, with access kept. Account hold follows, where the app should block access. By default the hold lasts 60 days minus the grace period, and then the subscription is cancelled.
- Stripe retries on the schedule you set. After the last retry it does one of three things, chosen in your settings: cancel the subscription, mark it
unpaid, or leave itpast_due(Stripe's retry settings). Its docs say to revoke access once a subscription is unpaid.
Choose those settings on purpose, and match your grace period to the retry window. If Stripe retries for two weeks but your product locks accounts after three days, customers lose access while their payment is still being fixed.
What "access" means is a product question. Say you sell booking software to physiotherapy clinics, priced per practitioner. Locking the diary at 9am on a Monday stops patients booking, and punishes the clinic's own customers for a card the office manager forgot to replace.
A banner for the admin and emails to the billing contact do less harm. So does a read-only hold once the retries fail. The clinic keeps working and has time to pay.
Dunning emails, and the failure a retry can't fix
Dunning is the sequence of reminders and retries after a failed payment. Stripe can send most of the emails for you. It can email after each failed payment with a link to update the card, a month before a saved card expires, and before each renewal.
Send them to someone who can act. In a business product, the person who signed up two years ago may have left. Store a billing contact on each customer account, let the account owner change it, and show billing banners only to people who can pay. Members who can't fix the card needn't see invoices at all, which our guide to user roles and permissions covers.
In the UK and EU, one kind of failure needs its own path. Strong Customer Authentication (SCA) lets a cardholder's bank ask them to confirm a payment. For UK e-commerce, the FCA's deadline was 14 March 2022.
Renewals charged while the customer is away can qualify for an exemption. Stripe warns that exemptions aren't guaranteed, and the bank may still ask.
When it asks, retrying the card changes nothing. Stripe lists authentication_required among the decline codes it can't retry until the customer acts. The email has to link to a page where they confirm the payment with their bank, and Stripe offers a hosted page for that. Turn it on, then test it with a card that asks for authentication.
Upgrades and downgrades: charge now, change later
Proration is the charge or credit for part of a billing period when a customer changes plan. Stripe works it out to the second by default. It doesn't refund a negative proration automatically, or bill a positive one straight away (Stripe's proration docs). You decide both.
The simplest rule, and the one we'd suggest: upgrades take effect and are charged now; downgrades take effect when the paid period ends. The customer paid for the bigger plan this month, so they keep it until renewal, and nobody handles a partial refund.
Three edge cases catch most products:
- An upgrade whose payment fails. By default, Stripe applies the change even if the payment fails, and rolling it back is manual work. The customer gets the bigger plan unpaid. Stripe's pending updates apply the change only once the payment succeeds.
- A downgrade below current usage. The clinic moves from ten practitioner seats to six while eight people still sign in. Your scope should say whether to refuse the downgrade, let the owner pick who stays, or make two accounts read-only. Never delete data to make the numbers fit.
- A plan change while an invoice is unpaid. Stripe calculates prorations as if earlier invoices will be paid, so a customer can be credited for time they never paid for. The usual workarounds can charge them twice unless the old invoice is voided.
One detail for per-seat pricing: when code changes a subscription's price through Stripe's API, the quantity resets to 1 unless the code sends the seat count again. A test with a ten-seat customer catches it.
| Change | When it takes effect | Money | Check in testing |
|---|---|---|---|
| Upgrade | Now | Charge the difference now | The plan stays the same if the payment fails |
| Downgrade | End of the paid period | No refund; the new price applies at renewal | What happens to usage over the new limit |
| Add seats | Now | Charge for the rest of the period | The new seat count reaches the invoice |
| Remove seats | End of the paid period | Credit or nothing, by written policy | Removed users' data stays |
| Monthly to annual | Now | Charge the annual price, minus unused time on the monthly plan | The renewal date moves to today |
| Cancel | End of the paid period | No refund unless your terms or the law require one | Export still works until the end date |
Refunds and credits: add an entry, never edit the invoice
A paid invoice stays exactly as it was issued. A refund or correction goes in as a credit note that points back to it. Stripe's credit notes work this way: a credit note doesn't void and replace the original invoice. On a paid invoice, it can refund the card, add to the customer's credit balance, or record a refund made outside Stripe.
UK VAT rules expect the same shape. HMRC's VAT manual sets out the conditions for a valid credit note. Among them: it goes to the customer, and it corrects a genuine mistake or overcharge or reflects an agreed reduction in price.
Decide between refund and credit in writing, per case. Slack's fair billing policy is a public example. When a paying member hasn't used Slack for more than 28 days, Slack stops billing for them and credits the account for the unused time.
That credit can't be exchanged for money. The rule is written down, so customers can check it and a support agent can apply it without asking anyone.
Inside your product, four rules keep refunds honest:
- Refunding is a permission, given to named roles.
- Every refund and credit needs a reason from a short list, plus a note.
- Refunds above an amount you set need a second person's approval.
- The billing history shows the original invoice, the credit note and who issued it.
That is an audit trail for money. Our guide to why your business software needs an audit trail explains how to stop anyone editing it later, your own administrators included.
Let the provider's events set the status
Your product learns about payments through webhooks: messages your payment provider sends your server when something happens, such as a failed renewal. Stripe's webhook docs warn of three things the receiving code must handle:
- Events can arrive in any order.
- The same event can arrive more than once.
- If your server doesn't answer, Stripe keeps retrying for up to three days in live mode.
So the code records each event's ID and ignores one it has already seen. Before it changes anything, it fetches the current subscription from Stripe. Your product's billing state becomes a copy of the provider's, refreshed from the source, not from whichever message arrived last.
Keep that copy read-only for your team. If a support agent edits "past due" to "active" in your database, the next event sets it back. Or no event comes, and the two systems disagree about who has paid.
To give a customer an extra week, act where the money lives: extend the retries, add a credit, or record a bank transfer as a payment. The provider sends an event, and your product follows it.
A missed event fails quietly. A customer who never paid keeps their access, and nothing on screen looks wrong. Run a daily job that compares every account's state with the provider's and reports any difference to a person.
If a job suspends accounts from a list of overdue customers, have it re-read each account just before acting. The payment may have landed a minute earlier.
UK and EU rules that touch subscription billing
Four sets of rules shape billing for UK and EU companies, besides the VAT rules on credit notes above. This is a map, not legal advice, so check the detail with your adviser.
- Strong Customer Authentication, covered above, means some renewals fail for a reason only the customer can fix.
- New UK rules for consumer subscriptions come into force in January 2027, under the Digital Markets, Competition and Consumers Act 2024. The government names clearer up-front information, regular reminders and an easier way to cancel. It adds a new 14-day cooling-off period after a trial or long contract renews.
- The CMA has already acted on customers who keep paying for a subscription they don't use. In 2022 Microsoft agreed with the CMA to contact long-inactive Xbox members still paying, remind them how to stop, and in the end stop taking their payments.
- In Germany, a business selling consumer subscriptions online must put a cancellation button on its website. Section 312k of the Civil Code says it must read "Verträge hier kündigen" (cancel contracts here) or something equally clear.
The UK's 2027 rules cover a contract between a trader and a consumer, and the German button applies to consumer contracts too. A product sold only to businesses sits outside both. If you also sell to consumers, your state table needs a reminder schedule and a way to cancel online. It also needs a refund path for the new cooling-off period.
Test the unhappy paths before launch
Every state in your table needs a test that forces it. Stripe's sandbox has test clocks that move a subscription's time forward, so you can watch a renewal fail without waiting a month. Its test cards decline on purpose or ask for authentication.
Run these checks in the shared staging environment before anyone calls billing finished:
- Renew with a card that declines. The account moves to retrying, only admins see the banner, and the email's link works.
- Renew with a card whose bank asks for confirmation. The email links to a page where the payment can be confirmed.
- Update the card halfway through the retries. Access continues, and the customer is charged once.
- Let the retries run out. The account goes read-only, and the export still works.
- Upgrade with a card that declines. The plan stays the same.
- Downgrade below current usage. The rule in your scope happens, and no data is lost.
- Refund part of an invoice. A credit note appears, with a reason and the name of whoever issued it.
- Switch off the webhook endpoint for an hour, then back on. Nothing is lost, and the daily comparison finds no difference.
- Send the same event twice. The account changes once.
We work from written scopes and a shared staging environment. A list like this one belongs in the scope, under what "done" means.
When you don't need to build most of this
You may not need much billing code of your own yet. Three options cover a lot of it.
- For the first few customers, an invoice and a bank transfer work, as our MVP guide explains. Store a status on each account anyway.
- Stripe's hosted customer portal lets customers update cards, change plans, cancel and download invoices without screens of your own. It has limits: customers can cancel but not change a subscription paid by invoice, one with several products, or one with usage-based pricing.
- A merchant of record such as Paddle becomes the legal seller to your customers. It takes on sales tax, refunds and chargebacks, and Paddle's docs say you don't register for VAT or sales tax in the countries where you operate. In return you give up some control of checkout and pay a fee on each sale, set out on its pricing page.
No provider can take the product's side of billing off your hands. That means what each state lets a customer do, what a downgrade does to their data, and who on your team may give money back.
Start with the state table
This week, copy the state table above and fill it in for your product. For each state, write what the customer can do, what they're sent and who acts. Add a line for each kind of plan change, saying when it takes effect and what happens to anything over the new limit.
Open the payment provider account in your company's name, as you would the domain. Then send the table with your brief. A builder who reads it can quote the billing you need, not just the checkout page.
Questions
Our business customers pay by invoice and bank transfer, not by card. Does this still apply?
Mostly, with one trap. Stripe marks a new subscription paid by invoice as active, even while its first invoice is unpaid. So for these customers your product has to check invoice due dates as well as the status. Decide how many days overdue moves an account to retrying and then to on hold, and who at your company phones the customer before that happens.
What should happen when a customer disputes a payment with their bank?
A dispute, or chargeback, is a customer asking their bank to reverse a payment. Treat it as its own state with a person deciding what happens next, because it can mean fraud, a misunderstanding or an unhappy customer. Record it on the account, send the payment provider your evidence, and decide by written policy whether access continues meanwhile.
Who should own the Stripe or Paddle account?
Your company, from the first day. The account holds your customers' payment records and receives your money, so it belongs in your company's name, like your domain and hosting. Give developers their own logins with the narrowest role that lets them work, and remove their access when they leave.
How we wrote this: drafted with AI, then checked and edited by the people who build our projects. Figures come from our own work or from the linked sources.