zazzy
Features

Billing

Stripe subscriptions, trials, customer portal, and webhooks.

Billing integrates Stripe for subscriptions: a plan picker, checkout, the hosted customer portal, per-seat quantity sync, and webhook processing. The local Subscription row is always a cached projection of Stripe — written only by webhook processing, never the source of truth. Plans are declared in config/plans.ts, which also seeds the marketing pricing page.

Optional feature

Billing is optional (core: false, requires: ["orgs", "email", "jobs"]). It owns the plan side of the entitlement seam that flags composes.

What it does

  • Plansconfig/plans.ts declares plan keys, prices, and entitlements; PlanPicker renders them (reused by the marketing pricing page).
  • Checkout & portal — Stripe Checkout for new subscriptions and the hosted billing portal for changes, from BillingSettings.
  • Webhooks/api/webhooks/stripe verifies the signature, records the event in an idempotency ledger, and enqueues a job that upserts the Subscription projection.
  • Seat syncenqueueSeatsSync(orgId) (called by orgs on membership change) reconciles the Stripe per-seat quantity to the live member count, best-effort and idempotent.
  • Metered usage pushreportOrgMeterUsage is the Stripe Meters seam the usage feature reports rolled-up totals through.
  • Plan resolutiongetPlanEntitlements maps a subscription (incl. an admin planKeyOverride) to plan-default entitlements; flags overlays per-org overrides on top.

Models it adds

ModelPurpose
SubscriptionCached projection of an org's Stripe subscription (plan, status, trial, seat quantity). One row per org; Free orgs have none.
StripeEventWebhook idempotency ledger keyed by Stripe event id — a replayed event is skipped exactly once.

Adds the marker-wrapped Organization.subscription relation.

Env it needs

STRIPE_SECRET_KEY=                      # server-side Stripe API key
STRIPE_WEBHOOK_SECRET=                  # signing secret for /api/webhooks/stripe
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=     # client-side publishable key

Adds the stripe:sync script (push local plans to Stripe) and the stripe compose service (webhook forwarding in dev).

Composition

  • requires: ["orgs", "email", "jobs"] — subscriptions are org-scoped, receipts are emailed, and webhook/seat work runs as jobs (billing/stripe-event, billing/seats.sync).
  • Dependentsflags requires: ["billing"] (and through flags, usage and admin); marketing requires: ["billing"] for the pricing page.
  • Exposes getSubscriptionSummary / setPlanKeyOverride for the admin panel.

What pruning removes

Leaving billing out drops features/billing, config/plans.ts, the /api/webhooks/stripe route, the billing settings page, the Subscription and StripeEvent models, the Organization.subscription relation, and the billing jobs — plus the stripe compose service and the stripe:sync script. Because flags requires billing, deselecting billing also removes flags, and transitively usage, admin, and marketing.

On this page