Stripe
Create your products, prices and webhook.
Billing needs a Stripe account. Work in test mode until you go live: test and live mode have separate keys, prices and webhooks.
API key
Copy the secret key from API keys:
STRIPE_SECRET_KEY=sk_test_...Products and prices
Create two products in the product catalog, Pro and Business, each with two recurring prices: one monthly, one yearly. Copy each price ID (price_...):
STRIPE_PRO_MONTHLY_PRICE_ID=price_...
STRIPE_PRO_YEARLY_PRICE_ID=price_...
STRIPE_BUSINESS_MONTHLY_PRICE_ID=price_...
STRIPE_BUSINESS_YEARLY_PRICE_ID=price_...Amounts are never stored in the code: the pricing page reads them from Stripe. Plans are declared in modules/billing/plans.ts, add one there if you need a third tier.
Only STRIPE_PRO_MONTHLY_PRICE_ID is required to switch billing on. A plan without a monthly price is hidden from the pricing page.
Webhook
The webhook keeps subscriptions in sync with your database. Its endpoint is /api/auth/stripe/webhook.
In development
Install the Stripe CLI and forward events to your local app:
stripe login
stripe listen --forward-to localhost:3000/api/auth/stripe/webhookThe command prints a signing secret (whsec_...). Keep it running while you test.
STRIPE_WEBHOOK_SECRET=whsec_...In production
Add an endpoint in Webhooks pointing to https://your-domain.com/api/auth/stripe/webhook, with these events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedprice.created,price.updated,price.deletedproduct.updated
Price and product events refresh the pricing page right away. Without them, new prices show up within 5 minutes.
Customer portal
The Manage button on the billing page opens the Stripe customer portal. Enable it in portal settings and choose what customers can do: cancel, switch plans, update their payment method.
Test a subscription
- Start
pnpm devandstripe listen. - Sign up, then pick a plan on
/pricing. - Pay with the card
4242 4242 4242 4242, any future date and any CVC. - Back on
/dashboard/billing, the plan is active. Cancel it from the portal to test the other way.