Billing
Not in
openapi.jsonyet. Written fromsrc/ResilientLang.Billinganddocs/work/WP-23.md; a test checks the routes against the source. Prices are the approved launch proposal and will be revisited after the first customers. No live payment provider is connected: the Stripe adapter is test mode only.
Routes (/v1/billing)#
| Route | Who | Purpose |
|---|---|---|
GET /v1/billing/plans | public | The plan catalogue: code, name, family, currency, monthlyPriceCents, annualPriceCents, sites, targetLanguages, aiWords, allowancePeriod, features, isCustom |
GET /v1/billing/entitlements | owner or admin | The tenant's plan and state, site and language limits, AI-word allowance and use for the current window, grace end and bundle retention end |
GET /v1/billing/invoices?limit= | owner or admin | Invoices, newest first (default 20) |
POST /v1/billing/checkout | owner | { planCode, interval, wordPacks?, successUrl, cancelUrl, email? } returns { url } to the provider's checkout page. Needs an Idempotency-Key header (400 without it). Redirect hosts must be on the configured allow list |
POST /v1/billing/portal | owner | { returnUrl } returns { url } to the provider's customer portal |
POST /v1/billing/webhooks/{provider} | provider only | Signed provider events (Stripe: Stripe-Signature). Body limit 256 KiB. Not for customers |
Access is decided by the signed-in role (rl_role claim). The scopes billing:read and billing:manage exist on API keys, but the billing routes check the role only, so a secret key is refused for now (verify when the scope check is added).
Plan limits answer 402, not 403#
When a plan, allowance or licence blocks an action, the API answers 402 with a problem that names the code; 403 stays for permission. Published bundles are never taken down by billing. See Errors for the codes and the quota operation in the reference to check your allowance first.
A lapse follows the rules in Licensing: serving, export and the dashboard always continue; translating, adding languages and publishing stop.