Configure Stripe
Fast Unicorn supports both one-time payments and subscriptions through Stripe.
This guide shows where the Stripe integration lives, which environment variables it needs, and how checkout, customer linking, and webhook synchronization work together.
What this guide covers
Products and prices
How Stripe price IDs map to the billing tiers expected by the template.
Checkout flows
How one-time payments, subscriptions, and upgrades are created and linked to users.
Webhook synchronization
How long-lived billing state is updated from Stripe events instead of only from the browser.
Main files and folders
| File | Propósito |
|---|---|
src/app/api/stripe/checkout/route.ts | Checkout entrypoint. |
src/app/api/stripe/webhook/route.ts | Webhook endpoint. |
src/server/api/routers/stripe.ts | Billing-related API contracts. |
src/server/services/billing/checkout.ts | Stripe checkout session creation. |
src/server/services/billing/customers.ts | Customer lookup and linking. |
src/server/services/billing/subscription.ts | Tier and price mapping. |
src/server/services/billing/webhooks.ts | Event synchronization logic. |
Required environment variables
| Variable | Propósito |
|---|---|
STRIPE_SECRET_KEY | Stripe server API key. |
STRIPE_PUBLISHABLE_KEY | Stripe publishable key. |
STRIPE_WEBHOOK_SECRET | Stripe webhook secret. |
STRIPE_PRICE_BASIC_ID | Stripe price ID for the BASIC tier. |
STRIPE_PRICE_PRO_ID | Stripe price ID for the PRO tier. |
STRIPE_PRICE_ENTERPRISE_ID | Stripe price ID for the ENTERPRISE tier. |
STRIPE_PRICE_ONE_TIME_ID | Stripe price ID for the ONE_TIME tier. |
NEXT_PUBLIC_APP_URL | Base URL used for app links and checkout redirects. |
Recommended billing sequence
Use this order when enabling or changing billing behavior.
Create products and prices in Stripe
Define the products you want to sell and copy the generated price IDs into the environment variables expected by the app.
Review the billing services
Confirm the checkout and subscription services map those price IDs to the tiers and checkout modes you want to support.
Configure webhook delivery
Point Stripe or Stripe CLI to the local webhook endpoint so subscription and payment events can sync correctly.
Test the full billing lifecycle
Verify checkout creation, webhook processing, customer linking, and billing state updates before shipping changes.
Create your Stripe products
Before using checkout, create the prices you need in Stripe and store their IDs in the environment variables expected by src/env.js.
The billing service maps those IDs to template tiers through src/server/services/billing/webhook-sync.ts.
This keeps price selection centralized instead of scattering Stripe identifiers across routes or UI components.
Checkout flow
The template supports:
- one-time checkout
- subscription checkout
- upgrade checkout
Checkout sessions are created through createStripeCheckoutSession in src/server/services/billing/checkout.ts.
Customer linking
Stripe customers are linked back to the authenticated app user through metadata and the local stripeCustomerId field.
This allows the app to preserve ownership even after checkout redirects or asynchronous webhook delivery.
This lets the app:
- verify ownership
- find active subscriptions
- sync invoices and payments
Why customer linking matters
Billing state should stay connected to a real application user, not only to a Stripe customer record. That makes account recovery, upgrades, and access checks much more reliable.
Webhook route
The webhook endpoint lives at /api/stripe/webhook.
It verifies the Stripe signature and delegates event handling to src/server/services/billing/webhook-sync.ts.
This webhook flow should remain the source of truth for long-lived billing state such as subscription updates and completed payments.
Events currently handled
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedinvoice.payment_succeededpayment_intent.succeeded
Local testing
Use Stripe CLI to forward webhook events:
stripe listen --forward-to http://localhost:3000/api/stripe/webhookThen copy the generated signing secret into STRIPE_WEBHOOK_SECRET.
Extension guidance
When changing billing behavior:
- keep entrypoint validation thin in route handlers
- keep Stripe orchestration in
src/server/services/billing - keep tier logic centralized in
webhook-sync.ts - make webhook sync the source of truth for long-lived billing state
Project structure reminder
If billing logic starts growing, keep route handlers thin and preserve the service boundary. That follows the same separation described in Project Structure.