Stripe Setup (Billing)

NextGenKit includes Stripe subscriptions, customer portal, and webhook-driven sync out of the box.

1. Create Stripe Products

  1. Go to Stripe Dashboard → Products
  2. Create two products: Pro and Business
  3. For each product, create two prices: Monthly and Annual
  4. Copy the Price IDs to your .env.local

2. Configure Customer Portal

  1. Go to Settings → Billing → Customer Portal
  2. Enable subscription cancellation and plan switching
  3. 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:listen

This forwards events directly to localhost:3000/api/webhooks/stripe.

4. Set Up Webhooks

  1. Go to Developers → Webhooks in Stripe Dashboard
  2. Add endpoint: https://xxxx.ngrok-free.app/api/webhooks/stripe
  3. Subscribe to events:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_failed
  4. Copy the Signing Secret to STRIPE_WEBHOOK_SECRET in .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