10 min read

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:

  1. Create a Stripe account at dashboard.stripe.com/register.
  2. Get test keys from Dashboard, then Developers, then API keys. Copy the Secret key (starts with sk_test_).
  3. Add to .env.local:
STRIPE_SECRET_KEY="sk_test_..."
  1. Restart the dev server:
make dev

Create Products and Prices

You need to create at least one product in Stripe to enable billing.

  1. Go to Stripe Products.
  2. 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_).
  3. Create an “Enterprise” product (optional):
    • Name: Enterprise
    • Description: For large organizations
    • Pricing: $99/month (recurring)
    • Copy the Price ID.
  4. 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.

  1. Install Stripe CLI:
# macOS
brew install stripe/stripe-cli/stripe

# Or download from https://stripe.com/docs/stripe-cli
  1. Login to Stripe:
stripe login
  1. 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.

  1. Add the webhook secret to .env.local:
STRIPE_WEBHOOK_SECRET="whsec_..."
  1. Restart the dev server and keep the Stripe CLI running in a separate terminal.

Test the Flow

  1. Log in as an organization owner.
  2. Go to /dashboard/billing.
  3. Click Upgrade to Pro to open Stripe Checkout.
  4. Use test card 4242 4242 4242 4242 (any future expiry, any CVC).
  5. Complete checkout. You will be redirected to the billing page.
  6. Check the Inngest dashboard at http://localhost:8288 to verify the process-stripe-webhook function ran successfully.

Production Setup

1. Get Production Keys

  1. Go to the Stripe Dashboard and ensure Test mode is off.
  2. Navigate to Developers, then API keys.
  3. 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

  1. Go to Developers then Webhooks in the Stripe Dashboard.
  2. Click Add endpoint.
  3. Set the endpoint URL to https://your-domain.com/api/webhooks/stripe.
  4. Select the following events:
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_failed
  5. 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

  1. Go to Settings then Billing then Customer Portal.
  2. Under Subscriptions, enable:
    • “Customers can switch plans”
    • “Prorate subscription changes”
  3. Click Add product and add your Pro and Enterprise products.
  4. 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.

  1. Go to Settings then Billing then Subscriptions and emails.
  2. Under Manage failed payments, enable:
    • “Send emails about expiring cards”
    • “Send emails when card payments fail”
  3. 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

IssueFix
”Billing Not Configured”Set STRIPE_SECRET_KEY in .env.local.
Upgrade button does nothingCheck browser console for errors and verify price IDs.
Webhook errorsCheck STRIPE_WEBHOOK_SECRET and ensure Stripe CLI is running.
Subscription not updatingCheck the Inngest dashboard for errors.
”No such price” errorVerify price IDs match those in the Stripe Dashboard.
503 on billing endpointsStripe is not configured. Set the required environment variables.
Portal shows wrong organizationEnsure stripeCustomerId is set on the organization record.

Common Test Cards

Card NumberScenario
4242 4242 4242 4242Successful payment
4000 0000 0000 9995Declined (insufficient funds)
4000 0000 0000 0341Declined (card declined)
4000 0027 6000 3184Requires authentication (3D Secure)

Environment Variables Reference

VariableRequiredDescription
STRIPE_SECRET_KEYYesAPI secret key from Stripe
STRIPE_WEBHOOK_SECRETYesWebhook signing secret
NEXT_PUBLIC_STRIPE_PRICE_ID_PRONoPrice ID for the Pro plan
NEXT_PUBLIC_STRIPE_PRICE_ID_ENTERPRISENoPrice ID for the Enterprise plan
NEXT_PUBLIC_STRIPE_PRICE_ID_FREENoPrice ID for the Free plan (optional)

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