Payments
Stripe subscriptions, checkout, and Customer Portal.
Overview
Stripe handles all payment processing. The template uses Stripe SDK v21 with the 2026-03-25.dahlia API version. It includes subscription checkout, webhook handling, and Customer Portal integration.
Setup
- Create products and prices in your Stripe Dashboard
- Copy price IDs to
config.ts - Add your Stripe keys to
.env.local - Set up the webhook endpoint (see below)
Important: The template targets the Stripe dahlia API version (2026-03-25). Make sure your Stripe account's API version is compatible (check Dashboard > Developers > API version). Older API versions will cause webhook failures.
Checkout Flow
- User clicks a plan on the pricing page
createCheckoutSession()Server Action is called- A Stripe Customer is created (or retrieved) for the user
- User is redirected to Stripe Checkout
- On success, the webhook updates the
subscriptionstable
Webhook Setup
Local Development
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Copy the webhook signing secret to STRIPE_WEBHOOK_SECRET in .env.local.
Production
Add a webhook endpoint in Stripe Dashboard pointing to:
https://yourdomain.com/api/webhooks/stripe
Events to listen for:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failed
Common mistake: If you add the webhook endpoint but don't select these specific events, Stripe will log events but never deliver them to your app. Make sure all 6 events are checked.
Stripe API Version (dahlia)
The template uses Stripe API version 2026-03-25.dahlia. Key differences from older versions:
- Subscription period fields are on
subscription.items.data[0], not the top-level subscription object - Invoice subscription ID is at
invoice.parent.subscription_details.subscription, notinvoice.subscription
The webhook handler already accounts for these changes. If you customize the webhook, keep this in mind.
Customer Portal
Users can manage their subscription via the Stripe Customer Portal:
import { createPortalSession } from '@/actions/billing'
// In a Server Action or form:
await createPortalSession()
// Redirects to Stripe Customer Portal
Testing
Use Stripe test mode and the test card 4242 4242 4242 4242.
For a free test flow, create a 100% discount coupon in Stripe and apply it at checkout.