Billing Provider Editions

Choose one provider edition, map its catalog, verify signed events, and run the durable billing worker before accepting live payments.

On this page

Provider setup matrix

Use the row that matches the branch you received. A buyer checkout should contain one row's provider code and credentials, not all five rows' SDKs.

ProviderProvider environmentCatalog keyRequired provider valuesModelsWebhook
StripeTest mode or live modestripePriceIdSTRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, BILLING_PORTAL_CONFIGURATION_IDAll five/api/webhooks/stripe/billing
Lemon SqueezyStore/test or livelemonsqueezyVariantIdLEMONSQUEEZY_API_KEY, LEMONSQUEEZY_STORE_ID, LEMONSQUEEZY_WEBHOOK_SECRETAll five/api/webhooks/lemonsqueezy
Dodo Paymentstest_mode or live_modedodoProductIdDODO_PAYMENTS_API_KEY, DODO_PAYMENTS_WEBHOOK_KEY, DODO_PAYMENTS_ENVIRONMENTAll five/api/webhooks/dodo
Polarsandbox or productionpolarProductIdPOLAR_ACCESS_TOKEN, POLAR_WEBHOOK_SECRET, POLAR_SERVERAll five/api/webhooks/polar
Creemtest_mode or live_modecreemProductIdCREEM_API_KEY, CREEM_WEBHOOK_SECRET, CREEM_ENVIRONMENTRecurring, one-time, credits/api/webhooks/creem

Provider launch sequence

  1. 1

    Create provider resources in test mode

    Create products, recurring prices or variants, one-time offers, meters, and portal settings in the provider's test or sandbox environment. Keep the provider mode aligned with the environment and catalog IDs.

    • One resource for each selected plan or offer
    • One catalog mapping for every enabled billing model
    • No production credentials in local development
  2. 2

    Set the runtime controls

    The active provider edition supplies provider identity. Set model selection and catalog configuration explicitly; keep production locks enabled when deployment configuration must be authoritative.

    text
    BILLING_ENABLED_MODELS=licensed_recurring,prepaid_credits
    BILLING_PRESET=hybrid
    BILLING_MODELS_LOCKED=true
    BILLING_CATALOG_JSON=<validated-catalog-json>
    BILLING_WEBHOOK_BATCH_SIZE=20
    BILLING_WEBHOOK_CONCURRENCY=5
  3. 3

    Register the application webhook

    Configure the provider dashboard with the matching HTTPS endpoint and signing secret. The route verifies the unmodified request body and stores a durable verified event before projection.

    • Stripe: /api/webhooks/stripe/billing
    • Lemon Squeezy: /api/webhooks/lemonsqueezy
    • Dodo: /api/webhooks/dodo
    • Polar: /api/webhooks/polar
    • Creem: /api/webhooks/creem
  4. 4

    Deploy the optional Supabase Edge ingress

    The shared billing-webhooks Edge Function can verify and enqueue provider events close to Supabase. It does not replace the Next.js billing projection worker. Keep one public destination active for each provider event while testing the rollout.

    text
    pnpm dlx supabase secrets set --env-file supabase/.env.edge
    pnpm dlx supabase functions deploy billing-webhooks --no-verify-jwt
  5. 5

    Schedule the billing worker

    Run GET /api/cron/billing-webhooks every 1–5 minutes with Authorization: Bearer <CRON_SECRET>. The worker claims verified events, retries transient failures, and moves exhausted events to dead letter. Schedule each job once through Supabase Cron, the hosting provider, or one external scheduler.

    • Keep BILLING_WEBHOOK_BATCH_SIZE bounded
    • Keep concurrency below the batch size
    • Alert on queue age, failed attempts, and dead letters
    • Never log raw provider payloads or secrets
Implementation reference3 areas

These Product code locations explain how the documented behavior is implemented. Expand them when you are ready to customize or maintain this area.

Edition lock and adapter composition

Distribution metadata and the selected adapter composition keep provider-specific dependencies out of the buyer's runtime boundary.

  • src/config/product-distribution.ts
  • src/features/billing/server/providers/runtime/selected.ts
  • src/features/billing/server/providers/runtime/adapter-contract.ts

Provider implementation boundaries

Each provider owns its checkout, pricing, portal, usage, refund, and webhook normalization behavior behind app-owned billing contracts.

  • src/features/billing/server/providers/stripe/checkout.ts
  • src/features/billing/server/providers/lemonsqueezy/checkout.ts
  • src/features/billing/server/providers/dodo/checkout.ts
  • src/features/billing/server/providers/polar/checkout.ts
  • src/features/billing/server/providers/creem/checkout.ts

Durable event projection

The selected ingress and worker separate signature verification from provider projection, allowing retries and duplicate delivery to be handled safely.

  • src/app/api/cron/billing-webhooks/route.ts
  • src/features/billing/server/webhooks/cron.ts
  • src/features/billing/server/webhooks/worker.ts
  • supabase/functions/billing-webhooks/handler.ts

Reference paths are relative to the delivered product checkout.

Ready for live billing when

  • The selected branch and provider mode match the credentials and catalog IDs.
  • Every enabled billing model has a provider resource and a validated catalog entry.
  • A signed test webhook creates exactly one durable event and one local projection.
  • A replayed or duplicate webhook does not create a second order, entitlement, credit grant, or notification.
  • Portal, cancellation, refund, usage, and credit behavior has been tested where supported.
  • The billing worker is scheduled once, monitored, and has an owner for dead-letter recovery.