Stripe
Set up billing and subscriptions with Stripe.
Stripe handles payment processing, subscription management, and invoicing.
Create a Stripe Account
- Go to stripe.com and create an account
- Complete the onboarding to enable payments
Get Your API Keys
Navigate to Developers → API Keys in your Stripe dashboard:
| Key | Environment Variable |
|---|---|
| Publishable key | NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY |
| Secret key | STRIPE_SECRET_KEY |
Use test mode keys during development. They start with pk_test_ and
sk_test_.
Billing Modes
VelocityKit supports multiple billing models out of the box:
| Mode | Description | Use Case |
|---|---|---|
| Recurring | Monthly or yearly subscription | SaaS with ongoing access |
| One-time with expiration | Single payment, access expires after X months | Software licenses, course access |
| Lifetime | Single payment, never expires | Lifetime deals, perpetual licenses |
How It Works
The billing mode is determined automatically based on your Stripe price configuration:
- Recurring prices → Subscription mode (access while subscription active)
- One-time prices → Payment mode (access for
grant_monthsduration)
For one-time purchases, set the grant_months metadata on your Stripe product:
grant_months Value | Access Duration |
|---|---|
12 (default) | 1 year |
24 | 2 years |
9999 | Lifetime (never expires) |
Extensions stack automatically. If a user purchases again before expiration, the new time is added to their existing access.
Create Products and Prices
VelocityKit fetches products and prices directly from Stripe using product metadata. No price IDs need to be configured in environment variables.
Option 1: Setup Wizard (Recommended)
The pnpm onboard wizard can create products automatically:
pnpm onboard
It will:
- Ask for your product name and pricing
- Create the product in Stripe via API
- Set up monthly and yearly prices with correct metadata
Option 2: Stripe Dashboard
- Go to Products → Add Product
- Create your product with metadata:
plan_type:freeorpaidhighlighted:truefor the recommended plancta_label: Button text (e.g., "Get Started")sort_order: Display order (0, 1, 2...)grant_months: For one-time prices, access duration (12, 24, 9999 for lifetime)
- Add features using Marketing features (up to 15)
- Add pricing (monthly, yearly, one-time, etc.)
Prices are fetched automatically from Stripe. Just ensure your paid product
has plan_type set to paid in its metadata.
Set Up Webhooks
Webhooks sync subscription status from Stripe to your database.
Production Webhooks
- Go to Developers → Webhooks in Stripe
- Click Add endpoint
- Enter your URL:
https://your-domain.com/api/webhooks/stripe - Select these events:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted
- Copy the Signing secret to
STRIPE_WEBHOOK_SECRET
Local Development
Use the Stripe CLI to forward webhooks locally:
# Install Stripe CLI (if not already)
brew install stripe/stripe-cli/stripe
# Login to Stripe
stripe login
# Forward webhooks to your local server
stripe listen --forward-to localhost:3000/api/webhooks/stripe
Copy the webhook signing secret from the CLI output to your .env.local.
Billing Flow
Here's how billing works in VelocityKit:
- User clicks Upgrade → Creates a Stripe Checkout session
- Stripe processes payment → Sends
checkout.session.completedwebhook - Webhook handler → Updates
profiles.subscription_statusin Supabase - User returns → Sees Pro features unlocked
Customer Portal
Users can manage their subscription through Stripe's Customer Portal:
- Update payment method
- Cancel subscription
- View invoices
- Download receipts
The portal is accessible from the account settings page.
Testing Payments
Use Stripe's test cards during development:
| Card Number | Scenario |
|---|---|
| 4242 4242 4242 4242 | Successful payment |
| 4000 0000 0000 3220 | 3D Secure required |
| 4000 0000 0000 9995 | Declined |
Use any future expiration date and any 3-digit CVC.