Payments

Stripe (default) + optional Polar, wired to the subscriptions table.

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

  1. Create an account: Stripe Dashboard
  2. Use Test mode while developing.
  3. 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_URL is 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.created
  • customer.subscription.updated
  • customer.subscription.deleted

Stripe docs:

Local webhook testing (Stripe CLI)

  1. Install Stripe CLI: Stripe CLI
  2. 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

  1. Create an account: Polar
  2. Create products/prices in Polar.
  3. 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:

  1. Update tanstarter/src/components/payments/PricingPlans.tsx to export @/payments/polar/ui/PricingPlans.
  2. Update tanstarter/src/routes/api/checkout.ts to use polarCheckoutGet from tanstarter/src/payments/polar/server/checkout.ts.

Then only configure webhooks for the provider(s) you’re using.