Overview
The starter persists billing state in Postgres (subscriptions table) and includes:
- Stripe: checkout + webhooks + billing portal (wired by default)
- Polar: webhook handler included; you can swap checkout/UI if you prefer Polar
Stripe is the default UI/provider in tanstarter/src/components/payments/PricingPlans.tsx.
Stripe (default)
1) Create products + prices in Stripe
- Create an account: Stripe Dashboard
- Use Test mode while developing.
- Create products/prices that match your plans (example: Pro/Enterprise):
- Billing: recurring monthly (or yearly)
- Copy each Price ID (it starts with
price_)
Stripe docs:
2) Set environment variables
In tanstarter/.env:
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
VITE_STRIPE_PRICE_BASIC=price_...
VITE_STRIPE_PRICE_PRO=price_...
VITE_STRIPE_PRICE_ENTERPRISE=price_...
Optional (recommended for production):
STRIPE_SUCCESS_URL=https://yourdomain.com/dashboard
STRIPE_RETURN_URL=https://yourdomain.com/pricing
PUBLIC_BASE_URL=https://yourdomain.com
Notes:
VITE_STRIPE_PRICE_*is read by the pricing UI in the browser.PUBLIC_BASE_URLis used as a fallback return URL for the billing portal.
3) Configure Stripe webhooks
Webhook endpoint (production):
https://yourdomain.com/api/webhooks/stripe
Subscribe to these events (used by tanstarter/src/payments/stripe/server/webhook.ts):
customer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deleted
Stripe docs:
Local webhook testing (Stripe CLI)
- Install Stripe CLI: Stripe CLI
- Run:
stripe listen --forward-to http://localhost:3000/api/webhooks/stripe
Then put the printed signing secret into STRIPE_WEBHOOK_SECRET.
4) Enable the Stripe customer portal (for “Manage subscription”)
The app redirects users to GET /api/portal (see tanstarter/src/routes/api/portal.ts).
In the Stripe Dashboard, enable/configure the customer portal:
Polar (optional)
1) Create products in Polar
- Create an account: Polar
- Create products/prices in Polar.
- Configure a webhook endpoint.
Polar docs:
2) Set environment variables
In tanstarter/.env:
POLAR_ACCESS_TOKEN=polar_oat_...
POLAR_WEBHOOK_SECRET=polar_whs_...
POLAR_MODE=sandbox # or production
Optional:
POLAR_SUCCESS_URL=https://yourdomain.com/dashboard
3) Configure Polar webhooks
Webhook endpoint:
https://yourdomain.com/api/webhooks/polar
Handler: tanstarter/src/payments/polar/server/webhook.ts
Switching to Polar checkout/UI
If you want the pricing page to use Polar:
- Update
tanstarter/src/components/payments/PricingPlans.tsxto export@/payments/polar/ui/PricingPlans. - Update
tanstarter/src/routes/api/checkout.tsto usepolarCheckoutGetfromtanstarter/src/payments/polar/server/checkout.ts.
Then only configure webhooks for the provider(s) you’re using.