billing
Covers 6 API operations in the billing category.
| Method | Path | Description |
|---|---|---|
| POST | /v1/hooks/polar | Polar billing webhook |
| GET | /v1/orgs/{orgSlug}/billing | Org's plan and billing status |
| POST | /v1/orgs/{orgSlug}/billing/checkout | Creates a checkout session for the Pro plan |
| POST | /v1/orgs/{orgSlug}/billing/portal | Creates a customer portal session (payment methods, receipts, cancellation) |
| POST | /v1/orgs/{orgSlug}/billing/session | Customer session token (authenticates the payment method embed) |
| POST | /v1/orgs/{orgSlug}/billing/cancel | Schedules or reverses cancellation at period end |
POST /v1/hooks/polar
This is not a path you call. Polar delivers subscription events here. Authentication
is not a token but a Standard Webhooks signature — it is verified from the three
headers webhook-id, webhook-timestamp, and webhook-signature together with the
server's RUNLOT_POLAR_WEBHOOK_SECRET (otherwise 403, timestamp within ±5 minutes). The
same webhook-id is applied only once (a redelivery returns 200 and is ignored).
This is what moves an organization between plans: for subscription.active and
updated, status active/trialing/past_due maps to Pro, and everything else
(canceled, unpaid, and so on) maps to Free. Returns 501 if the server has no token.
Client libraries do not call this.
operationId polarHook
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | received (if applied is true, the plan changed) | — |
| 400 | — | — |
| 403 | the signature does not match | — |
| 501 | billing is off | — |
GET /v1/orgs/{orgSlug}/billing
Returns the plan (plan) and, for Pro, its status (status: active · past_due ·
canceled · granted) and the end of the current period (periodEnd). granted is Pro
provided by Runlot with no subscription: nothing is billed, and usage above the
included amounts is included. If enabled is false, billing is not configured for this
deployment and the screen shows only a contact address. If sandbox is true, this is a
test environment, so there is no real billing.
limits is the limit table for the two plans. Requires viewer or higher.
operationId getBilling
| Status code | Description | Response body |
|---|---|---|
| 200 | Billing status | BillingStatus |
| 403 | — | — |
| 404 | — | — |
POST /v1/orgs/{orgSlug}/billing/checkout
Creates a single Polar checkout session and returns its url. The dashboard displays
that URL in an iframe on its own page (the session's embed_origin is the origin
of returnTo). Completing payment does not change the plan by itself: the plan
changes once Polar's webhook arrives, and the screen re-reads state after the success
event.
returnTo must be under this deployment's public URL, otherwise 400. If the org is
already Pro, 409 already_pro — open the billing portal instead. Requires admin.
operationId createBillingCheckout
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | Checkout session | object |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 409 | already_pro | Error |
| 501 | billing_off — billing is not configured | — |
| 502 | billing_unavailable — Polar is not responding | — |
POST /v1/orgs/{orgSlug}/billing/portal
Returns a one-time url for the Polar customer portal. Payment methods,
receipts, and cancellation are all handled there, so card details never
reach runlot. An org that has never made a payment returns 404.
Requires admin.
operationId createBillingPortal
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | Portal session | object |
| 400 | — | — |
| 403 | — | — |
| 404 | — | — |
| 501 | billing_off | — |
| 502 | billing_unavailable | — |
POST /v1/orgs/{orgSlug}/billing/session
Returns the customer session token required by the payment method embed. It is valid for 1 hour and for that one customer, so fetch a fresh one each time the screen opens. An org with no billing history returns 404. Requires admin.
operationId createBillingSession
| Status code | Description | Response body |
|---|---|---|
| 200 | Customer session | object |
| 403 | — | — |
| 404 | — | — |
| 501 | billing_off | — |
| 502 | billing_unavailable | — |
POST /v1/orgs/{orgSlug}/billing/cancel
With cancel: true, Pro ends at the close of the current period and stays active until
then. false reverses a scheduled cancellation. There is no immediate revocation: the
period already paid for is used in full. The response reflects the new status right
away. If the org is not Pro, 409 not_pro. Requires admin.
operationId cancelBilling
Request body: application/json · object
| Status code | Description | Response body |
|---|---|---|
| 200 | The status that changed | object |
| 403 | — | — |
| 404 | — | — |
| 409 | not_pro | Error |
| 501 | billing_off | — |
| 502 | billing_unavailable | — |