Billing (Stripe)
VibeReady integrates Stripe for subscription billing, checkout, and customer portal management. Webhooks are processed asynchronously through Inngest for reliability.
Free tier: No monthly fees. Stripe charges 2.9% + $0.30 per successful transaction.
Setup Wizard
When running make setup in Advanced mode, the wizard offers to configure Stripe automatically. It will prompt for your Stripe Secret Key and add it to your local environment.
The webhook secret (STRIPE_WEBHOOK_SECRET) is configured separately — locally via the Stripe CLI, and in production via the Stripe Dashboard.
Local Development
The app works without Stripe configured. Billing features display a “Not Configured” message, and all other functionality remains unaffected.
To test billing locally:
- Create a Stripe account at dashboard.stripe.com/register.
- Get test keys from Dashboard, then Developers, then API keys. Copy the Secret key (starts with
sk_test_). - Add to
.env.local:
STRIPE_SECRET_KEY="sk_test_..."
- Restart the dev server:
make dev
Create Products and Prices
You need to create at least one product in Stripe to enable billing.
- Go to Stripe Products.
- Create a “Pro” product:
- Name:
Pro - Description:
For growing teams and businesses - Pricing:
$29/month(recurring) - Click Save product and copy the Price ID (starts with
price_).
- Name:
- Create an “Enterprise” product (optional):
- Name:
Enterprise - Description:
For large organizations - Pricing:
$99/month(recurring) - Copy the Price ID.
- Name:
- Add Price IDs to
.env.local:
NEXT_PUBLIC_STRIPE_PRICE_ID_PRO="price_xxx"
NEXT_PUBLIC_STRIPE_PRICE_ID_ENTERPRISE="price_yyy"
Test Locally with Stripe CLI
The Stripe CLI forwards webhook events from Stripe to your local development server, enabling end-to-end testing of the billing flow.
- Install Stripe CLI:
# macOS
brew install stripe/stripe-cli/stripe
# Or download from https://stripe.com/docs/stripe-cli
- 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 (whsec_...) displayed in the output.
- Add the webhook secret to
.env.local:
STRIPE_WEBHOOK_SECRET="whsec_..."
- Restart the dev server and keep the Stripe CLI running in a separate terminal.
Test the Flow
- Log in as an organization owner.
- Go to
/dashboard/billing. - Click Upgrade to Pro to open Stripe Checkout.
- Use test card
4242 4242 4242 4242(any future expiry, any CVC). - Complete checkout. You will be redirected to the billing page.
- Check the Inngest dashboard at
http://localhost:8288to verify theprocess-stripe-webhookfunction ran successfully.
Production Setup
1. Get Production Keys
- Go to the Stripe Dashboard and ensure Test mode is off.
- Navigate to Developers, then API keys.
- Copy the Secret key (starts with
sk_live_).
2. Create Production Products
Repeat the product creation steps above with your production pricing.
3. Configure Webhook Endpoint
- Go to Developers then Webhooks in the Stripe Dashboard.
- Click Add endpoint.
- Set the endpoint URL to
https://your-domain.com/api/webhooks/stripe. - Select the following events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_failed
- Click Add endpoint and copy the Signing secret (
whsec_...).
4. Add Secrets to CI/CD
Add the Stripe keys to your CI/CD pipeline (e.g., GitHub Secrets) so they are available during builds and deployments. Price IDs are not sensitive and can be stored as standard environment variables.
5. Add to Terraform (GCP Deployment)
Add the Stripe secret key and webhook secret to your Terraform configuration file. Then apply the changes:
terraform apply
This creates secrets in GCP Secret Manager that Cloud Run accesses at runtime.
Note: Price IDs (NEXT_PUBLIC_STRIPE_PRICE_ID_PRO, etc.) are configured as CI/CD environment variables, not through Terraform, since they are not sensitive and do not require Secret Manager.
Configure Customer Portal
Stripe’s Customer Portal lets subscribers manage their own plans, payment methods, and invoices.
Enable Plan Switching
- Go to Settings then Billing then Customer Portal.
- Under Subscriptions, enable:
- “Customers can switch plans”
- “Prorate subscription changes”
- Click Add product and add your Pro and Enterprise products.
- Save the configuration.
Users who click “Manage Billing” will be able to upgrade or downgrade plans directly through the portal.
Enable Payment Failure Emails
Stripe can automatically notify customers when payments fail.
- Go to Settings then Billing then Subscriptions and emails.
- Under Manage failed payments, enable:
- “Send emails about expiring cards”
- “Send emails when card payments fail”
- Configure the “Update payment method” link to use Customer Portal.
This handles payment failure notifications, automatic retry notifications (Smart Retries), final warnings before subscription cancellation, and links to update payment methods.
Note: Configure both Test mode and Live mode separately using the toggle in the top-right of the Dashboard.
Architecture
The billing flow follows this path:
User clicks "Upgrade"
|
v
POST /api/billing/checkout
|
v
Stripe Checkout Session created
|
v
User completes payment on Stripe
|
v
Stripe sends webhook to /api/webhooks/stripe
|
v
Webhook handler sends event to Inngest
|
v
processStripeWebhook function:
1. Validates event
2. Updates subscription in database
3. Returns success
Webhook processing is handled asynchronously through Inngest, which provides automatic retries on failure and observability through its dashboard.
Troubleshooting
| Issue | Fix |
|---|---|
| ”Billing Not Configured” | Set STRIPE_SECRET_KEY in .env.local. |
| Upgrade button does nothing | Check browser console for errors and verify price IDs. |
| Webhook errors | Check STRIPE_WEBHOOK_SECRET and ensure Stripe CLI is running. |
| Subscription not updating | Check the Inngest dashboard for errors. |
| ”No such price” error | Verify price IDs match those in the Stripe Dashboard. |
| 503 on billing endpoints | Stripe is not configured. Set the required environment variables. |
| Portal shows wrong organization | Ensure stripeCustomerId is set on the organization record. |
Common Test Cards
| Card Number | Scenario |
|---|---|
4242 4242 4242 4242 | Successful payment |
4000 0000 0000 9995 | Declined (insufficient funds) |
4000 0000 0000 0341 | Declined (card declined) |
4000 0027 6000 3184 | Requires authentication (3D Secure) |
Environment Variables Reference
| Variable | Required | Description |
|---|---|---|
STRIPE_SECRET_KEY | Yes | API secret key from Stripe |
STRIPE_WEBHOOK_SECRET | Yes | Webhook signing secret |
NEXT_PUBLIC_STRIPE_PRICE_ID_PRO | No | Price ID for the Pro plan |
NEXT_PUBLIC_STRIPE_PRICE_ID_ENTERPRISE | No | Price ID for the Enterprise plan |
NEXT_PUBLIC_STRIPE_PRICE_ID_FREE | No | Price ID for the Free plan (optional) |
Related Docs
- Background Jobs (Inngest) — webhook processing runs through Inngest
- GCP Deployment — production deployment with Secret Manager
- Authentication (Clerk) — organization-based billing context
Ready to build with VibeReady?
Get the full AI-native SaaS foundation with production infrastructure, AI development framework, and all integrations.
Get VibeReady — From $149