Skip to main content
All endpoints below require an email-verified session unless stated otherwise.

GET /api/billing/overview

Summarises the caller’s balances, active subscription, latest usage transactions, and pay-as-you-go pricing table.

GET /api/billing/plans

Returns the plan catalog as configured in lib/billing/plans. Each plan view includes the Stripe price ID, marketing copy, and the computed monthly price/discount figures. No authentication required beyond optional sessions.

POST /api/billing/subscription

  • Body{ "priceId": "<stripe price id>" }.
  • Behavior – validates the price against the internal catalog, ensures currency compatibility with the active plan, calculates prorated credits for upgrades, and returns { url }, the Stripe Checkout session.
  • Errors – HTTP 400 for unknown price IDs, disallowed downgrades, or cross-currency switches. HTTP 500 if the checkout session cannot be created.

POST /api/billing/top-up

  • Body{ "amount": "25", "currency": "USD" }.
  • Response{ url } (Stripe Checkout session).
  • Validation – only the default currency is accepted. Amount must parse as a decimal string.

POST /api/billing/portal

Creates a Stripe billing-portal session so users can manage payment methods or cancel plans themselves. Returns { url }.

POST /api/stripe/webhook

Stripe sends signed events to this endpoint. Requirements:
  • Add the endpoint to your Stripe dashboard with the same signing secret configured in STRIPE_WEBHOOK_SECRET.
  • Send the raw body and stripe-signature header untouched; the handler uses them to validate the event.
  • Events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, and any others you need for bookkeeping.
Responses follow Stripe’s convention: { "received": true } on success, HTTP 4xx/5xx otherwise. Errors are logged to help with debugging misconfigurations.