Billing System Setup Guide
This guide explains how to set up and configure the Stripe billing system for homepage.dev.
Overview
The billing system provides three subscription tiers:
- Free: 5 items, 1 workspace (permanent, no credit card)
- Pro: $15/month - 100 items, 3 workspaces, advanced features
- Business: $79/month - Unlimited everything, all features
Architecture
- Convex: Subscription data storage (source of truth)
- Clerk: User metadata for fast feature access (cached)
- Stripe: Payment processing and subscription management
Setup Steps
1. Create Stripe Account
- Sign up at https://stripe.com
- Get your API keys from the Stripe Dashboard
- Use test mode for development
2. Create Products in Stripe Dashboard
Pro Plan
- Navigate to Products → Add Product
- Name:
Pro Plan - Description:
Perfect for professionals and small teams - Create two prices:
- Monthly: $15.00 USD (recurring monthly)
- Annual: $144.00 USD (recurring annually)
- Copy the Price IDs for both
Business Plan
- Navigate to Products → Add Product
- Name:
Business Plan - Description:
For teams and organizations - Create two prices:
- Monthly: $79.00 USD (recurring monthly)
- Annual: $790.00 USD (recurring annually)
- Copy the Price IDs for both
3. Configure Environment Variables
Add these to your .env.local file:
# Stripe Keys (Test Mode for Development)
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxx
# Stripe Price IDs (from step 2)
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PRICE_ID=price_xxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_PRO_ANNUAL_PRICE_ID=price_xxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PRICE_ID=price_xxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_BUSINESS_ANNUAL_PRICE_ID=price_xxxxxxxxxxxxxxxxxxxxx
# App URL (for redirects)
NEXT_PUBLIC_APP_URL=http://localhost:3017For Production, replace with live mode keys:
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxxxxxxxxxx4. Set Up Webhooks (Required for Subscription Updates)
Local Development (using Stripe CLI)
- Install Stripe CLI: https://stripe.com/docs/stripe-cli
- Login:
stripe login - Forward webhooks to local server:
stripe listen --forward-to localhost:3017/api/webhooks/stripe - Copy the webhook signing secret from the output:
Ready! Your webhook signing secret is whsec_xxxxxxxxxxxxxxxxxxxxx - Add to
.env.local:STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxx
Production Deployment
- Deploy your application
- Navigate to Stripe Dashboard → Developers → Webhooks
- Click Add Endpoint
- Enter your webhook URL:
https://yourdomain.com/api/webhooks/stripe - Select events to listen for:
customer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededinvoice.payment_failed
- Copy the signing secret and add to production environment variables
5. Initialize Free Tier for Users
Option A: Automatic (Recommended)
Set up Clerk webhook to auto-create subscriptions on user signup:
- Create webhook endpoint:
/api/webhooks/clerk(TODO: implement) - Listen for
user.createdevent - Call Convex
subscriptions.createmutation with tier="free"
Option B: Migration Script
For existing users, run a one-time migration:
// convex/migrations/initializeSubscriptions.ts
// TODO: Create migration script to add free subscriptions for existing users6. Test the System
Test Card Numbers (Stripe Test Mode)
- Success:
4242 4242 4242 4242 - Decline:
4000 0000 0000 0002 - Requires Authentication:
4000 0025 0000 3155
Test Flow
- Sign in to your app
- Navigate to Profile → Billing
- Click "Upgrade to Pro"
- Enter test card details
- Complete checkout
- Verify:
- Subscription updated in Convex
- Clerk metadata updated
- Features unlocked in app
7. Enable Stripe Tax (Optional but Recommended)
- Navigate to Stripe Dashboard → Settings → Tax
- Enable Stripe Tax
- Configure tax IDs for your business
- Stripe will automatically calculate and collect taxes
Feature Gating
Client-Side (React Components)
import { useHasFeature, useUsageLimit } from "@/lib/subscription/hooks"
function MyComponent() {
const hasAPI = useHasFeature("apiAccess")
const itemLimit = useUsageLimit("items")
if (!hasAPI) {
return <UpgradePrompt feature="API Access" />
}
return <div>API content here...</div>
}Server-Side (Server Actions)
import { requireFeature, checkUsageLimit } from "@/lib/subscription/server"
export async function createItem() {
// Check if user has feature
await requireFeature("advancedAnalytics")
// Check usage limits
const currentItems = await getCurrentItemCount()
await requireUnderLimit("items", currentItems)
// Create item...
}Monitoring & Analytics
Key Metrics Dashboard
Track these metrics in your admin panel:
- MRR (Monthly Recurring Revenue)
- Churn rate
- Upgrade conversion rate (Free → Pro → Business)
- Average Revenue Per User (ARPU)
Convex Query Example
import { api } from "@/convex/_generated/api"
import { useQuery } from "convex/react"
export function useMRR() {
return useQuery(api.subscriptions.getStats)
}Troubleshooting
Webhook Not Receiving Events
- Check Stripe CLI is running:
stripe listen ... - Verify webhook secret in
.env.local - Check webhook endpoint logs
- Test webhook manually in Stripe Dashboard
Subscription Not Updating
- Check Convex logs for errors
- Verify Clerk user has publicMetadata field
- Check webhook signature validation
- Review Stripe Dashboard → Events for webhook delivery status
TypeScript Errors
If you see Stripe API version errors:
- Check
lib/subscription/stripe.ts- API version should match installed stripe package - Update if needed:
pnpm add stripe@latest
Security Checklist
- Webhook signatures verified
- STRIPE_SECRET_KEY stored securely (not in git)
- Server actions protected with
await auth() - Feature gates on both client AND server side
- Stripe Customer Portal enabled for payment management
- PCI compliance (never store card details)
Next Steps
- Test thoroughly in Stripe test mode
- Set up monitoring for failed payments
- Configure email notifications for subscription events
- Create upgrade prompts throughout your app
- Add usage indicators to show limits
- Deploy to production and test with real cards
Support
- Stripe Documentation: https://stripe.com/docs
- Stripe Support: Available in Dashboard
- Convex Documentation: https://docs.convex.dev
- Clerk Documentation: https://clerk.com/docs