REST API
src/content/docs/docs/reference/rest-api.md · verified against cerbix f5240f5Edit on GitHub ↗The cerbix UI is built on the same REST API you can call from scripts and pipelines. This page covers the conventions every endpoint shares and maps the main resource groups. The OpenAPI file is the reference for individual routes, request bodies and responses.
Base URL and format
Section titled “Base URL and format”The API is served by the api and all roles on the same origin as the UI, under /api/v1. Requests and responses are JSON, except the event stream and the status-page feeds.
The binary mounts several route trees side by side:
| Prefix | Authentication | Purpose |
|---|---|---|
/api/v1/ |
Session cookie or bearer credential | The main API. |
/api/v1/public/ |
None | Status pages, subscriptions, push heartbeats, branding. |
/api/v1/agent/ |
Agent token | HTTP-pull agents. |
/auth/ |
None | Sign-in, callback, sign-out. |
/healthz, /readyz, /metrics |
None | Operational endpoints. See Metrics and alerts. |
Authentication
Section titled “Authentication”The main API accepts three kinds of credential, checked in this order:
| Credential | How it is sent | Notes |
|---|---|---|
| Session cookie | Cookie cerbix_session (configurable with session.cookie_name) |
Issued by POST /auth/local/login or by the OIDC flow GET /auth/login → GET /auth/callback. HttpOnly, SameSite=Lax; Secure when session.secure is set. |
| API token | Authorization: Bearer cbx_… |
A service-account token issued per organization. |
| OIDC client-credentials JWT | Authorization: Bearer <jwt> |
Accepted when OIDC is active. cerbix verifies issuer and signature; it does not check the audience. The token subject is provisioned as a user on first use and gets only the access its memberships grant. |
A request without a valid credential gets 401 with {"error":"unauthorized"}. GET /auth/config reports which sign-in methods are enabled. See OIDC.
API tokens
Section titled “API tokens”An org admin issues tokens with POST /api/v1/organizations/{orgID}/tokens. The body sets name, role, an optional project_id (omit it for an org-scoped token) and an optional actions allow-list. The secret appears once, in the token field of the 201 response.
The allow-list only narrows what the role grants. It cannot be changed after creation; issue a new token instead. A token for CI that asks the gate and records changes, and can do nothing else:
{ "name": "ci-checkout-api", "role": "editor", "project_id": "<project-id>", "actions": ["gate:evaluate", "change:record"]}Authorization
Section titled “Authorization”Roles are org_admin, project_admin, editor and viewer. Some routes need a global admin. A caller who is not a member of the organization or project gets 404, so existence is not revealed. A member with too low a role gets 403.
Errors
Section titled “Errors”Every error body has one field:
{"error": "<message>"}Many 400 responses carry a stable code in error, such as limit_invalid, cursor_invalid or range_required. Each route’s codes are listed in the OpenAPI file.
Pagination
Section titled “Pagination”Ledger-style lists use keyset pagination:
| Parameter | Meaning |
|---|---|
limit |
Page size, 1–200, default 50. Anything else is 400 limit_invalid. |
cursor |
Opaque. Pass the next_cursor of the previous page. |
next_cursor |
In the response; null on the last page. |
This applies to GET /api/v1/projects/{projectID}/gate/decisions, GET /api/v1/projects/{projectID}/services/{serviceID}/changes (where limit counts change groups) and GET /api/v1/projects/{projectID}/monitors/{monitorID}/expected-runs. The traversal is live: rows committed during it may or may not appear. A few other lists accept limit only: heartbeats, the audit logs and the dead-letter outbox.
Rate limits
Section titled “Rate limits”POST /api/v1/projects/{projectID}/services/{serviceID}/gate is bounded per process. Each api or all replica keeps its own counters, so the cluster allowance grows with the replica count.
| Config key | Default | Refusal code |
|---|---|---|
gate.evaluate_inflight_process |
8 |
process_inflight |
gate.evaluate_inflight_principal |
2 |
principal_inflight |
gate.evaluate_rate_principal_per_minute |
10 |
principal_rate |
gate.evaluate_rate_process_per_minute |
60 |
process_rate |
A refused request gets 429 with the code in error and a Retry-After header. Retry-After is 1 for an in-flight refusal and the whole seconds until the next token for a rate refusal. A refused request runs no evaluation and writes no ledger row. Do not retry into a 429. Gate ledger reads take the in-flight permits but no rate token.
POST /api/v1/projects/{projectID}/services/{serviceID}/changes has its own bounds: change.record_inflight_process (default 32), change.record_rate_principal_per_minute (default 30) and change.record_rate_process_per_minute (default 300). Change timeline, comparison and incident-change reads share change.read_inflight_process (default 64). Local sign-in and password-reset requests share a per-client-IP limit, local.login_rate_limit_per_minute (default 10 per minute).
Live events
Section titled “Live events”GET /api/v1/events is a Server-Sent Events stream of monitor status changes, filtered to the projects the caller can see.
: connected
event: statusdata: {"type":"status","monitor_id":"<id>","project_id":"<id>","status":"down","latency_ms":0,"ts":"<timestamp>"}
event: pingdata: {}status is up, down or pending. A ping event arrives every 25 s so clients can detect a dead connection. The event bus is in-process: a stream carries the status changes ingested by the replica it is connected to.
Public routes
Section titled “Public routes”These routes need no credential. Request bodies are capped at 64 KiB.
| Route | Purpose |
|---|---|
GET /api/v1/public/status-pages/{slug} |
Render a status page. Unlisted pages need ?token=; internal pages return 404. |
GET /api/v1/public/status-pages/{slug}/feed |
Incident feed: RSS by default, ?format=atom or ?format=json. |
POST /api/v1/public/status-pages/{slug}/subscribers |
Subscribe to updates. |
POST /api/v1/public/subscriptions/{token}/confirm |
Confirm a subscription. |
DELETE /api/v1/public/subscriptions/{token} |
Unsubscribe. |
POST /api/v1/public/push/{token} |
Push heartbeat for a push monitor; ?status=down reports a failure. |
GET /api/v1/public/branding |
Instance branding for the sign-in page. |
See Status pages.
Agent routes
Section titled “Agent routes”HTTP-pull agents (cerbix serve --role agent) use /api/v1/agent/* to claim jobs, report results and heartbeat. These routes are mounted only when pull.token, pull.agents or pull.regions is configured, and are not part of the OpenAPI file.
An agent authenticates with Authorization: Bearer <token> and names its region with ?region=. Three token sources are accepted: the catch-all pull.token, a per-region pull.agents[].token, and database-managed tokens issued by a global admin through /api/v1/agent-tokens. A wrong token gets 401. See Geo probers.
Resource groups
Section titled “Resource groups”Representative routes. All paths start with /api/v1.
| Group | Representative routes |
|---|---|
| Identity | GET /me, GET /version, POST /me/password, POST /me/totp/enroll |
| Organizations and members | GET /organizations, GET /organizations/{orgID}/projects, GET /organizations/{orgID}/members, GET /organizations/{orgID}/audit |
| Projects | GET /projects/{projectID}, GET /regions |
| Monitors | GET /projects/{projectID}/monitors, POST /projects/{projectID}/monitors/test, PATCH /monitors/{monitorID}, GET /monitors/{monitorID}/heartbeats |
| Services and reliability | GET /projects/{projectID}/services, PUT …/services/{serviceID}/declaration, GET …/services/{serviceID}/reliability, GET …/services/{serviceID}/reliability/series |
| SLA and availability | GET /projects/{projectID}/sla, PUT /projects/{projectID}/sla-target, GET /monitors/{monitorID}/availability |
| Release gate | POST …/services/{serviceID}/gate, PUT …/services/{serviceID}/gate/policy, POST …/services/{serviceID}/gate/override, GET /projects/{projectID}/gate/decisions |
| Changes | POST …/services/{serviceID}/changes, GET …/services/{serviceID}/changes/compare, GET /projects/{projectID}/incidents/{incidentID}/changes |
| Incidents | GET /projects/{projectID}/incidents, POST /incidents/{incidentID}/updates, PUT /incidents/{incidentID}/postmortem, POST /projects/{projectID}/alerts/alertmanager |
| Maintenance | GET /projects/{projectID}/maintenance, POST /projects/{projectID}/maintenance/preview |
| On-call | GET /projects/{projectID}/escalation-policies, GET /projects/{projectID}/oncall-schedules, GET /oncall-schedules/{scheduleID}/current |
| Notifications | GET /projects/{projectID}/notification-channels, GET /organizations/{orgID}/webhooks, POST /monitors/{monitorID}/notifications |
| Status pages | GET /organizations/{orgID}/status-pages, GET /status-pages/{pageID}/render, POST /status-pages/{pageID}/components |
| Secrets | GET /projects/{projectID}/secrets, POST /projects/{projectID}/secrets |
| Tokens | GET /organizations/{orgID}/tokens, DELETE /tokens/{tokenID}, GET /agent-tokens |
| Search and events | GET /search, GET /events |
| Instance settings | GET /settings/oidc, PUT /settings/branding, GET /settings/auth-policy, PUT /settings/monitor-defaults |
| Administration | GET /admin/users, GET /admin/audit, GET /admin/file-providers, GET /admin/outbox/dead |
… stands for /projects/{projectID}. Related pages: Services, Release gate, Change intelligence, Incidents, On-call.