Stripe Setup (Billing)
NextGenKit includes Stripe subscriptions, customer portal, and webhook-driven sync out of the box.
1. Create Stripe Products
- Go to Stripe Dashboard → Products
- Create two products: Pro and Business
- For each product, create two prices: Monthly and Annual
- Copy the Price IDs to your
.env.local
2. Configure Customer Portal
- Go to Settings → Billing → Customer Portal
- Enable subscription cancellation and plan switching
- Save the configuration
3. Set Up ngrok for Local Development
Stripe webhooks need a publicly accessible URL. Use ngrok to expose your local server:
# Install ngrok (macOS)
brew install ngrok
# Authenticate (one-time setup)
ngrok config add-authtoken YOUR_AUTH_TOKEN
# Start the tunnel
ngrok http 3000
Copy the https://xxxx.ngrok-free.app URL — you'll use this as your webhook endpoint.
Alternative: You can also use the Stripe CLI to forward webhooks locally without ngrok:
pnpm stripe:listenThis forwards events directly to
localhost:3000/api/webhooks/stripe.
4. Set Up Webhooks
- Go to Developers → Webhooks in Stripe Dashboard
- Add endpoint:
https://xxxx.ngrok-free.app/api/webhooks/stripe - Subscribe to events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_failed
- Copy the Signing Secret to
STRIPE_WEBHOOK_SECRETin.env.local
5. Production Webhook URL
When you deploy your app, update the webhook endpoint in Stripe Dashboard to your production URL:
https://your-domain.com/api/webhooks/stripe
Replace the ngrok URL with your actual deployed domain. You can keep the ngrok endpoint as a separate webhook for local development, or remove it entirely.
Plan Gating
Use requirePlan() from lib/billing/gate.ts to restrict features by plan:
import { requirePlan } from "@/lib/billing/gate"
// In a server action or route handler:
await requirePlan("pro") // throws if user is on free plan