Stripe Billing is the part of Stripe that runs recurring charges: you define products and prices, attach them to customers as subscriptions, and Stripe creates invoices, collects payment and retries failures. A working SaaS setup needs five things: clean prices, a trial rule, proration settings, the customer portal and a verified webhook handler.
| Step | Stripe object or feature | Decision to make | What usually breaks |
|---|---|---|---|
| Model plans | Product and Price | One product per plan, one price per currency and interval | Editing prices in the Dashboard instead of versioning them |
| Offer a trial | Subscription trial settings | Card up front or not; what happens at trial end | Trial ends with no card and access lingers |
| Change plans | Proration behaviour | Upgrade now with credit, downgrade at period end | Customers surprised by a mid-cycle charge |
| Invoice | Invoices, tax IDs, receipts | Collect VAT numbers and company details at checkout | Missing business details on invoices |
| Self-service | Customer portal | Which plans and actions customers may use | Portal allows plan switches your app cannot handle |
| Sync access | Webhook endpoint | Which events update your database | Unverified, non-idempotent handlers |
| Authenticate | 3D Secure and invoice recovery | How a customer completes a bank challenge | No recovery link in failed-payment emails |
Stripe Billing is Stripe's subscription and invoicing product. It stores customers, products and prices, creates recurring invoices, and charges the saved payment method. It fits any SaaS that bills monthly or yearly, per seat or by usage. A one-off purchase needs only a simple checkout, not Billing.
Stripe describes Billing as monetization infrastructure that combines subscriptions and usage-based billing with its built-in payment system. For a startup, the practical benefit is that you do not write renewal logic, retry schedules or invoice PDFs yourself.
This guide is about the subscription layer. If you are still choosing how to take card payments at all, our separate post on payment gateway integration covers that decision. Here we assume Stripe is chosen and focus on what breaks once real customers renew.
Our team builds these flows in Next.js and Node.js with Supabase as the database, and the pattern below reflects that stack. The ideas hold for any backend. If you are still weighing frameworks, our tech stack explainer for non-technical founders is a good companion.
Create one product per plan and one price per currency and billing interval, and never rely on editing a price. A Stripe price's amount is fixed once created. To change a plan's cost, create a new price, move new customers to it, and migrate existing subscribers deliberately.
This is where most early builds go wrong. Founders hard-code a price ID into the app, then want to raise a price six months later. If the old price is still attached to live subscriptions, you now have two prices for one plan and no map between them.
Give every price a lookup key such as team_monthly_gbp_v1. Your code asks Stripe for the price by lookup key, so a later v2 can replace it without a code change. Archive old prices instead of deleting them, so existing subscribers keep working.
Decide early which currencies you will sell in. A UK and Nordic audience often wants GBP, EUR, SEK, DKK or NOK. Stripe lets one price carry several currencies, but each needs an amount you chose, not a raw conversion. Publish those amounts on your pricing page as well.
Flat monthly plans, per-seat plans and usage-based plans each map to a different price setup. If you have not picked a model yet, read our breakdown of SaaS pricing models and how to pick one first. Billing code is expensive to rewrite after launch.
Keep your own plan table in the database, with a column for the Stripe lookup key and the feature limits. Stripe knows what a customer pays. Your database should say what that payment unlocks.
Set a trial length on the subscription, decide whether to collect a card at sign-up, and choose what happens if no payment method exists when the trial ends. Collecting a card converts more trials to paid, while skipping it lowers sign-up friction. Pick one deliberately and test the final day.
Stripe lets you start a subscription with a trial period or a fixed trial end date. During the trial the invoice is zero, and the first real charge happens when the trial finishes.
Our rule of thumb for early-stage B2B SaaS: if your product needs setup effort before it shows value, skip the card and rely on onboarding emails. If the value is visible in minutes, ask for the card. Neither choice is universally right, and your own conversion data should override our rule after a few hundred trials.
For no-card trials, Stripe lets you set what happens at the end if there is no payment method: cancel, pause, or create an invoice. Pausing is usually friendliest, because a returning user can add a card and resume without recreating the subscription. Whatever you choose, make your app mirror it.
Stripe also sends a customer.subscription.trial_will_end event shortly before a trial ends. Use it to trigger a reminder email from your own system, with a button that opens the customer portal or a checkout session to add a card.
When a customer changes plan mid-cycle, Stripe can prorate: it credits the unused time on the old price and charges for the remaining time on the new one. You control this with the proration behaviour setting. Most SaaS products upgrade immediately with proration and apply downgrades at the end of the period.
The setting has three practical modes: create prorations on the next invoice, invoice the difference immediately, or apply no proration at all. Which you choose changes when the customer sees the charge.
Suppose a customer pays £30 a month on a 30-day cycle and upgrades to a £60 plan on day 10. This is an illustration, not a quote. Stripe calculates by the second, so real figures will differ slightly.
If you add the difference to the next invoice, the customer gets the upgrade at once but sees a larger bill at renewal. That surprise generates support tickets. Invoicing immediately is cleaner for most small teams.
For downgrades, schedule the change for the end of the current period. The customer has already paid for the higher tier, so they keep it until then. Avoid refund-style credits unless you have a clear policy. Your terms of service, not your code, should state what you refund.
The billing cycle anchor decides which day of the month renewals happen. Leave it at the sign-up date unless you have a reason, such as aligning every customer to the first of the month. Changing it later triggers proration of its own.
Stripe creates an invoice for every billing cycle, finalises it, and attempts payment. Each invoice has a hosted page and a PDF that customers can download. For European B2B sales, collect the customer's company name, address and VAT number at checkout so the invoice carries them from the start.
The invoice lifecycle runs from draft to open to paid, with void and uncollectible as the other end states. Your app rarely touches drafts. It reacts when an invoice is paid or fails.
UK and Nordic finance teams expect an invoice that names their company and shows a VAT number. Stripe checkout can collect tax IDs, and Stripe offers a tax product that calculates tax by location. How VAT applies to your sales depends on where you and your customers are based, so confirm the setup with your accountant before launch. We build the flow; we do not give tax advice.
The regulation of the payment itself is separate. In the UK, payment services fall under the Payment Services Regulations 2017, which require the FCA to maintain a register of authorised payment institutions. Because Stripe handles the card processing, your SaaS is not the one moving the money. If you ever plan to hold or transfer funds for others, the FCA authorisation page on GOV.UK is where to begin checking your position.
Stripe can email receipts and invoices on your behalf. Many teams switch this on at first, then replace it with branded emails from their own system once the product matures. Either way, show a billing history page inside your app. Customers should not need to hunt through their inbox for an invoice.
The Stripe customer portal is a hosted page where customers update their card, view invoices, change plan or cancel. You create a portal session from your server and redirect the user to it. It removes the need to build most billing screens yourself, which saves weeks on an MVP.
Configure the portal in the Dashboard before you ship it. Decide three things:
The portal changes billing state without your app being involved, so it only works safely if webhooks are in place. A customer who cancels in the portal will not tell your app. Stripe will, through an event.
Branding matters for trust. Add your logo and colours so the redirect does not feel like a different company. Our UI/UX design team usually pairs the portal with a billing page inside the product that shows current plan, next renewal date and a clear "Manage billing" button.

The key events are checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted and customer.subscription.trial_will_end. Handle these, verify each signature, and treat the events as the single source of truth for who has access.
Subscription state changes outside your app all the time: renewals, failed renewals, portal cancellations and edits your team makes in the Dashboard. Webhooks are how your system finds out. Public Stripe guides from several developer teams make the same point, and so does our experience: a redirect URL is not proof of payment.
| Event | What your app should do |
|---|---|
checkout.session.completed | Link the Stripe customer ID to your account and store the subscription ID |
invoice.paid | Extend the access period and record the payment |
invoice.payment_failed | Mark the account past due and start your recovery emails |
customer.subscription.updated | Sync plan, status, quantity and period end into your database |
customer.subscription.deleted | Revoke paid features and move the account to a free or locked state |
customer.subscription.trial_will_end | Send a reminder with a link to add a payment method |
In a Next.js app this is a route handler that reads the raw body, verifies it, writes to a Supabase table, and returns. Keep the table simple: customer ID, subscription ID, status, plan lookup key, current period end. Row-level security then lets each user read only their own billing row.
One question stays open for us on most projects: whether to gate access on status alone or on current_period_end as well. A past-due account may deserve a few days of grace. That is a product call, so write it down before you code it.
Strong Customer Authentication (SCA) is the PSD2 rule that asks card customers in Europe to confirm many online payments with two factors, usually through a 3D Secure bank prompt. Stripe handles the prompt at sign-up. Your job is to recover renewals that need a customer to authenticate later.
PSD2 is in force across the EU, and strong customer authentication applies to electronic payments there, as the Austrian regulator and others describe in their guidance.
The first payment happens with the customer present, so the bank challenge appears in checkout. Renewals happen without them. Many renewals go through under exemptions or because the card was set up for off-session use. Some banks still demand authentication, and then the payment fails until the customer acts.
Stripe marks such an invoice as needing action and gives you a hosted invoice page where the customer can authenticate. That page is your recovery tool.
invoice.payment_failed or an action-required status, email the customer a link to the hosted invoice page or the customer portal.Test this with Stripe's test cards that force authentication. Run both outcomes, a passed challenge and a failed one, and confirm your database ends up in the right state each time. UK cards fall under UK rules rather than EU ones, but in practice most UK SaaS vendors with European customers build for 3D Secure everywhere.
Mobile subscriptions add another layer. If you sell access inside a React Native app, check the app store's rules on digital purchases before wiring Stripe into the app. Our app development team can map which flows belong on the web and which in the store.

Before launch, run every billing path in test mode using test clocks: sign up, trial end, renewal, upgrade, downgrade, failed payment, authentication challenge and cancellation. Confirm that your database matches Stripe after each one. Most billing bugs appear only on the second or third billing cycle.
Test clocks let you move a test customer forward in time, so you can watch a renewal or a trial ending in minutes instead of waiting a month. Use them for every scenario below.
A formal user acceptance pass helps here, because billing touches support, finance and product at once. Our UAT checklist for launch shows how to structure it.
Start with Checkout and the customer portal, two plans, a webhook handler with five events, and nothing custom. Add usage metering, multi-currency or invoicing extras only when a paying customer asks. A small billing system that is correct beats a clever one that is not. Founders with unusual needs, such as annual contracts with manual invoices, should plan for more custom work.
You can sell simple subscriptions with Stripe's no-code payment links and the customer portal. Once your app must unlock features based on plan, you need a developer for the webhook handler and plan table. That is a small, well-defined piece of work, not a large build.
Use test mode with Stripe's test API keys and test card numbers, plus test clocks to simulate renewals and trial endings. Test mode has its own customers, prices and webhook secrets, so repeat your configuration in live mode before launch and never reuse test price IDs.
Stripe retries failed deliveries, so the same event can arrive more than once. Store processed event IDs and skip repeats. If your endpoint was down, you can also resend events from the Dashboard. Fetching the current subscription from Stripe on each event keeps your database correct either way.
You cannot edit an existing price amount. Create a new price, then update each subscription to it, choosing whether to prorate. Tell customers before a rise takes effect, and check your own terms for notice requirements. We do not give legal advice on contract wording.
Stripe Billing saves months of work, but only if the plan model, trial rules and webhook handler are designed together. Axire Infotech is a lean studio in India working remotely with startups and businesses across Europe, with overlap on CET afternoons. We build these flows in React, Next.js, Node.js and Supabase, as part of our web development service.
See where billing sits among our full list of services and browse the projects we have built, or read more on the Axire blog. When you are ready to scope your own subscription flow, contact us with your plans and pricing. We reply to enquiries within 2 hours during business hours.
Let's discuss your project and create something amazing together.