Plans & quotas
Plan catalog, metered usage, quota enforcement, and checkout.
Plans
The catalog is returned by GET /v1/plans. The built-in plans are free,
pro, growth, and enterprise, each with per-kind limits. View and switch the
current plan in the console's Billing view or via the API:
curl http://localhost:8080/v1/subscription -H "Authorization: Bearer <KEY>"
curl -X POST http://localhost:8080/v1/subscriptions \
-H "Authorization: Bearer <KEY>" -H "Content-Type: application/json" \
-d '{"plan":"pro"}'Metered usage
GET /v1/usage returns per-kind counters for the current period:
| Kind | Counts |
|---|---|
connect | connections started |
active_domain | live domains |
cert | certificates issued |
api_call | API calls |
Quota enforcement
Quota is enforced on the control-plane write path only — never on the edge
ask hot path, so serving traffic never blocks on billing. When a connect would
exceed the plan limit, POST /v1/connections returns:
{ "error": { "code": "QuotaExceeded", "message": "…", "limit": 3, "plan": "free", "upgrade_url": "…" } }Reservation is atomic under a Postgres advisory lock: N concurrent creates
over a limit yield exactly limit successes and the rest 402.
Checkout
POST /v1/billing/checkout returns a provider checkout URL. The billing provider
is behind an interface; the default is a no-op stub, and a Stripe backend can be
wired in. When no provider is configured, checkout returns
502 billing_unavailable.