Follow us:

Guides & How-Tos

How to Set Up Recurring Billing in Stripe for a SaaS Business

by Derek Voss

Setting up recurring billing in Stripe is one of the first infrastructure decisions a SaaS business has to get right. You can have a working subscription system live within a day. Stripe provides the products, prices, customer objects, and webhook events that handle the entire billing lifecycle — from a customer's first payment to their eventual cancellation. This guide covers the exact steps, common pitfalls, and long-term decisions that affect how well your billing holds up as you scale. For a quick reference, bookmark our overview on how to set up recurring billing in Stripe.

how to set up recurring billing in Stripe dashboard showing subscription products and pricing
Figure 1 — Stripe Dashboard showing recurring subscription products, pricing tiers, and billing cycle settings for a SaaS business.

Stripe has become the dominant payment infrastructure layer for SaaS companies worldwide. According to Stripe's entry on Wikipedia, the company was founded in 2010 and now processes payments for businesses ranging from solo founders to publicly traded enterprises. Its Billing product — the subscription-specific layer — launched as a dedicated suite designed to handle the complexity of recurring revenue at scale.

The platform charges 0.5% per recurring charge on top of standard card processing fees when you use Stripe Billing. That cost is predictable and models well against alternatives, especially at early revenue stages. Understanding the fee structure before you build helps you forecast unit economics without surprises later.

bar chart comparing Stripe Billing setup steps and transaction fee percentages versus alternatives
Figure 2 — Comparison of key metrics across Stripe Billing and competing recurring billing platforms, including fee structures and feature availability.

What Stripe's Subscription Model Actually Does

Stripe Billing is built on three core objects: Products, Prices, and Subscriptions. Understanding how they relate is essential before you write a single line of code.

A Product represents what you're selling — "Pro Plan," "Team Tier," or "Enterprise." A Price defines the cost and billing frequency attached to that product: $49/month, $499/year, or $0.005 per API call. A Subscription links a customer to one or more Prices and automates the charge cycle going forward.

The Billing Cycle Engine

Stripe's billing engine manages the entire subscription lifecycle without custom code on your end. It generates invoices, attempts payment, runs dunning logic for failed charges, and triggers webhook events at every state change. Your application receives those events and updates its own database in response. The payment logic lives entirely in Stripe. Your job is to react to it.

Metered vs. Licensed Pricing

Two pricing models dominate SaaS billing:

  • Licensed (seat-based): A fixed fee per billing cycle. Easiest to implement. One Price, one Subscription, one charge.
  • Metered: Charges based on usage you report via the API. You submit usage records before each billing cycle closes, and Stripe invoices accordingly.

Stripe supports both natively. Your choice depends on your business model. The technical complexity of metered billing is higher — plan for it if your pricing is consumption-based from the start rather than retrofitting it later.

What the Common Myths Get Wrong

Several misconceptions lead SaaS founders to either overbuild their billing stack or underprepare for real-world edge cases. The following three come up most often.

You Don't Always Need a Backend Developer

For basic monthly subscriptions, Stripe's hosted Checkout and no-code dashboard handle the UI and product setup. Non-developers can create products, set pricing, and issue test charges without writing code. Developers become necessary when you need custom plan logic, metered usage reporting, or integration with your application's permission system.

Stripe Doesn't Handle Tax Automatically

Stripe Tax exists as a paid feature, but it is not enabled by default. Sales tax and VAT compliance require explicit configuration. Selling to customers in tax-regulated regions without this in place creates real liability. Enable Stripe Tax in Dashboard settings before launching, or consult a tax advisor to assess your obligations by jurisdiction.

Failed Payments Still Require Your Work

Stripe's Smart Retries use machine learning to retry failed charges at statistically optimal times. That handles the payment attempt layer. But you still need to build the customer-facing side: dunning emails, account access changes during grace periods, and re-activation after recovery. Stripe fires the events. Your application has to act on them.

Pro tip: Configure your webhook endpoint to return a 200 status immediately and process events asynchronously — Stripe marks endpoints as failed if they don't respond within 30 seconds, and failed endpoints stop receiving events.

What You Need Before You Build

Before writing any integration code, confirm you have these in place. Missing one often causes hours of debugging that could have been avoided.

Required Accounts and API Keys

  • A Stripe account — free to create; fees apply per transaction
  • Publishable key and secret key from Dashboard > Developers > API Keys
  • A publicly accessible webhook endpoint URL, or Stripe CLI running locally
  • A server environment that can receive and process POST requests
  • Your webhook signing secret — generated when you register an endpoint in the Dashboard

Stripe CLI for Local Development

The Stripe CLI is the fastest way to test webhook handling without deploying to a staging server. Install it from Stripe's documentation, run stripe login to authenticate, then use stripe listen --forward-to localhost:3000/webhook to forward live Stripe events to your local machine. You can also trigger specific events manually with stripe trigger invoice.payment_failed to test your dunning flow without waiting for a real failure.

Your Tech Stack Matters

Stripe maintains official libraries for Node.js, Python, Ruby, PHP, Go, Java, and .NET. Use the official library for your language — it handles idempotency keys, typed error classes, and API versioning automatically. If you're wiring Stripe into a broader business automation stack, tools like those covered in our guide on how to use Zapier to connect your business apps without code can bridge Stripe events to your CRM, helpdesk, or analytics platform without writing custom webhook handlers for each destination.

How to Set Up Recurring Billing in Stripe: Step by Step

This section covers the standard integration path for a seat-based SaaS subscription. Metered billing follows a similar flow with additional usage reporting calls.

Step 1 — Create a Product and Price

In the Stripe Dashboard, navigate to Products > Add Product. Enter a name, optional description, and image. Under Pricing, select "Recurring" and set the amount and interval — monthly, yearly, or a custom period. Save the product. Stripe generates a Price ID formatted as price_XXXX. You'll reference this ID in all subscription creation calls.

To create products programmatically via the API:

const product = await stripe.products.create({ name: 'Pro Plan' });
const price = await stripe.prices.create({
  unit_amount: 4900,
  currency: 'usd',
  recurring: { interval: 'month' },
  product: product.id,
});

Step 2 — Create a Customer Object

Every subscription in Stripe requires a Customer object. Create one when a user registers:

const customer = await stripe.customers.create({
  email: user.email,
  name: user.name,
});

Store the returned customer.id in your user database immediately. Every future billing operation — subscriptions, invoices, payment method updates — references this ID. Losing the association between your user record and the Stripe customer ID is one of the more painful data problems to fix retroactively.

Step 3 — Launch a Checkout Session

Stripe Checkout handles the payment form, card validation, 3D Secure authentication, and browser-level security entirely. Create a session server-side and redirect the user to the returned URL:

const session = await stripe.checkout.sessions.create({
  customer: customerId,
  payment_method_types: ['card'],
  line_items: [{ price: 'price_XXXX', quantity: 1 }],
  mode: 'subscription',
  success_url: 'https://yourdomain.com/success?session_id={CHECKOUT_SESSION_ID}',
  cancel_url: 'https://yourdomain.com/pricing',
});
res.redirect(session.url);

Never redirect based on the success URL alone. Customers can reach the success page by typing the URL directly. Always confirm subscription status via the webhook before unlocking access.

Step 4 — Handle Webhooks

After payment, Stripe sends signed events to your webhook endpoint. The events that matter most for a subscription system:

  • checkout.session.completed — activate the subscription in your database
  • invoice.payment_succeeded — confirm ongoing payments each cycle
  • invoice.payment_failed — trigger dunning emails and begin grace period countdown
  • customer.subscription.updated — handle plan changes and proration
  • customer.subscription.deleted — revoke access and mark the account as churned

Always verify the webhook signature using stripe.webhooks.constructEvent() with your endpoint's signing secret. Processing unverified webhook payloads is a security vulnerability.

Step 5 — Test Before Going Live

Stripe provides test card numbers for simulating outcomes. Use 4242 4242 4242 4242 for a successful charge. Use 4000 0000 0000 9995 to simulate a declined card. Use 4000 0025 0000 3155 to trigger 3D Secure authentication. Run through every user-facing scenario — subscription creation, plan upgrade, plan downgrade, cancellation, and failed payment recovery — before switching your Stripe account to live mode.

Stripe Billing vs. Alternatives: Comparing the Trade-offs

Stripe Billing is not the only option for recurring revenue. The right platform depends on your team's technical resources, pricing model complexity, and geographic markets. Here's how the main options compare:

Feature Stripe Billing Chargebee Paddle Recurly
Setup complexity Moderate (API-first) Low–moderate Low Moderate
Metered billing Yes Yes Limited Yes
Tax compliance Add-on (Stripe Tax) Built-in Merchant of Record Add-on
Revenue recognition Stripe Sigma (paid tier) Built-in Basic Built-in
Transaction fee (billing layer) 0.5% per recurring charge 0.75% (Growth plan) 5% + $0.50 0.9% per transaction
Best for Technical teams Growing SaaS Global / non-technical Enterprise SaaS

Stripe's advantage is flexibility. Its API gives you control that hosted platforms don't. The tradeoff is that you build more. Teams that want out-of-the-box dunning workflows, revenue recognition reports, and a SaaS metrics dashboard often find Chargebee or Recurly faster to deploy. For a parallel look at a simpler billing workflow, see our guide on how to set up client invoicing in FreshBooks — it illustrates where a lightweight tool excels and where it runs short for recurring models.

Fixing the Most Common Stripe Billing Problems

Most billing issues fall into a small number of categories. Knowing where to look first saves significant debugging time.

Subscriptions Not Activating After Checkout

This almost always means a webhook isn't reaching your server. Open Dashboard > Developers > Webhooks > event logs. If the event shows a failed delivery, check that your endpoint URL is publicly accessible, returns HTTP 200 within 30 seconds, and doesn't require authentication headers Stripe isn't sending. During local development, confirm the Stripe CLI listener is running and forwarding to the correct port.

Duplicate Charges on Retry

Duplicate charges happen when you create multiple Checkout sessions or Payment Intents for the same user without idempotency keys. Pass an Idempotency-Key header on every API call that creates a charge. Use a stable identifier — such as a combination of user ID and a request-specific UUID — that stays the same on retries but differs across distinct operations. Stripe deduplicates requests with matching idempotency keys within a 24-hour window.

Proration Errors on Plan Upgrades

When a customer upgrades mid-cycle, Stripe prorates the difference by default. If your UI displays incorrect amounts, inspect the proration_behavior parameter in your subscription update call. Set it to none to skip proration entirely, or always_invoice to immediately charge the prorated difference rather than crediting it to the next invoice. The default behavior is create_prorations, which adds a line item to the next invoice.

Scaling Your Billing System Over Time

A billing system that works at 50 customers often breaks at 5,000 if you haven't thought through the edge cases. These investments pay off early.

Add a Customer Portal

Stripe's hosted Customer Portal lets subscribers manage their own plans, update payment methods, view invoice history, and cancel — without you building any UI. Enable it under Dashboard > Billing > Customer Portal and generate a portal session server-side when a user clicks "Manage Subscription." This feature alone eliminates a category of support tickets and improves net revenue retention by making it easier for customers to update expired cards instead of churning silently.

Implement Revenue Recovery Workflows

Smart Retries handle the payment attempt layer. Email outreach closes the gap. Set up automated emails triggered by invoice.payment_failed events. A standard dunning sequence: immediate notification with a payment update link → 3-day reminder → 7-day final warning → access suspension. Each email should link directly to the Customer Portal for a frictionless fix. Most teams recover 20–30% of initially failed payments through this sequence.

Reporting and Revenue Recognition

Stripe provides built-in revenue reporting under Dashboard > Revenue Recognition on paid plans. For SaaS, the metrics that matter are MRR, churn rate, average revenue per user (ARPU), and LTV. Connect Stripe to a BI tool or query your data with Stripe Sigma's SQL interface to build custom dashboards. Establishing this reporting infrastructure early — before your subscriber count makes manual analysis impossible — is one of the highest-return investments a growing SaaS team can make.

Frequently Asked Questions

How much does Stripe charge for recurring billing?

Stripe charges 2.9% + $0.30 per successful card charge as its base processing fee, plus an additional 0.5% per recurring charge when you use Stripe Billing. For invoices, Stripe adds 0.4% per paid invoice if you use its invoice-sending feature. These fees stack, so model them carefully against your pricing before launch.

Can you set up Stripe subscriptions without a developer?

Yes, for basic use cases. Stripe's no-code hosted Checkout and Dashboard-based product creation let non-technical founders launch monthly subscriptions without writing code. Custom logic — metered pricing, per-seat billing, mid-cycle upgrades, and database-driven access control — requires developer involvement. Start with hosted Checkout and expand from there as your needs grow.

What happens when a subscription payment fails in Stripe?

Stripe automatically retries the charge using Smart Retries, which uses machine learning to pick optimal retry windows based on failure reason and time of day. If all retries fail, Stripe marks the invoice as uncollectible and fires a customer.subscription.deleted or invoice.payment_failed event depending on your dunning settings. You configure how many retries occur and how many days pass before cancellation in Dashboard > Billing > Subscriptions and emails.

Final Thoughts

Your billing system is foundational infrastructure — get it right early and it runs quietly in the background for years. Start with Stripe's hosted Checkout and a minimal webhook handler, verify your end-to-end flow in test mode, then add the Customer Portal and dunning sequences before your first hundred paying customers. Each layer you add protects revenue and reduces operational overhead. If you're ready to move, open your Stripe Dashboard, create your first product, and run a test subscription through to completion today.

About Derek Voss

Derek Voss worked as an operations lead at two different B2B SaaS startups before moving into software review writing, where his job was picking the tools that would actually get used by non-technical teams under real budget constraints. That experience means less time comparing feature-list PDFs and more time asking whether a five-person marketing team will actually adopt a tool or quietly go back to spreadsheets after week two. At Gleanster, Derek writes buying guides and how-to content aimed at the moment right before someone commits to a new tool -- what to check, what to ignore, and which questions actually predict whether a switch will stick.