
Custom CRM & Micro-SaaS
SaaS Subscription Billing With Stripe: A 2026 Setup Guide
Set up SaaS subscription billing with Stripe: October 2026 fees vs Paddle, trials, proration, usage billing, dunning, tax, the customer portal and webhooks.
By Issa Badran · Published · 10 min read
To run SaaS subscription billing on Stripe, you set up products and prices, create subscriptions through Checkout or the API, let Stripe handle renewals, retries and the customer portal, and keep your app in sync through webhooks. As of October 2026, Stripe charges 2.9% + 30¢ for domestic cards plus 0.7% of Billing volume on its pay-as-you-go plan, while Paddle charges 5% + 50¢ but acts as merchant of record and takes on sales tax and VAT. Most of the engineering work is in webhooks: they decide when a customer gains or loses access. This guide covers fees, plans, trials, proration, usage billing, dunning, tax, the portal and the webhooks you can't skip.
Key Takeaways
- As of October 2026: Stripe is 2.9% + 30¢ per domestic card charge plus 0.7% for Billing; Paddle is 5% + 50¢ per checkout transaction, including merchant-of-record services.
- Stripe Tax calculates and helps file tax, but it is not a merchant of record; tax liability stays with you.
- Stripe's legacy trial parameters are marked Legacy in favor of "trial offers," and Stripe now recommends Metronome for new usage-based integrations.
- Smart Retries and the hosted customer portal cover most dunning and self-service needs; don't rebuild them.
- Grant and revoke access from webhooks, deduplicate by event ID and never rely on event order.
How Stripe Subscription Billing Works
In plain English, Stripe Billing is a recurring-invoice machine. You define products (what you sell) and prices (how much and how often). When a customer signs up, Stripe creates a subscription, which generates an invoice each billing period and tries to collect payment. Your app doesn't run the schedule; it listens for events Stripe sends to your webhook endpoint and updates who has access.
That split matters. Stripe is the source of truth for money. Your database is the source of truth for product access, kept in sync by webhooks. If you're designing the whole platform around this, our pillar guide on how to build a SaaS platform shows where billing fits among the other components.
Fees as of October 2026: Stripe vs Paddle
All figures below are list prices as of October 2026 from Stripe's pricing page and Paddle's pricing page. Both change periodically.
| Fee | Stripe | Paddle |
|---|---|---|
| Headline transaction fee | 2.9% + 30¢ per domestic card charge | 5% + 50¢ per Checkout transaction (pay-as-you-go) |
| International cards | +1.5% | † |
| Currency conversion | +1% | † |
| Subscription billing | 0.7% of Billing volume (pay-as-you-go; one-off invoices excluded), or a pay-monthly plan from $620/month on a 1-year contract | † |
| Sales tax and VAT | Stripe Tax Basic: 0.5% per transaction where registered (no-code), or $0.50 per transaction via API with 10 calculation calls included, then 5¢ per call. Tax Complete from $90/month (1-year contract) | Paddle collects, files and remits as merchant of record |
| One-off invoicing | Invoicing Starter: 0.4% per paid invoice | † |
| Who is the legal seller | You | Paddle |
| Fraud, chargebacks, buyer support | You (with Stripe's tools) | Paddle |
† We don't list Paddle figures for international cards, currency conversion, subscription billing or one-off invoicing; check Paddle's pricing page for how those apply to your account.
Illustrative arithmetic, not a benchmark: on a $100 monthly subscription paid with a US card, Stripe's listed fees come to $3.20 for card processing plus $0.70 for Billing, or $3.90, before tax tools and international surcharges. Adding Stripe Tax's no-code rate where you're registered adds $0.50. Paddle's listed fee on the same transaction is $5.50, with tax filing, fraud and chargebacks included. The right comparison is total cost, including your own time and any accountant fees for tax filing.
Plans and Pricing Models
Common SaaS pricing models include flat-rate, per-seat, tiered and usage-based, and Stripe's billing products are built to handle them. Choose the model that tracks the value customers get, then keep the number of plans small. Each extra plan adds upgrade paths, proration cases and support questions.
If you're considering per-seat pricing, it's worth understanding how it feels from the buyer's side. Our breakdown of per-seat CRM pricing and its true cost shows why some customers resent it as teams grow.
Free Trials
Stripe's documentation now marks the older trial parameters (trial_end and trial_period_days, which allow trials up to 730 days) as Legacy, in favor of a newer "trial offers" approach. If a trial starts without a payment method, you can configure it to cancel, pause or create an invoice when it ends (Stripe Docs). Check the current trial documentation before you build, since new integrations should follow the recommended path.
Stripe sends customer.subscription.trial_will_end three days before a trial ends (Stripe Docs). Use it to prompt users to add a card or confirm they want to continue.
Proration for Upgrades and Downgrades
Proration is how Stripe charges fairly when someone changes plans mid-cycle. By default, proration_behavior is create_prorations: Stripe calculates credit for unused time on the old price and a charge for the new price, to the second, and adds them to the next invoice. The alternatives are always_invoice, which bills the difference immediately, and none (Stripe Docs).
Two details catch teams out. Usage-based charges aren't prorated. And negative prorations, such as credit from a downgrade, aren't automatically refunded (see Stripe's proration docs for how credits are applied). Decide your downgrade policy and explain it on your pricing page.
Usage-Based Billing
Usage-based billing charges for what customers consume: API calls, messages sent, AI tokens. Seats are usually simpler, handled as a quantity on a regular price.
For metered usage, the guidance changed recently. Stripe now recommends Metronome, "now part of Stripe," for new usage-based integrations, while Billing Meters remain supported for existing integrations. Stripe's Billing page notes that Metronome is not included in Stripe Billing (Stripe Docs), so confirm its pricing separately. Whatever you use, record usage events in your own database too, so you can show customers what they're being billed for.
Dunning: Recovering Failed Payments
Dunning is the process of retrying failed payments and nudging customers to update their card. Stripe's Smart Retries handles the retry schedule. Stripe recommends a default of 8 tries within 2 weeks, with configurable windows from 1 week to 2 months. Hard declines, such as lost_card or stolen_card, aren't retried until the customer adds a new payment method. When retries run out, you can cancel the subscription, mark it unpaid, leave it past due or pause it (Stripe Docs).
Practitioner guidance:
- Turn on Smart Retries before writing any custom retry logic.
- Decide what "past due" means in your product: full access, read-only or a warning banner.
- Show an in-app prompt with a direct link to update payment details.
- Choose what happens when retries end, and make sure your webhooks act on it.
Sales Tax and VAT: Stripe Tax vs Merchant of Record
This is one of the biggest structural decisions in SaaS billing. With Stripe, you are the seller. Stripe Tax monitors thresholds, helps with registration, calculates tax and can file "directly or through integrated partners," and it supports US sales tax and some local taxes. But Stripe Tax is not a merchant of record (Stripe Tax docs). The liability stays with your business.
A merchant of record (MoR) is the legal seller of your product. Paddle describes the role as taking responsibility for the sale, including tax, PCI and compliance, refunds and chargebacks, and fraud, while a payment service provider handles only the transaction (Paddle). That's the vendor's own definition, but it captures the trade-off.
| Situation | Leans toward |
|---|---|
| Selling mainly to US businesses, with an accountant handling sales tax | Stripe Billing plus Stripe Tax |
| Selling to consumers or businesses in many countries | Merchant of record such as Paddle |
| Need full control of checkout, pricing logic and customer data | Stripe |
| Small team with no appetite for tax registrations and filings | Merchant of record |
| Thin margins on high-volume, low-price plans | Model both carefully; per-transaction fixed fees weigh more on small charges |
An MoR may be cheaper overall once you count the cost of registering and filing VAT in multiple countries yourself. Get advice from a tax professional before you decide.
The Customer Portal
Stripe's hosted customer portal lets customers update payment methods and tax IDs, switch or cancel plans, and view and pay invoices. It has limits: it can't be embedded in an iframe, plan switching supports up to 10 products, and subscriptions with usage-based prices or multiple products can be canceled but not updated in the portal (Stripe Docs). If those limits don't block you, use it instead of building your own billing settings page.
Webhooks Your SaaS Must Handle
Webhooks are messages Stripe sends to your server when something happens. They're how your app learns that a payment succeeded or a subscription ended. These are the subscription and invoice events covered in Stripe's subscription webhook docs:
| Event | When it fires | What your app should do |
|---|---|---|
customer.subscription.created |
When the subscription is created (status may be incomplete if the customer must authenticate) |
Store subscription ID, price and status |
customer.subscription.updated |
When a subscription starts or changes, such as renewing, applying a coupon or changing plans | Update plan limits and access to match the new status; revoke access if it becomes canceled or unpaid |
customer.subscription.deleted |
When a customer's subscription ends | Revoke paid access or move the tenant to a free tier |
customer.subscription.trial_will_end |
Three days before a trial ends | Remind the user to add payment details |
invoice.created |
A new invoice is created | Respond with 2xx promptly; add any extra line items |
invoice.paid |
An invoice is paid | Retrieve the subscription, confirm its status is active, then provision access |
invoice.payment_failed |
Payment for an invoice failed | Notify the customer, let Smart Retries run and prompt them to update their payment method |
invoice.payment_action_required |
The customer must authenticate to complete payment | Ask the customer to complete authentication |
invoice.finalization_failed |
The invoice couldn't be finalized | Fix the cause; payment can't be collected until it's resolved |
If you use Stripe Checkout to start subscriptions, see Stripe's Checkout docs for the events it sends.
Three details from Stripe's subscription webhook docs deserve attention. If your endpoint doesn't successfully respond to invoice.created, Stripe delays finalizing the invoice for up to 72 hours. After invoice.paid, confirm the subscription status is active before extending access. And subscriptions left incomplete because the first payment wasn't completed expire after 23 hours.
Handling Webhooks Safely
Stripe's general webhook documentation sets out the rules:
- Verify signatures. Stripe signs each event with HMAC-SHA256, with a default tolerance of five minutes to block replayed events.
- Return 2xx fast. Acknowledge the event, then do the real work in a background queue.
- Don't rely on order. Events can arrive out of sequence.
- Deduplicate by event ID. The same event can arrive more than once, and in live mode Stripe retries failed deliveries for up to three days.
An illustrative table for recording events:
-- Illustrative only
create table stripe_events (
event_id text primary key, -- Stripe's evt_ ID, used to deduplicate
type text not null, -- e.g. 'invoice.paid'
payload jsonb not null,
received_at timestamptz not null default now(),
processed_at timestamptz, -- null until the worker finishes
error text
);
-- On receipt: insert, and skip if already seen
insert into stripe_events (event_id, type, payload)
values ($1, $2, $3)
on conflict (event_id) do nothing;
In practice, because events can arrive out of order, it helps for the background worker to fetch the latest subscription from Stripe's API before updating your database, rather than trusting the snapshot inside an older event. That fits Stripe's own advice to retrieve the subscription and confirm it's active after invoice.paid (Stripe Docs).
Auto-Renewal and Cancellation Rules
ROSCA and state auto-renewal laws set requirements for subscriptions; check current FTC guidance and state rules with a lawyer.
Limitations and When Stripe Billing Isn't the Right Choice
Stripe Billing isn't always the best fit:
- Global tax burden. If you sell to many countries and don't want tax liability, an MoR such as Paddle may cost less overall despite higher listed fees.
- Complex usage pricing. Products with heavy metered billing should evaluate Metronome or a dedicated usage-billing tool, and price it separately from Stripe Billing.
- Portal limits. Multi-product or usage-based subscriptions can't be updated in the hosted portal, so you may need your own plan-change screens.
The opposite mistake is more common: building custom dunning flows or billing pages when Smart Retries and the hosted portal already cover the need. Start with Stripe's defaults and customize only where they block you.
Billing as Part of Your Platform
Billing touches tenancy, permissions and your data model, so design it alongside them: a subscription record per tenant, plan limits read from your own database and webhooks as the only path that changes access. Our guides to multi-tenant SaaS architecture and CRM data model design cover those neighboring pieces. For help wiring Stripe into a custom CRM or SaaS product, Robustech's custom CRM and SaaS development team builds billing integrations you own.



