Stripe and Lemon Squeezy

The environment variables and settings for each payment provider, and how to switch between them.

Choose the provider

Set the provider in two places so the app and the database agree:

  1. NEXT_PUBLIC_BILLING_PROVIDER=stripe or lemon-squeezy.
  2. billing_provider in the public.config row (stripe by default, from apps/web/supabase/schemas/02-config.sql).

billing.config.ts is validated against the provider at build time.

Stripe

VariableNotes
STRIPE_SECRET_KEYServer only. Must start with sk_ or rk_
STRIPE_WEBHOOK_SECRETServer only. Must start with whsec_
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYMust start with pk_. Required unless you use the hosted checkout page
STRIPE_UI_MODEembedded_page (default) shows checkout inside your app; hosted_page sends users to Stripe's page
STRIPE_ENABLE_TRIAL_WITHOUT_CCtrue lets users start a plan's trial without entering a card

The Stripe package checks these prefixes and stops with a message naming the variable if one is wrong.

In the Stripe dashboard:

  • Create the products and prices, and copy each price id into billing.config.ts.
  • Add a webhook endpoint for https://<your-domain>/api/billing/webhook. The handler acts on checkout.session.completed, checkout.session.async_payment_succeeded, checkout.session.async_payment_failed, customer.subscription.updated, customer.subscription.deleted and invoice.paid.
  • Turn on the customer portal so users can manage their plan.

Lemon Squeezy

VariableNotes
LEMON_SQUEEZY_SECRET_KEYAPI key, server only
LEMON_SQUEEZY_SIGNING_SECRETThe webhook signing secret
LEMON_SQUEEZY_STORE_IDYour store id

In Lemon Squeezy:

  • Create the products and variants, and use the variant ids as line item ids in billing.config.ts.
  • Add a webhook for https://<your-domain>/api/billing/webhook with the signing secret above. The handler acts on order_created, subscription_created, subscription_updated, subscription_expired and subscription_payment_success.

Lemon Squeezy plans can have only one line item. The config schema rejects more.

Test mode

Use test keys while you build. With Stripe test mode, the card 4242 4242 4242 4242 completes checkout. Run pnpm stripe:listen to receive webhooks locally (see Webhooks).