Use Stripe Billing with Checkout for the purchase flow, webhooks for lifecycle events, and Entitlements for feature gating. If usage-based pricing is on your roadmap, build on Metronome instead of legacy Billing Meters. The first engineering steps: create your Products and Prices, wire a Checkout session, stand up a webhook endpoint with signature verification and idempotent handlers, persist every Stripe ID you get back, and schedule reconciliation before you ever take a live payment.
TL;DR:
- Use one Product with multiple Prices to represent different billing cycles, and create separate Products only when feature sets differ significantly.
- Build the Checkout session with proper webhook handling, verifying signatures, and store all Stripe IDs before activating customer access.
- Manage feature access through Stripe Entitlements by attaching Features to Products and maintaining local, synchronized records for fast authorization.
- Prefer Metronome over Billing Meters for usage-based pricing to take advantage of real-time metering, event-based usage tracking, and simplified migration later.
- Schedule thorough testing of full lifecycle events, webhook retries, and invoice finalization failures before deploying the Stripe integration into production.
Table of Contents
- Product Modeling: How to Structure Products and Prices for a SaaS Plan
- How Do You Set Up a Checkout Session for Subscriptions?
- What Are Stripe Entitlements and How Do They Handle Feature Access?
- Should You Use Billing Meters or Metronome for Usage-Based Pricing?
- How Does Stripe Handle Tax and Revenue Recognition?
- What Should You Test Before Taking a Stripe Integration Live?
- Integration Checklist: From Setup to Launch
- What I'd Tell Any Founder Before They Touch the Stripe API
- How I Can Help With Your Stripe Integration
- FAQ
Product Modeling: How to Structure Products and Prices for a SaaS Plan
Every plan you sell should map to one Stripe Product, with Prices attached to represent cadence and amount. A monthly and annual version of the same plan are two Prices on one Product, not two Products. Naming matters more than most teams expect: use a lookup_key scheme that survives migrations (plan_pro_v2 beats a raw price ID hardcoded in your app), because Stripe lets you retire and replace Prices without breaking references if you build against the key instead of the ID.
The decision that trips people up is when to split a Product versus add a Price:
- Use multiple Prices on one Product when the offering itself doesn't change, just the cadence or amount (monthly vs. annual, USD vs. EUR).
- Use separate Products when the feature set differs, because entitlements attach at the Product level and you want clean boundaries for what each plan unlocks.
- For flat-rate plans, one Price per tier is enough. For per-seat, use Stripe's quantity field on the subscription item rather than inventing your own multiplier logic.
- For tiered or hybrid pricing (a base fee plus usage), model the base as a standard Price and layer usage separately, covered below.
Stripe's own SaaS integration guide treats these as distinct design areas, not one billing switch you flip. Get the catalog structure right early. Reworking Product boundaries after customers are subscribed is a migration project, not a config change.
How Do You Set Up a Checkout Session for Subscriptions?
The purchase flow for a flat-rate or per-seat SaaS product is a solved problem, and Stripe's own startup guide for SaaS subscriptions lays out the exact sequence: create a Product and recurring Price, generate a Checkout Session in mode=subscription, redirect the customer to Stripe-hosted Checkout, then let webhooks handle everything that happens after.
The flow breaks down like this:
- Server side: create a Checkout Session using the Price ID for the plan the customer selected, passing a
billing_cycle_anchorif you need billing dates to align to a fixed day (common for annual contracts invoiced on the 1st). - Client side: redirect the browser to the Checkout URL Stripe returns. Do not build a custom card form unless you have a specific reason to; hosted Checkout handles 3D Secure, wallet payments, and localized payment methods for you.
- Success and cancel pages: Checkout redirects back to URLs you specify, but treat those as UX signals only, not proof the subscription is active.
- Webhooks: the real state changes arrive through
checkout.session.completed, followed byinvoice.created,invoice.finalized,invoice.paid, and, when a card fails,invoice.payment_failed. Verify the signature on every event, make your handler idempotent (Stripe retries deliveries), and store the customer, subscription, and invoice IDs the moment they arrive.
Pro Tip: Never grant access on the Checkout success redirect alone. A user can land on that page and then close the tab before the webhook fires, or the webhook can arrive seconds later. Gate access on invoice.paid, not on the browser redirect.
What Are Stripe Entitlements and How Do They Handle Feature Access?
Entitlements are the layer that turns a Stripe Product into an actual permission in your app, and they're the piece most homegrown billing integrations get wrong. Instead of checking "does this customer's plan name equal 'pro'" in application code, you create Features in Stripe, attach them to Products, and let Stripe tell you when access changes.
The mechanism is an event: entitlements.active_entitlement_summary.updated fires whenever a customer's entitlements shift, whether from an upgrade, a cancellation, or a failed renewal. That event, plus the List Active Entitlements endpoint for reconciliation, becomes your source of truth.
- Use
lookup_keyvalues on Features that mirror your internal feature flags exactly, so mapping is a one-to-one lookup, not a translation table. - Persist entitlements locally for fast authorization checks on every request, but treat the Stripe record as authoritative and sync on the event.
- Build grant and revoke as idempotent operations. A duplicate webhook delivery should never double-grant or leave a flag stuck on.
- On service startup or after any suspected gap, call List Active Entitlements to reconcile rather than trusting your local cache blindly.
Pro Tip: Run the entitlement check at the API gateway or middleware layer, not scattered inside individual route handlers. One centralized check means one place to fix when Stripe changes how a Feature is structured.
Should You Use Billing Meters or Metronome for Usage-Based Pricing?
Pick Metronome for any new usage-based work. Stripe directs new integrations toward Metronome rather than its own legacy Billing Meters, and the feature gap explains why: Metronome handles real-time metering, prepaid credits, enterprise rate cards, and dimensional pricing, which Billing Meters was never built to carry. If you're already on Billing Meters, know that migrating later means re-architecting how usage events flow into billing, so the earlier you decide, the cheaper that decision is.
Whichever platform you pick, the design constraint that matters most sits outside Stripe entirely: where does metering truth live. That's an architectural call with real consequences for disputes and replay, and it should shape your event pipeline before you write the first line of billing code.
- Record every usage event as immutable data: event ID, customer ID, measured quantity, timestamp, and the pricing version active at the time.
- Keep that trail queryable independent of Stripe, so a billing dispute doesn't require digging through Stripe's dashboard to find out what actually happened.
- Treat pricing version as a first-class field. A rate card change mid-cycle is the single most common source of "why doesn't this invoice match what I expected" tickets.
- If you're staying on Billing Meters for now, budget time for the eventual move. Interoperability between the two systems is limited, not seamless.
How Does Stripe Handle Tax and Revenue Recognition?
Tax and revenue are two separate line items in Stripe's model, and conflating them is a common invoicing mistake. Stripe calculates tax separately from the subscription price, and that tax amount is a liability, not recognizable revenue. Revenue gets recognized against the invoice line item over the service period it covers, following Stripe's own revenue recognition methodology.
The operational risk hiding here is invoice.finalization_failed. A subscription can stay fully active while its invoice fails to finalize, which means you're serving a customer you can't yet collect from. That's a distinct failure mode from a declined card, and it needs its own monitor and its own repair path, not a shared alert with payment failures.
- Pick
collection_methoddeliberately:charge_automaticallyfor self-serve SaaS,send_invoicefor enterprise contracts paid by wire or purchase order. - The collection method changes which lifecycle events fire and when, so your reconciliation logic needs to branch on it.
- Design invoice line items with your finance team's revenue recognition rules in mind before launch, not after your first audit.
An invoice sitting in finalization_failed for days is one of the more expensive silent failures in a Stripe integration, because everything downstream still looks normal until someone in finance asks why revenue and active subscriptions don't line up.
What Should You Test Before Taking a Stripe Integration Live?
Stripe's own subscription testing guidance points teams toward sandbox simulations that exercise the full lifecycle, not just a happy-path signup. Build your test matrix around these cases before you touch production:
- First payment success and first payment failure (expired card, insufficient funds).
- Successful renewal and failed renewal, including what happens to entitlements on each.
- Trial-to-paid conversion, and trial expiration with no card on file.
- Upgrade and downgrade mid-cycle, checking proration lands where you expect.
- Duplicate webhook delivery and out-of-order delivery.
- Invoice finalization failure, isolated from payment failure.
Pro Tip: Log the raw webhook payload before you parse it, even in production. When a reconciliation mismatch shows up three weeks later, the raw event is the only record that tells you what Stripe actually sent versus what your handler assumed.
Beyond the test matrix, three practices carry the integration long-term: idempotency keys on every mutating call, signature verification on every webhook with no exceptions for "trusted" internal calls, and a periodic reconciliation job comparing your local subscription state against Stripe's. Alert on webhook failure rate, on any invoice.finalization_failed, and on reconciliation mismatches, since each one signals a different class of bug.

Integration Checklist: From Setup to Launch
Run this roughly in order. Skipping steps to move faster almost always costs more time later, in the reconciliation debugging you'll do instead.
- Create the Stripe account, set up Products and Prices matching your finalized pricing model.
- Decide flat-rate, per-seat, usage-based, or hybrid, and lock the catalog structure before writing checkout code.
- Build the Checkout Session flow (
mode=subscription) and success/cancel pages. - Stand up the webhook endpoint with signature verification and idempotent handlers.
- Persist Stripe customer, subscription, and invoice IDs against your internal account record.
- Map Features to entitlements and build the provisioning and de-provisioning handlers.
- Enable the customer portal for self-serve upgrades, downgrades, and cancellations.
- Run the full test matrix in sandbox, including proration and duplicate webhook cases.
- Schedule the reconciliation job and configure tax collection if applicable.
- Flip to live mode with monitoring already in place, not added after launch.
What I'd Tell Any Founder Before They Touch the Stripe API
Reliable billing beats clever billing. Checkout plus Entitlements handles the vast majority of SaaS pricing needs, and bespoke usage metering built early is usually solving a problem you don't have yet. Keep billing identity separate from application login. Your Stripe customer ID and your user's auth account are two different records, linked by a stable internal mapping. When that mapping gets tangled with login logic, every future billing change becomes a risk to authentication.
If a prototype's payment flow is already breaking core signups, patching it rarely holds. A fixed-scope rebuild, two to four weeks, usually costs less than months of firefighting webhook bugs in code nobody fully understands.
— Hanad Kubat
How I Can Help With Your Stripe Integration
I am an alternative to hiring an agency to wire up billing: a senior engineer, a fixed price, and you own the code from the first commit. I build the Checkout flow, the webhook endpoint with signature verification, entitlement mapping, and reconciliation, then hand it over with no ongoing retainer required. Scope gets frozen at kickoff, so there are no surprise invoices halfway through.
Builds run from €12,000, two to four weeks, milestone by milestone, whether you're adding Stripe Billing to a first real version of your product or rebuilding a prototype where payments already broke. If you want a fixed-price quote on getting billing production-ready, that is available via my website: Hanadkubat.
FAQ
What Is the Best Billing System for SaaS?
For most subscription SaaS products, Stripe Billing paired with Checkout and Entitlements covers flat-rate, per-seat, and hybrid pricing without custom infrastructure. Add Metronome only once usage-based pricing becomes a real requirement, since it's built for that case specifically.
What Is the Best Payment Gateway for SaaS?
Stripe is the dominant choice for SaaS specifically because Billing, Checkout, Entitlements, and Metronome are designed to work together rather than as separate bolted-on tools. That integration between products is what saves engineering time versus stitching a generic payment gateway to a custom subscription engine.
Does Elon Musk Own Part of Stripe?
Elon Musk co-founded X.com, which merged with Confinity to become PayPal, and Stripe is a separate company founded later by Patrick and John Collison. Musk has no known ownership stake in Stripe tied to that history.
How Much Does Stripe Billing Cost?
Stripe's billing fees are usage-based and listed directly on Stripe's own pricing page, since rates vary by region, payment method, and volume. If you want a fixed-price quote for building the integration itself rather than Stripe's processing fees, current pricing for that work is available at Hanadkubat.
