▸ Billing Systems Guide · 2025

SaaS Billing Systems Guide

TL;DR

A production SaaS billing system has six components: Stripe Checkout (payment collection), Stripe Subscriptions (recurring billing), Webhook handlers (database sync), Billing Portal (self-service), Dunning sequences (revenue recovery), and Feature gating (plan enforcement). Webhooks — not the checkout redirect — are the authoritative source of subscription state.

Billing is non-negotiable in a SaaS MVP. A product without billing is a demo. 4Byte Agency integrates the full billing stack in week 3 of every 28-day build.

Read time:18 min
Level:Technical
Platform:Stripe
By:4Byte Agency
3–5Days
To integrate Stripe billing in a SaaS MVP
15%MRR
Average revenue recovered through dunning logic
2.9%+ 30¢
Stripe processing fee per successful transaction
135+Markets
Countries Stripe supports for SaaS payment collection

▸ Billing Components

Six components of a complete SaaS billing system

Billing is not a single integration — it's six interconnected components. Missing any one of them creates revenue leakage, customer experience failures, or security vulnerabilities.

💳01

Payment Collection

The interface where customers enter payment details. Stripe Checkout is the fastest, most secure implementation — a Stripe-hosted page that handles card validation, 3D Secure, and PCI compliance automatically.

Tools

Stripe CheckoutStripe Elements (embedded)Payment Intents API
Week 3 of MVP build
🔄02

Subscription Management

The engine that manages recurring billing — creating subscriptions, handling trial periods, processing plan upgrades and downgrades, and scheduling cancellations. Stripe handles the recurring charge logic; your code handles the business rules.

Tools

Stripe SubscriptionsStripe Prices APIStripe Trial Management
Week 3 of MVP build
03

Webhook Event Handler

The critical sync layer between Stripe and your database. Every subscription state change — payment success, failure, cancellation, upgrade — is delivered as a webhook event. Your handler must process these events and update your database subscription record accordingly.

Tools

Stripe WebhooksStripe-Signature verificationIdempotent event processing
Week 3, alongside subscription setup
🏦04

Self-Service Billing Portal

A Stripe-hosted portal where customers manage their own subscription — update payment methods, download invoices, change plans, and cancel. Reduces billing support requests to near zero and is implemented in one API call.

Tools

Stripe Billing PortalCustomer Portal SessionsPortal Configuration API
Week 3, post-checkout integration
💰05

Dunning & Revenue Recovery

The automated process of recovering failed payments. When a card charge fails, dunning sends a structured email sequence asking customers to update their payment method, while Stripe retries the charge on a schedule. Recovers 10–20% of at-risk MRR.

Tools

Stripe Smart RetriesResend email sequencesFailed payment webhooks
Week 4 or first post-launch sprint
🔒06

Feature Gating by Plan

The mechanism that enforces plan-level access to features. Subscription status and plan tier are checked at the API middleware layer before executing gated operations. Free, trial, and paid users see different feature sets based on their active subscription.

Tools

Subscription status middlewarePlan tier constantsUpgrade prompt components
Throughout build — applied per feature

▸ Pricing Models

Four SaaS pricing models — how to choose the right one

Pricing model choice directly impacts revenue ceiling, churn behaviour, and billing complexity. Here are the four models with honest trade-offs and clear guidance on which to use at which stage.

📦

Flat-Rate (Fixed Price)

$49/month — unlimited users, unlimited usage

Start Here

One price for full access to the product. No per-seat or usage variables. Easiest to understand, easiest to sell, easiest to build.

Advantages

  • Simplest for customers to understand
  • No billing complexity by user count
  • Easiest to implement and test
  • Predictable revenue per customer

Trade-offs

  • Leaves money on the table from power users
  • Hard to segment by company size
  • No natural expansion revenue path

Revenue Model

Fixed MRR per customer. Growth comes from new customers only.

Best For

Single-user tools, early-stage SaaS, products with high variance in user count

👥

Per-Seat (Per-User)

$15/seat/month — first 5 seats minimum

Most Common

Price scales with the number of user seats in the organisation. Each additional team member added increases the monthly bill. Natural expansion revenue as teams grow.

Advantages

  • Revenue scales naturally with team growth
  • Easy to segment by company size
  • Built-in expansion revenue mechanism
  • Simple to communicate value

Trade-offs

  • Customers resist adding seats (cost avoidance)
  • Shared logins become a common workaround
  • Revenue predictability harder at small team sizes

Revenue Model

MRR grows as customers add seats. Best expansion metric: seats per org over time.

Best For

Team collaboration tools, project management, CRM, HR software

📊

Usage-Based (Metered)

$0.01 per API call, first 1,000 free

Post-MVP

Price scales with actual product usage — API calls, messages sent, documents processed, AI tokens consumed. Customers pay only for what they use. Revenue scales perfectly with value delivered.

Advantages

  • Perfect value alignment
  • Low friction to start (low initial cost)
  • Revenue scales with customer success
  • No seat-sharing workarounds

Trade-offs

  • Unpredictable revenue per customer
  • Higher billing infrastructure complexity
  • Customers may limit usage to control costs
  • Hard to budget from customer side

Revenue Model

Revenue directly tied to customer usage volume. Forecasting requires usage trend data.

Best For

API products, AI-powered tools, email sending platforms, infrastructure SaaS

🏆

Tiered Plans

Starter $29/mo · Pro $79/mo · Business $199/mo

Most Scalable

Multiple fixed-price plans (Starter, Pro, Business, Enterprise) with different feature sets and usage limits. The most common SaaS pricing structure. Allows natural upsell from entry to higher tiers.

Advantages

  • Natural upgrade path built in
  • Segment customers by value and use case
  • Flexibility to gate premium features
  • Familiar pattern customers understand

Trade-offs

  • Plan design requires careful thought
  • Feature gating logic adds development complexity
  • Risk of underpricing tiers vs actual value

Revenue Model

Expansion revenue from plan upgrades. Goal: move customers from Starter to Pro and Pro to Business.

Best For

Most B2B SaaS products with a clear feature differentiation between customer segments

▸ Stripe Integration

How to integrate Stripe in a SaaS — step by step with real code

The exact six-step Stripe integration 4Byte Agency implements in every SaaS product. Each step has a defined output and a code pattern — not pseudocode, but production-ready implementation guidance.

01

Configure Stripe Products and Prices

Create Products and Prices in the Stripe Dashboard (or via API). Each pricing plan maps to a Stripe Price object with its interval (monthly/annual) and amount. Store the Stripe Price ID in your codebase constants.

Code Pattern

// .env
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_STARTER_PRICE_ID=price_...
NEXT_PUBLIC_STRIPE_PRO_PRICE_ID=price_...
02

Create Stripe Customer on Organisation Creation

When a new organisation is created, immediately create a corresponding Stripe Customer object and store the stripe_customer_id on the organisation record. This links your tenant to Stripe and enables future billing operations.

Code Pattern

const customer = await stripe.customers.create({
  email: user.email,
  name: organisation.name,
  metadata: { organisation_id: org.id },
});
await db.organisations.update({
  where: { id: org.id },
  data: { stripe_customer_id: customer.id },
});
03

Create Checkout Session for Upgrade

When a user clicks 'Upgrade', create a Stripe Checkout Session and redirect them to the Stripe-hosted payment page. Pass success_url and cancel_url to handle both outcomes. Checkout handles card collection, 3D Secure, and PCI compliance.

Code Pattern

const session = await stripe.checkout.sessions.create({
  customer: org.stripe_customer_id,
  mode: 'subscription',
  line_items: [{ price: priceId, quantity: 1 }],
  success_url: `${origin}/dashboard?upgraded=true`,
  cancel_url: `${origin}/pricing`,
  subscription_data: { trial_period_days: 14 },
});
04

Handle Webhooks — The Source of Truth

Never trust the redirect URL to confirm payment. Always use webhooks as the authoritative source of subscription state. Verify Stripe-Signature on every incoming webhook. Process events idempotently — the same event may arrive multiple times.

Code Pattern

const sig = headers['stripe-signature'];
const event = stripe.webhooks.constructEvent(
  rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET
);
// Process based on event.type
switch (event.type) {
  case 'invoice.payment_succeeded': ...
  case 'customer.subscription.deleted': ...
}
05

Create Billing Portal Session for Self-Service

For the billing settings page, create a Stripe Billing Portal Session and redirect the customer. The portal handles all self-service billing operations — no custom UI needed. Configure allowed actions (update payment, cancel, change plan) in the Stripe Dashboard.

Code Pattern

const portalSession = await stripe.billingPortal.sessions.create({
  customer: org.stripe_customer_id,
  return_url: `${origin}/settings/billing`,
});
return redirect(portalSession.url);
06

Gate Features by Subscription Status

In API middleware and UI components, check subscription status and plan tier before granting access to paid features. The database subscription record (synced from Stripe via webhooks) is the source of truth — never call the Stripe API inline for every request.

Code Pattern

// API middleware
const subscription = await db.subscriptions.findFirst({
  where: { organisation_id: org.id, status: 'active' }
});
if (!subscription) {
  return json({ error: 'UPGRADE_REQUIRED' }, { status: 402 });
}

▸ Subscription Lifecycle

Five subscription states — what triggers each and how to handle it

Every subscription moves through these five states. Each state has defined webhook triggers, database actions, and next-state transitions. Missing any one creates silent billing or access failures.

01

Trial

Customer signs up and starts a free trial period. Full product access, no charge yet. Trial period typically 7–14 days.

Webhook Events

customer.subscription.created (status: trialing)

Database Action

Set subscription.status = 'trialing'. Grant full feature access. Start trial countdown.

Next State

Active (trial converts) or Incomplete (card declined) or Cancelled (explicit cancel)

02

Active

Customer is paying successfully. Subscription renews automatically at the period end. Full feature access granted based on plan tier.

Webhook Events

customer.subscription.updated (status: active)
invoice.payment_succeeded

Database Action

Set subscription.status = 'active'. Update current_period_end. Grant plan features.

Next State

Past Due (payment fails) or Cancelled (customer cancels) or Updated (plan change)

03

Past Due

A payment attempt failed. Stripe is retrying on a schedule. Customer still has access but is in the dunning sequence. This is a critical revenue recovery window.

Webhook Events

invoice.payment_failed
customer.subscription.updated (status: past_due)

Database Action

Set subscription.status = 'past_due'. Trigger dunning email sequence. Maintain feature access during retry window.

Next State

Active (payment recovered) or Cancelled (all retries exhausted)

04

Cancelled

Subscription has been cancelled — either by the customer, by Stripe after exhausted retries, or by admin action. Access is revoked at period end for voluntary cancellations, immediately for payment failures.

Webhook Events

customer.subscription.deleted
customer.subscription.updated (cancel_at_period_end: true)

Database Action

Set subscription.status = 'cancelled'. Set cancel_at_period_end. Revoke feature access at period_end or immediately.

Next State

Can resubscribe — treat as new subscription creation

05

Paused

Customer pauses their subscription instead of cancelling. Billing is suspended for a defined period. Feature access is restricted. An effective churn prevention tool for seasonal or budget-constrained customers.

Webhook Events

customer.subscription.updated (pause_collection: { behavior: 'void' })

Database Action

Set subscription.status = 'paused'. Restrict to free-tier features. Show resume prompt.

Next State

Active (resumes) or Cancelled (doesn't resume in time)

▸ Webhook Events Reference

The eight Stripe webhook events every SaaS must handle

These eight events cover 99% of subscription state changes in a SaaS product. Each one has a defined trigger, required database action, and priority level.

Event
Trigger
Action
Priority
customer.subscription.created
New subscription created (trial start or direct payment)
Insert subscription record. Set status. Grant feature access. Send welcome email.
Critical
invoice.payment_succeeded
Successful recurring payment
Update subscription.current_period_end. Set status = 'active'. Send payment receipt email.
Critical
invoice.payment_failed
Payment attempt failed (card declined, expired, insufficient funds)
Set status = 'past_due'. Trigger dunning email 1. Log failure reason. Maintain access during retry window.
Critical
customer.subscription.updated
Plan change, quantity change, trial end, cancellation scheduled
Update plan_id, status, cancel_at_period_end, current_period_end in database.
Critical
customer.subscription.deleted
Subscription fully cancelled (period ended or immediate cancellation)
Set status = 'cancelled'. Revoke feature access. Send cancellation confirmation. Trigger win-back sequence.
Critical
customer.subscription.trial_will_end
Trial ending in 3 days
Send trial expiry warning email. Show in-app upgrade prompt. Trigger conversion sequence.
High
payment_method.automatically_updated
Stripe updates card details via Account Updater
Log the update. Clear any past_due flags if now valid. No customer action needed.
Medium
invoice.upcoming
Upcoming invoice ~7 days before charge
Optional: send advance billing notice for large invoices or annual plans.
Low

Idempotency is mandatory: Stripe retries webhook delivery for up to 3 days when your endpoint returns a non-2xx response or times out. Every handler must be safe to run multiple times with the same event. Use upsert operations and store processed Stripe event IDs to detect and skip duplicate deliveries.

▸ Dunning & Revenue Recovery

The 14-day dunning sequence that recovers 15% of at-risk MRR

Dunning is the most underbuilt part of most SaaS billing systems. A three-email sequence combined with Stripe Smart Retries recovers 10–20% of payments that would otherwise churn. Here's the exact sequence 4Byte builds.

D0

Trigger

Payment fails

System Action

Stripe Smart Retry (immediate retry for some failure types). Set status = past_due. Send Dunning Email 1.

Email

Subject: Action required: Your payment didn't go through

Payment failed notice. Clear link to update payment method in Stripe Billing Portal. Current period end date shown.

D3

Trigger

No payment update after 3 days

System Action

Stripe retries charge. Send Dunning Email 2 if still failing.

Email

Subject: Your account will be restricted in 4 days

Urgency increase. Feature access warning. Direct link to update card. Offer support contact.

D5

Trigger

Still no payment update

System Action

Stripe final retry. Send Dunning Email 3 with final warning.

Email

Subject: Final notice: Update your payment to keep access

Final warning. Specific date access will be revoked. One-click update CTA. Pause option offered as alternative to cancel.

D7

Trigger

All Stripe retries exhausted

System Action

Stripe fires customer.subscription.deleted. Set status = cancelled. Revoke feature access. Send Cancellation Email.

Email

Subject: Your account has been suspended

Access revoked notice. Grace period offer (48hr to update and restore). Resubscribe link. Support contact.

D14

Trigger

Post-cancellation win-back

System Action

Send win-back email to cancelled customers who haven't resubscribed.

Email

Subject: We're holding your data — come back and pick up where you left off

Data retention assurance. Reactivation link. Optionally offer a discount or extended trial.

▸ Billing Metrics

Six billing metrics every SaaS founder must track

These six metrics tell you whether your SaaS billing system is generating healthy, growing, recoverable revenue — or silently leaking at each stage of the subscription lifecycle.

Monthly Recurring Revenue (MRR)

Sum of all active subscription values normalised to a monthly figure. The primary health metric for SaaS billing.

Formula

MRR = Σ (active subscriptions × monthly plan value)

Target

Growing 10–20% month-over-month in early stage

Churn Rate

Percentage of MRR or customers lost in a period. The most important retention signal in SaaS.

Formula

Monthly Churn = (MRR lost / MRR at start of month) × 100

Target

< 3% monthly for early-stage B2B SaaS

Net Revenue Retention (NRR)

Revenue from existing customers after expansion, contraction, and churn. Above 100% means existing customers are generating more revenue over time.

Formula

NRR = (Starting MRR + Expansion - Contraction - Churn) / Starting MRR × 100

Target

> 100% is healthy. > 120% is excellent

Trial-to-Paid Conversion Rate

Percentage of trial users who convert to a paid subscription at trial end.

Formula

Conversion = (Trial → Paid) / Total Trials × 100

Target

> 15% for card-required trials. > 5% for no-card trials

Payment Recovery Rate

Percentage of failed payment invoices that are eventually recovered through retries and dunning.

Formula

Recovery Rate = (Recovered invoices / Failed invoices) × 100

Target

> 50% with Smart Retries + dunning emails

Average Revenue Per Account (ARPA)

Average monthly revenue per paying account. Tracks whether revenue quality is improving over time.

Formula

ARPA = Total MRR / Number of active accounts

Target

Rising ARPA signals successful upsell to higher-tier plans

▸ Billing Mistakes

Six billing mistakes that create revenue leakage or security risks

These are the six most common and most expensive billing implementation mistakes across SaaS products. Every one is preventable and costly once users are live.

Trusting the Stripe Checkout redirect URL as payment confirmation

Consequence

The success_url redirect fires even if the user manually navigated to the URL without paying. Fraudulent access to paid features is trivially easy if billing state is set on redirect rather than webhook.

4Byte Standard

Never set subscription state on the success_url redirect. Only update subscription state via webhook handlers after receiving invoice.payment_succeeded or customer.subscription.created with status: active.

Not making webhook handlers idempotent

Consequence

Stripe retries webhooks up to 3 days for failed deliveries. A non-idempotent handler processing the same invoice.payment_succeeded twice could send duplicate receipts, double-credit accounts, or throw duplicate key errors.

4Byte Standard

Check for existing records before inserting. Use upsert operations. Store processed event IDs in a webhook_events table and skip already-processed events.

Calling the Stripe API on every authenticated request to check subscription status

Consequence

Stripe API calls add 100–300ms latency to every request. At scale this becomes a significant performance bottleneck. The Stripe API also has rate limits that will be hit under load.

4Byte Standard

Sync subscription state to your database via webhooks. Read subscription status from your own database on every request — not from Stripe. The database query is 10–50× faster.

Not verifying Stripe webhook signatures

Consequence

Without signature verification, anyone can POST fake webhook events to your endpoint. A malicious actor could fire a fake invoice.payment_succeeded event and upgrade themselves to a paid plan for free.

4Byte Standard

Always call stripe.webhooks.constructEvent(rawBody, sig, webhookSecret) before processing any event. This verifies the HMAC signature and prevents event forgery.

Revoking access immediately when cancel_at_period_end = true

Consequence

When a customer cancels but still has days remaining in their billing period, they've already paid for that time. Revoking access immediately breaks trust and violates reasonable user expectations.

4Byte Standard

Distinguish between cancel_at_period_end (scheduled cancel — maintain access until period_end) and subscription.deleted (immediate cancel — revoke access now). Only revoke on the webhook that fires at period end.

No dunning sequence for failed payments

Consequence

Without dunning, every failed payment results in immediate churn. Stripe's Smart Retries alone without customer communication recovers far less revenue than retries combined with a structured email sequence.

4Byte Standard

Build a 3-email dunning sequence triggered by invoice.payment_failed webhook. Provide a direct link to the Stripe Billing Portal for one-click card update. Stripe Smart Retries handles the technical retry; emails handle the human recovery.

▸ FAQ

Frequently asked questions about SaaS billing systems

How do you implement billing in a SaaS product?+

SaaS billing is implemented using Stripe — the industry standard payment infrastructure. The core components are: Stripe Checkout for payment collection, Stripe Subscriptions for recurring billing management, Stripe Webhooks for syncing subscription state to your database, and Stripe Billing Portal for self-service customer management. 4Byte Agency integrates all four components in every SaaS product we build.

What is the best pricing model for a SaaS product?+

The best SaaS pricing model depends on your product type. Per-seat (per-user) pricing works well for collaboration and team tools. Flat-rate pricing is simplest to understand and works for single-user products. Usage-based pricing aligns cost with value and scales well for API and infrastructure products. Most SaaS products start with flat-rate or per-seat tiers and add usage-based components post-launch.

How do Stripe webhooks work in a SaaS product?+

Stripe webhooks are HTTP POST requests Stripe sends to your server when subscription events occur — payment succeeded, payment failed, subscription cancelled, trial ending. Your webhook handler verifies the Stripe-Signature header, processes the event, and updates your database subscription state. The handler must be idempotent — safe to receive the same event multiple times — because Stripe retries failed deliveries.

What is dunning in SaaS billing?+

Dunning is the process of recovering failed subscription payments through automated retry logic and customer communication. When a payment fails (expired card, insufficient funds), dunning sends a sequence of emails asking the customer to update their payment method, while Stripe automatically retries the charge on a configurable schedule. Well-implemented dunning recovers 10–20% of churning revenue.

Should a SaaS MVP include billing from day one?+

Yes — billing must be included in the SaaS MVP. A product without billing is a demo, not a business. Even if you offer a free trial, requiring a credit card gate validates willingness to pay. Stripe integration in an MVP takes 3–5 days and provides the most important validation signal — whether users will actually pay for the product.

How does 4Byte Agency implement SaaS billing?+

4Byte Agency implements billing using Stripe Checkout and Stripe Subscriptions, synced to the database via webhook handlers. We build subscription lifecycle management, trial logic, plan upgrade/downgrade flows, a Stripe Billing Portal integration for self-service, and dunning email sequences via Resend. Billing is integrated in week 3 of every 28-day SaaS build.

▸ Ship billing that works from day one

Need your SaaS billing system built correctly and securely?

We implement the complete Stripe billing stack — Checkout, Subscriptions, Webhooks, Billing Portal, dunning sequences, and feature gating — in week 3 of every 28-day SaaS build. Using the exact patterns from this guide, refined across 45+ products.

Available now
Billing built in week 3
Response in ≤ 4 hours
45+ products shipped