Prerequisites
Before configuring Stripe, you’ll need:- A Stripe account (Sign up)
- Stripe CLI installed (Installation guide)
- Stripe CLI authenticated (
stripe login)
Stripe API Configuration
The Stripe client is initialized inlib/payments/stripe.ts:
lib/payments/stripe.ts
Required Environment Variables
Add these to your.env file:
Your Stripe secret API keyFormat:
sk_test_... (test mode) or sk_live_... (production)Where to find it: Stripe Dashboard → API KeysWebhook signing secret for verifying eventsFormat:
whsec_...See Webhook Configuration below for setup instructions.Your application’s base URL for redirectsDevelopment:
http://localhost:3000Production: https://yourdomain.comGetting Your API Keys
Test Mode (Development)
- Go to Stripe Dashboard
- Ensure you’re in Test mode (toggle in top right)
- Copy the “Secret key” (starts with
sk_test_) - Add to
.env:
Live Mode (Production)
- Switch to Live mode in Stripe Dashboard
- Copy the “Secret key” (starts with
sk_live_) - Update your production
.envwith the live key - Complete Stripe account verification before processing real payments
Subscription Products Setup
The starter includes a seed script that creates subscription products in Stripe.Creating Products with Seed Script
Run the database seed command:- Name: “Base”
- Price: $8.00/month
- Trial: 7 days
- Billing: Monthly recurring
- Name: “Plus”
- Price: $12.00/month
- Trial: 7 days
- Billing: Monthly recurring
Products are created in cents.
unit_amount: 800 = $8.00 USD.Seed Script Details
Fromlib/db/seed.ts:
lib/db/seed.ts
Manual Product Creation
You can also create products manually in the Stripe Dashboard:- Click “Add product”
- Enter product name and description
- Set pricing model to “Recurring”
- Configure price and billing interval
- Add trial period if desired
- Save the product
Checkout Session
The application uses Stripe Checkout for subscription sign-ups.Implementation
Fromlib/payments/stripe.ts:
Checkout Features
Accepted payment methods - currently
['card']Set to
'subscription' for recurring billingRedirect URL after successful payment:
/api/stripe/checkout?session_id={CHECKOUT_SESSION_ID}Redirect URL if user cancels:
/pricingEnables promo code input during checkout
Free trial duration - set to 14 days
Customer Portal
Stripe Customer Portal lets users manage their subscription, payment methods, and billing history.Implementation
Fromlib/payments/stripe.ts:
Portal Features
✅ Subscription updates: Change plan, quantity, or apply promo codes ✅ Subscription cancellation: Cancel at period end with feedback ✅ Payment methods: Update card information ✅ Billing history: View invoices and receipts ✅ Proration: Automatic prorated charges when upgrading/downgradingWebhook Configuration
Webhooks enable Stripe to notify your application about subscription changes.Events Handled
The webhook endpoint (app/api/stripe/webhook/route.ts) handles:
customer.subscription.updated- Subscription changes (plan upgrades, renewals, etc.)customer.subscription.deleted- Subscription cancellations
app/api/stripe/webhook/route.ts
Development Setup (Stripe CLI)
For local development, use the Stripe CLI to forward webhook events:- Install Stripe CLI: Follow the installation guide
-
Authenticate:
-
Get webhook secret:
Copy the webhook secret (
whsec_...) to your.env: -
Start webhook forwarding:
Keep the
stripe listen command running while developing. It forwards Stripe events to your local server.Production Setup
- Go to Stripe Dashboard → Webhooks
- Click “Add endpoint”
-
Enter endpoint URL:
-
Select events to listen to:
customer.subscription.updatedcustomer.subscription.deleted
-
Copy signing secret:
- After creating the endpoint, copy the “Signing secret”
- Update your production
.env:
Webhook Security
Stripe signs webhook events to prevent tampering. The verification process:- Stripe sends event with
stripe-signatureheader - Your app verifies the signature using
STRIPE_WEBHOOK_SECRET - If valid, the event is processed
- If invalid, a 400 error is returned
Subscription Management
ThehandleSubscriptionChange function updates your database when subscriptions change:
lib/payments/stripe.ts
Subscription Statuses
active: Subscription is active and paidtrialing: In free trial periodcanceled: Subscription has been cancelledunpaid: Payment failedpast_due: Payment is overdue
Testing
Test Card Numbers
Stripe provides test cards for development:Testing Webhooks Locally
-
Start your development server:
-
Start Stripe webhook forwarding:
-
Trigger test events:
- Check your application logs to verify webhook processing
Testing Subscriptions
- Create a checkout session with a test price ID
- Use test card
4242 4242 4242 4242 - Complete checkout
- Verify subscription appears in:
- Your database (
teamstable) - Stripe Dashboard → Customers
- Your database (
- Test the customer portal:
- Update payment method
- Cancel subscription
- View invoices
Retrieving Products and Prices
Helper functions to fetch Stripe data:lib/payments/stripe.ts
Production Checklist
Before going live:- Switch to live API keys (
sk_live_...) - Create live products and prices
- Configure production webhook endpoint
- Update
BASE_URLto production domain - Complete Stripe account activation
- Set up tax collection (if required)
- Configure email receipts and invoices
- Test the complete checkout flow
- Test webhook delivery in production
- Monitor Stripe logs for errors
Troubleshooting
Webhook signature verification failed
Cause:STRIPE_WEBHOOK_SECRET is incorrect or missing
Solution:
- Development: Run
stripe listen --print-secretand copy the secret - Production: Get the secret from your webhook endpoint in Stripe Dashboard
No such customer
Cause: Team doesn’t have astripeCustomerId set
Solution: Ensure the checkout session sets the customer ID correctly
Subscription not updating in database
Cause: Webhook not being received or processed Solution:- Check
stripe listenis running (development) - Verify webhook endpoint is configured (production)
- Check application logs for errors
- Verify
handleSubscriptionChangeis being called
Test mode mismatch
Cause: Using test API key with live webhook secret (or vice versa) Solution: Ensure all Stripe resources (keys, products, webhooks) are in the same modeNext Steps
Environment Variables
Review all configuration options
Database Setup
Set up PostgreSQL and migrations