Skip to content
Docs

Command palette

Jump to a page or view, or find a todo by name.

Changelog

Payments

Stripe, Polar and RevenueCat feed one server-verified entitlement model.

Markdown

Enable providers deliberately

All providers start off. Set BILLING_PROVIDERS to the required comma-separated names: stripe, polar, revenuecat. Each listed provider must have its complete valid configuration. BILLING_ENVIRONMENT distinguishes SANDBOX from PRODUCTION; Stripe key mode must agree.

Stripe and Polar sell on the web. RevenueCat connects store purchases on mobile. If both web providers are enabled, BILLING_CHECKOUT_PROVIDER chooses new checkouts; existing customers retain their provider portal. Visibility separately uses billing.web and billing.mobile.

Entitlements and webhooks

Paid Access belongs to the User, not an Organization. The server's entitlement read model projects enabled-provider rows in the current environment. Device-reported purchases alone grant nothing. RevenueCat reconciliation replaces only its provider rows; Stripe and Polar apply signed, deduplicated events in transactions.

ProviderWebhook pathServer secrets
Stripe/api/billing/stripeSTRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_IDS
Polar/api/billing/polarPOLAR_ACCESS_TOKEN, POLAR_WEBHOOK_SECRET, POLAR_PRODUCT_IDS
RevenueCat/api/billing/revenuecatREVENUECAT_SECRET_API_KEY, REVENUECAT_WEBHOOK_AUTHORIZATION, REVENUECAT_WEBHOOK_SIGNING_SECRET

Configure RevenueCat app and entitlement IDs too. Public platform SDK keys belong in the mobile environment; server keys do not. Raw webhook verification precedes payload parsing. A replay is a no-op, and a failed write rolls back its dedupe record so the provider can retry.

Extend and test

Add plans to the leaf billing-plans.ts, map provider product IDs in env, and add name/description translations. Checkout return URLs come from the server, never a client-supplied redirect. Test purchases in sandbox and verify billing.status, cancellation and webhook replay before enabling production visibility.

Stripe and Polar currently rely on webhooks plus the grace window; no scheduled pull reconciles their subscriptions. RevenueCat verification has a freshness bound. Native purchases require a development build with the SDK, not just a successful TypeScript check. See ADR-0004.

Key files

Edit on GitHubDocumentation is in English.