
Photo by Tech Daily on Unsplash
How to Build SaaS Billing With Stripe: Subscriptions, Trials, Coupons (Guide)
How to Build SaaS Billing With Stripe: Subscriptions, Trials, Coupons
Stripe is the gold standard for SaaS billing. But wiring up subscriptions, trials, and coupons correctly takes more than a quick API call. This guide covers the full implementation — from creating products in Stripe to handling every webhook that keeps your app in sync.
Step 1: Set Up Stripe Products and Prices
Before writing code, configure your plans in the Stripe Dashboard:
Create a Product for Each Plan
| Product | Monthly Price | Annual Price | Stripe Price ID |
|---|---|---|---|
| Starter | $19/mo | $190/yr | price_starter_monthly |
| Pro | $49/mo | $490/yr | price_pro_monthly |
| Business | $99/mo | $990/yr | price_business_monthly |
Best practice: Create both monthly and annual prices for each product. Annual plans (with a ~17% discount) improve cash flow and reduce churn.
Step 2: Implement Checkout
Using Stripe Checkout (Recommended for MVP)
Stripe Checkout is a hosted payment page. You create a session, redirect the user, and Stripe handles everything — card entry, validation, 3D Secure, Apple/Google Pay.
Flow:
- User clicks "Subscribe" on your pricing page
- Your API creates a Stripe Checkout Session
- User is redirected to Stripe's hosted checkout
- After payment, user is redirected back to your app
- Webhook confirms the payment and activates the subscription
Key parameters for the Checkout Session:
mode: 'subscription'— for recurring billingcustomer— attach to an existing Stripe customer (or let Stripe create one)line_items— the price ID(s) the user selectedsuccess_url— where to redirect after paymentcancel_url— where to redirect if they cancelsubscription_data.trial_period_days— to add a free trial
Step 3: Add Free Trials
Trial Without Payment Method
Let users try your product without entering a card. The subscription starts in trialing status. When the trial ends, the subscription becomes past_due if no card is on file.
Best for: Maximizing trial signups (lower friction). Risk: Low conversion if users forget about the trial.
Trial With Payment Method (Recommended)
Collect the card during signup but don't charge until the trial ends. This is the standard SaaS pattern.
Best for: Higher conversion rates (card is already on file).
Implementation: Set trial_period_days in the Checkout Session and payment_method_collection: 'always'.
Typical Trial Lengths
| Product Type | Trial Length | Industry Standard |
|---|---|---|
| Simple tool | 7 days | Common |
| SaaS platform | 14 days | Most common |
| Enterprise SaaS | 30 days | Large products |
Step 4: Implement Coupons and Promotions
Coupon Types
| Type | Example | Use Case |
|---|---|---|
| Percentage off | 20% off for 3 months | Marketing promotions |
| Fixed amount off | $10 off per month for 6 months | Referral rewards |
| Free trial extension | 30-day trial instead of 14 | Onboarding incentive |
| 100% off for X months | Free for 3 months | Beta users, partners |
Creating Coupons in Stripe
Create coupons in the Stripe Dashboard or via API. Then create Promotion Codes that users enter at checkout.
Add to Checkout Session: allow_promotion_codes: true — this shows a "Have a promo code?" field on the Stripe Checkout page.
Step 5: Handle Webhooks (Critical)
Webhooks are how Stripe tells your app what happened. Your billing system is broken without webhooks.
Essential Webhook Events
| Event | Action in Your App |
|---|---|
checkout.session.completed | Create subscription record, activate user's plan |
invoice.payment_succeeded | Renew subscription access, update billing date |
invoice.payment_failed | Start dunning flow, notify user |
customer.subscription.updated | Handle plan changes (upgrades/downgrades) |
customer.subscription.deleted | Revoke access, update user record |
customer.subscription.trial_will_end | Send "trial ending soon" email (3 days before) |
Webhook Security
Always verify webhook signatures:
- Get the raw request body (not parsed JSON)
- Get the
Stripe-Signatureheader - Use
stripe.webhooks.constructEvent()to verify - Only process the event after verification passes
Step 6: Add the Customer Portal
Stripe's Customer Portal lets users manage their own subscriptions:
- Update payment method
- View invoices and receipts
- Change plan (upgrade/downgrade)
- Cancel subscription
Implementation: Create a portal session and redirect the user. Takes about 10 lines of code. Configure allowed actions in the Stripe Dashboard under Customer Portal settings.
Step 7: Sync Subscription Status
Your database needs a subscription table that stays in sync with Stripe:
| Field | Source |
|---|---|
userId | Your app |
stripeCustomerId | Created during first checkout |
stripeSubscriptionId | From checkout.session.completed webhook |
stripePriceId | From webhook — determines which plan |
status | trialing, active, past_due, canceled |
currentPeriodEnd | From webhook — when access expires |
cancelAtPeriodEnd | Whether user has scheduled cancellation |
Golden rule: Never trust the client. Always check subscription status server-side before granting access to paid features.
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Not verifying webhook signatures | Fake payments, free access | Always verify signatures |
| Checking plan status client-side only | Users bypass payment | Server-side checks on every request |
Not handling invoice.payment_failed | Users lose access silently | Implement dunning (retry + notify) |
| Hardcoding price IDs | Breaks when prices change | Use environment variables |
| Not testing with Stripe CLI | Webhooks work in production but not locally | Use stripe listen --forward-to |
Final Thoughts
SaaS billing with Stripe is a solved problem — but it has many moving parts. Get the checkout flow right, handle webhooks properly, and sync subscription status to your database. Everything else (coupons, trials, portal) is built on that foundation.
Need a billing template? Browse SaaS boilerplates with Stripe built in on MVPHub.
Planning your billing features? Read SaaS Billing Features Checklist.







