All posts
Product design

Stripe Billing for SaaS: Plans, Trials and Webhooks Done Right

Stripe billing for SaaS done right: modeling plans and prices, trials, Checkout, webhooks, entitlements, metered usage and failed payments, step by step.

By Mehdi Hassan6 min read

The short answer

Stripe billing for a SaaS app works best when Stripe owns payments and subscriptions while your database owns what each workspace is allowed to do. Model plans as products and prices, start subscriptions through Checkout, sync state through verified webhooks, and gate features on a local entitlements record. Never grant access from a browser redirect alone.

Key takeaways

  • Stripe is the source of truth for payments; your database is the source of truth for access.
  • Webhooks drive every state change. Verify signatures and make handlers safe to run twice.
  • Attach subscriptions to the workspace, not the user, or team billing becomes a rewrite.
  • Decide early whether trials need a card. It changes your funnel, emails and webhook handling.
  • Use Stripe's hosted Checkout and Customer Portal first; build custom billing screens later.

Part of Full-Stack Product Engineering for Startups: From Figma to Production

How do you implement Stripe billing in a SaaS app?

You implement Stripe billing in a SaaS app by modeling your plans as Stripe products and prices, sending customers to Checkout to subscribe, listening to webhooks to keep your database in sync, and checking a local entitlements record before enabling any feature. Stripe handles cards, invoices and retries; your app handles access.

This is the engineering side of billing. The design side, from plan pages to paywalls and usage limits, is in our guide to in-app billing and upgrade UX, and the two should be planned together. Both are part of our hub on full-stack product engineering for startups.

  1. Model plans and prices

    Create a product per plan and a price per billing interval and currency. Store Stripe price IDs in config, not scattered through code.

  2. Link customers to workspaces

    Create one Stripe customer per workspace or organization and store its ID on the workspace record.

  3. Subscribe through Checkout

    Create a Checkout Session on the server for the chosen price and redirect the user. Stripe handles payment details, tax collection options and authentication.

  4. Sync with webhooks

    Handle subscription and invoice events to update your local subscription and entitlements records.

  5. Gate features locally

    Every feature check reads your own entitlements record, never the Stripe API on each request.

  6. Hand off self-service

    Link to the Stripe Customer Portal so customers can change plans, update cards and download invoices.

How should you model plans, prices and entitlements?

Model each plan as a Stripe product with one price per interval, such as monthly and annual, and keep a separate entitlements map in your code that says what each plan includes. Separating price from permission lets you change prices, run discounts or grandfather old customers without touching feature checks.

Concept

Lives in

Example

Product

Stripe

Pro plan

Price

Stripe

Pro, billed monthly, in USD

Subscription

Stripe, mirrored locally

Workspace X on Pro, renews next month

Entitlements

Your database

Up to N seats, API access on, SSO off

Usage

Your database, reported to Stripe if metered

Reports generated this period

Stripe also offers its own entitlements feature that maps products to features. It's worth evaluating, but keep a local copy either way, because your app needs to answer "can this workspace do X" instantly, even if Stripe is slow to respond.

Which Stripe webhooks does a SaaS app need?

A SaaS app needs webhooks for the moments a subscription starts, changes, renews, fails or ends. At minimum, handle a completed Checkout Session, subscription created, updated and deleted events, and invoice paid and payment failed events. Those cover most of the subscription lifecycle.

  • Checkout completed: link the new subscription to the workspace that started it.
  • Subscription created or updated: store the plan, status, period end, trial end and cancellation flag, then recompute entitlements.
  • Subscription deleted: move the workspace to the free tier or a locked state.
  • Invoice paid: confirm the renewal and clear any past-due warning.
  • Invoice payment failed: flag the workspace as past due and start your in-app and email reminders.
Writing webhook handlers that don't break

Verify every webhook's signature with your endpoint secret before reading it, and reject anything that fails.

Make handlers idempotent: Stripe can send the same event more than once, and events can arrive out of order. Store processed event IDs, and when an event concerns a subscription, fetch the subscription's current state from Stripe and save that, rather than applying the event as a delta.

Respond quickly with a success status and move slow work, such as sending emails or recalculating usage, to a background job. Test with the Stripe CLI, which can forward events to your local machine and trigger test events on demand.

How should SaaS trials work with Stripe subscriptions?

SaaS trials in Stripe work by creating a subscription with a trial period, with or without collecting a payment method up front. Card-required trials convert differently from card-free trials, so decide based on your sales motion and design the emails and in-app reminders around the trial end.

Pros

  • Card-free trial: lower friction, more people start
  • Card-free trial: works well for product-led growth with strong activation
  • Card-required trial: users who start have shown more intent, and renewal is automatic

Cons

  • Card-free trial: needs clear prompts to add a card before the trial ends
  • Card-free trial: needs a defined state for trials that end with no payment method
  • Card-required trial: fewer people start, and some will dispute charges they forgot about

Whichever you choose, show the trial's end date inside the product, send a reminder before it ends and make cancellation easy. Check the current rules for the regions you sell in, because subscription and cancellation regulations vary.

How do you add metered or usage-based billing?

Add usage-based billing by recording usage events in your own database first, then reporting them to Stripe's meters so invoices reflect actual use. Keeping your own record lets you show live usage in the product, enforce limits and reconcile any disagreement with what Stripe billed.

Most SaaS products do best with a hybrid: a base subscription that includes an allowance, plus usage charges above it. It keeps invoices predictable for buyers while still charging fairly for heavy use. Show usage clearly in a billing section of your settings pages, with warnings before a limit, not only after.

How do you handle failed payments and plan changes?

Handle failed payments with Stripe's automatic retries and reminder emails, plus your own in-app banner for workspace admins, and a defined grace period before you restrict access. Handle plan changes by letting Stripe calculate proration and updating entitlements from the resulting webhook.

Restrict carefully. Locking a whole team out on the first failed payment punishes users who can't fix billing. A softer pattern is a banner for admins, then read-only access, then a lock. Downgrades need equal care: decide what happens to seats, projects or data above the new plan's limits before a customer asks.

What does a reliable Stripe billing architecture look like?

A reliable architecture keeps billing logic in one module: one place creates Checkout Sessions and portal links, one webhook route processes events, and one function answers what a workspace is entitled to. Every other part of the app calls those functions.

Type the whole flow, from Stripe event payloads to your entitlements, as we argue in TypeScript for startups, and keep billing tables in the same Postgres database as your workspaces. The wider structure, including where authorization lives, is in building a SaaS app with Next.js.

Frequently asked questions

Should you use Stripe Checkout or build a custom payment form?
Start with Stripe Checkout. It handles card entry, wallets, local payment methods, strong customer authentication and tax collection options, and Stripe maintains it as rules change. Build a custom payment form with Stripe Elements only when you have a measured reason, such as a checkout embedded deep in onboarding, and accept that you then own more of the edge cases.
How do you test Stripe billing before going live?
Use Stripe's test mode with its published test cards, including cards that decline or require authentication. Use the Stripe CLI to forward webhooks to your local app and trigger events. Stripe's test clocks let you simulate time passing, so you can check trial endings, renewals and failed payment retries without waiting days or weeks.
Should a subscription belong to a user or a workspace?
For B2B SaaS, a subscription should belong to the workspace or organization. Companies pay for teams, change admins and expect billing to survive when the person who signed up leaves. Attaching subscriptions to individual users works for consumer apps but becomes a painful migration once a B2B product adds teams.
Do you need a billing platform on top of Stripe?
Usually not at first. Stripe Billing covers subscriptions, trials, proration, invoices, retries and usage-based pricing for most early SaaS products. Extra billing platforms become useful with complex contracts, many currencies, sales-negotiated deals or advanced revenue reporting. Start with Stripe directly and add tools when finance or sales workflows demand them.

· CEO & Design Director

Copywriter, designer and developer, and founder of Designify Studio. Over five years, 60+ projects across 14+ industries, for startups that have raised $300M+.

Want us to do this for you?

We take craft seriously over at Designify Studio. We do deep research and do what we do best - pay attention to the smallest details and make sure we speak to the right audience.

Schedule Call