REST API reference
Every operation of the Belvador API: path, required scope, which ones need a person's approval, retries and version checks; generated from the list the server runs.
On this page
Status: live (beta). The REST API answers at https://api.belvador.dev. This page is generated from the same list of operations the gateway runs, so it changes only when the API does. Tools that support OAuth can connect by sign-in instead of a token. Coding agents can use the same operations through the MCP server.
Basics#
Base URL:
https://api.belvador.dev/v1. JSON usessnake_case, times are RFC 3339 in UTC, ids are strings.Authentication: send a personal token (
blv_pat_…, from Account → API tokens) or a service token (blv_svc_…, from Workspace settings → Service accounts) in theAuthorizationheader asBearer blv_…(credentials). Tokens last at most 365 days. A token works only inside its workspace and the projects and environments it was given, and never above the current role of the person or service account behind it.Sign in with OAuth: tools that support OAuth 2.1, such as MCP clients, find Belvador from
https://api.belvador.dev/.well-known/oauth-protected-resourceandhttps://belvador.dev/.well-known/oauth-authorization-server. They register themselves (RFC 7591, or a Client ID Metadata Document), send you to belvador.dev to pick a workspace and permissions, and must use PKCE withS256. Access tokens (blv_oat_…) last 60 minutes; refresh tokens (blv_ort_…) change on every use and stop after 30 days without use. A code or refresh token used twice ends that connection — two refreshes sent at the same moment count as reuse, so refresh one at a time. See and disconnect apps under Account → Connected apps.Errors follow RFC 9457 (
application/problem+json):codeis the stable error code,request_ididentifies the call, anderrors[].pointernames each invalid field, for example/name.Creating something needs an
Idempotency-Keyheader. Sending the same key with the same body within 24 hours returns the first answer again, markedIdempotent-Replayed: true, and creates nothing new. A one-time secret in that answer (a ping token, a key) is never repeated: the replay showsnulland names the field inBelvador-Secret-Withheld. The same key with a different body is refused with 422IDEMPOTENCY_KEY_REUSED.Changing or deleting a monitor, uptime check, SLO, project setting or alert rule needs
If-Matchwith theETagyou last read. Without it the answer is 428; if someone changed it since, 412 — read it again and retry.Lists return
{ "data": [...], "next_cursor": "...", "complete": true }. Passcursorwith the same filters for the next page; a cursor lasts 24 hours and only works for the list that made it.Sensitive operations — keys, members, alert destinations, node changes — answer 403
APPROVAL_REQUIREDand wait for a person; see Approvals.Data stored on your node (issues, events, traces, logs, monitor runs) is marked node data below. The gateway reads it from your node with a ticket that lasts a few minutes and passes the answer through; Belvador's servers neither store nor log it. If your node is offline the answer is 503
NODE_OFFLINE— nothing is served from a copy. Trace and log searches needstartandend, at most 168 hours apart.Rate limits: 300 calls per minute per token and 1200 per workspace, and 4 node-data calls in flight per token. Every answer carries the IETF
RateLimit-PolicyandRateLimitheaders; over the limit the answer is 429RATE_LIMITEDwithRetry-After.Turning it off: revoking a token stops it within about 30 seconds. In an emergency Belvador can pause the API for one workspace or for everyone; calls then answer 503
PUBLIC_API_PAUSEDand the app keeps working.
Approvals#
Sensitive operations never run straight from a token: DSN, upload and ingest keys, ping tokens, members and invites, tokens and service accounts, alert destinations and node changes. They are marked approval in the list below.
The call answers 403
APPROVAL_REQUIREDwithapproval_id,approval_url(a page on belvador.dev),expires_atandstate, and aLink: <…>; rel="approval"header. Nothing has changed yet.A person opens the link, sees exactly what will change, and approves with a code from their authenticator app no older than 10 minutes — or rejects. Most operations need an admin; deleting, rebuilding or recovering the node needs the owner; a new personal token can only be approved by the token's own holder. Requests from service accounts and OAuth apps are also emailed to the workspace's owners and admins.
Send the same request again with the same
Idempotency-Key, or pollGET /v1/approvals/{approval_id}, to read the outcome:executedwith the ids it produced (200),rejected,expiredafter 15 minutes (410), orfailedwith the reason incode.
What always holds:
It runs exactly the request the person saw, once, as that person. If the stored request no longer matches, or the token was revoked or lost its rights meanwhile, it fails and nothing runs.
Secrets it creates — a new key, token or invite link — are shown once to the approving person, never to the caller.
What a person types themselves — the project or node name that confirms a deletion, a bot token, webhook URL or mail password — is never accepted from the caller.
At most 20 requests wait per workspace; more answer 429
RATE_LIMITED.failedwithAPPROVAL_OUTCOME_UNKNOWNmeans it was approved but its result was never recorded. Check the resource before asking again.
Operations#
alert_deliveries#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/alert-deliveries/{delivery_id}/replay | alerts:write | admin | — |
alert_rules#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/alert-rules | alerts:read | viewer | paged |
POST /v1/alert-rules | alerts:write | admin | — |
PUT /v1/alert-rules/{rule_id}/enabled | alerts:write | admin | — |
DELETE /v1/alert-rules/{rule_id} | alerts:write | admin | If-Match |
alerts#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/alerts | alerts:read | viewer | paged |
approvals#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/approvals/{approval_id} | org:read | viewer | — |
audit#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/audit-log | audit:read | admin | paged |
coverage#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/coverage | coverage:read | viewer | — |
PUT /v1/projects/{project_id}/coverage-expectations | coverage:write | member | — |
destinations#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/destinations | alerts:read | viewer | paged |
POST /v1/destinations | destinations:manage | admin | approval · Idempotency-Key |
PATCH /v1/destinations/{destination_id} | destinations:manage | admin | approval |
POST /v1/destinations/{destination_id}/connection | destinations:manage | admin | approval |
DELETE /v1/destinations/{destination_id} | destinations:manage | admin | approval |
PUT /v1/destinations/{destination_id}/recipients | destinations:manage | admin | approval |
POST /v1/destination-recipients/{recipient_id}/resend | destinations:manage | admin | — |
POST /v1/destinations/{destination_id}/test | notifications:write | admin | — |
events#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/issues/{issue_id}/events | events:read | viewer | node data · paged |
GET /v1/issues/{issue_id}/events/{event_id} | events:read | viewer | node data |
incident_rules#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/incident-rules | alerts:read | viewer | — |
POST /v1/incident-rules | alerts:write | admin | — |
DELETE /v1/incident-rules/{rule_id} | alerts:write | admin | — |
incidents#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/incidents | incidents:read | viewer | paged |
GET /v1/incidents/{incident_id} | incidents:read | viewer | — |
POST /v1/incidents/{incident_id}/ack | incidents:write | member | — |
POST /v1/incidents/{incident_id}/resolve | incidents:write | member | — |
POST /v1/incidents/{incident_id}/notes | incidents:write | member | — |
PATCH /v1/incidents/{incident_id} | incidents:write | member | — |
ingest_keys#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/projects/{project_id}/ingest-keys | keys:manage | member | approval · Idempotency-Key |
DELETE /v1/ingest-keys/{key_id} | keys:manage | member | approval |
invites#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/invites | members:manage | admin | approval · Idempotency-Key |
DELETE /v1/invites/{invite_id} | members:manage | admin | — |
issues#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/issues | issues:read | viewer | node data · paged |
GET /v1/issues/{issue_id} | issues:read | viewer | node data |
GET /v1/issues/{issue_id}/stats | issues:read | viewer | node data |
GET /v1/issues/{issue_id}/tags | issues:read | viewer | node data |
GET /v1/issues/{issue_id}/activity | issues:read | viewer | node data |
PATCH /v1/issues/{issue_id} | issues:write | member | node data |
POST /v1/issues/bulk | issues:write | member | node data |
logs#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/logs | logs:read | viewer | node data · start/end · paged |
GET /v1/logs/histogram | logs:read | viewer | node data · start/end |
GET /v1/logs/facets | logs:read | viewer | node data · start/end |
GET /v1/logs/{log_id}/around | logs:read | viewer | node data |
maintenance#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/maintenance-windows | monitors:read | viewer | paged |
POST /v1/maintenance-windows | monitors:write | member | Idempotency-Key |
PATCH /v1/maintenance-windows/{window_id} | monitors:write | member | — |
DELETE /v1/maintenance-windows/{window_id} | monitors:write | member | — |
members#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/members | members:read | viewer | paged |
PATCH /v1/members/{user_id} | members:manage | admin | approval |
DELETE /v1/members/{user_id} | members:manage | admin | approval |
metrics#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/metrics/names | metrics:read | viewer | node data |
GET /v1/metrics/series | metrics:read | viewer | node data · paged |
GET /v1/metrics/query | metrics:read | viewer | node data · start/end |
monitors#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/monitors | monitors:read | viewer | paged |
GET /v1/monitors/{monitor_id} | monitors:read | viewer | — |
POST /v1/monitors | monitors:write | member | Idempotency-Key |
PATCH /v1/monitors/{monitor_id} | monitors:write | member | If-Match |
DELETE /v1/monitors/{monitor_id} | monitors:write | member | If-Match |
PUT /v1/monitors/{monitor_id}/pause | monitors:write | member | — |
PUT /v1/monitors/{monitor_id}/mute | monitors:write | member | — |
DELETE /v1/monitor-discoveries/{discovery_id} | monitors:write | member | — |
GET /v1/monitors/{monitor_id}/signal | monitors:read | viewer | node data |
GET /v1/monitors/{monitor_id}/occurrences | monitors:read | viewer | node data · paged |
POST /v1/monitors/backtest | monitors:read | viewer | node data |
node#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/node | org:read | viewer | — |
POST /v1/node | node:operate | admin | approval · Idempotency-Key |
POST /v1/node/jobs/{job_id}/retry | node:operate | admin | — |
POST /v1/node/{node_id}/resize | node:operate | admin | approval |
POST /v1/node/{node_id}/upgrade | node:operate | admin | — |
DELETE /v1/node/{node_id} | node:operate | admin | approval |
POST /v1/node/{node_id}/restore | node:operate | admin | — |
POST /v1/node/backups | node:operate | admin | — |
PUT /v1/node/backup-custody | node:operate | admin | approval |
POST /v1/node/{node_id}/rebuild | node:operate | admin | approval · Idempotency-Key |
POST /v1/node/jobs/{job_id}/recovery-kit | node:operate | admin | approval |
notification_policies#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/notification-policies | alerts:read | viewer | — |
POST /v1/notification-policies | alerts:write | admin | — |
DELETE /v1/notification-policies/{policy_id} | alerts:write | admin | — |
occurrences#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/occurrences | monitors:write | member | node data |
DELETE /v1/occurrences/{monitor_slug}/{occurrence_id} | monitors:write | member | node data |
ping_tokens#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/monitors/{monitor_id}/ping-tokens/rotate | keys:manage | member | approval |
POST /v1/monitors/{monitor_id}/ping-tokens/revoke-previous | keys:manage | member | approval |
POST /v1/monitors/{monitor_id}/ping-tokens/reset | keys:manage | member | approval |
privacy#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/projects/{project_id}/privacy | projects:read | viewer | — |
PUT /v1/projects/{project_id}/privacy | privacy:write | admin | approval |
project_keys#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/projects/{project_id}/keys | keys:manage | member | approval · Idempotency-Key |
POST /v1/keys/{key_id}/rotate | keys:manage | member | approval |
DELETE /v1/keys/{key_id} | keys:manage | member | approval |
projects#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/projects | projects:read | viewer | paged |
GET /v1/projects/{project_id} | projects:read | viewer | — |
POST /v1/projects | projects:write | member | Idempotency-Key |
PATCH /v1/projects/{project_id} | projects:write | member | If-Match |
PATCH /v1/projects/{project_id}/intake | projects:write | member | If-Match |
PATCH /v1/projects/{project_id}/observability | projects:write | member | If-Match |
PUT /v1/projects/{project_id}/scrub/{group} | privacy:write | admin | approval |
PUT /v1/projects/{project_id}/checkin-auth | keys:manage | member | approval |
PUT /v1/projects/{project_id}/environments/{name}/hidden | projects:write | member | — |
DELETE /v1/projects/{project_id} | projects:delete | admin | approval |
POST /v1/projects/{project_id}/restore | projects:write | member | — |
POST /v1/projects/{project_id}/test-event | projects:write | member | — |
service_principals#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/service-accounts | tokens:manage | admin | approval · Idempotency-Key |
PATCH /v1/service-accounts/{id} | tokens:manage | admin | approval |
slos#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/slos | monitors:read | viewer | paged |
GET /v1/slos/{slo_id} | monitors:read | viewer | — |
POST /v1/slos | monitors:write | member | Idempotency-Key |
PATCH /v1/slos/{slo_id} | monitors:write | member | If-Match |
DELETE /v1/slos/{slo_id} | monitors:write | member | If-Match |
PUT /v1/slos/{slo_id}/hold | monitors:write | member | — |
POST /v1/slos/import | monitors:write | member | — |
spans#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/spans | traces:read | viewer | node data · start/end · paged |
GET /v1/spans/histogram | traces:read | viewer | node data · start/end |
telemetry#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/telemetry/usage | usage:read | viewer | node data |
tickets#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/tickets | issues:read | viewer | node data |
tokens#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/tokens | tokens:manage | admin | approval · Idempotency-Key |
POST /v1/service-accounts/{service_principal_id}/tokens | tokens:manage | admin | approval · Idempotency-Key |
DELETE /v1/tokens/{id} | tokens:manage | admin | — |
PUT /v1/token-policy | tokens:manage | admin | approval |
traces#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/traces/{trace_id} | traces:read | viewer | node data |
GET /v1/traces/{trace_id}/spans | traces:read | viewer | node data |
GET /v1/traces/{trace_id}/spans/{span_id} | traces:read | viewer | node data |
upload_tokens#
| Call | Scope | Role | Notes |
|---|---|---|---|
POST /v1/projects/{project_id}/upload-tokens | keys:manage | member | approval · Idempotency-Key |
DELETE /v1/upload-tokens/{token_id} | keys:manage | member | approval |
uptime#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/uptime-checks | monitors:read | viewer | paged |
GET /v1/uptime-checks/{check_id} | monitors:read | viewer | — |
POST /v1/uptime-checks | monitors:write | member | Idempotency-Key |
PATCH /v1/uptime-checks/{check_id} | monitors:write | member | If-Match |
DELETE /v1/uptime-checks/{check_id} | monitors:write | member | If-Match |
PUT /v1/uptime-checks/{check_id}/hold | monitors:write | member | — |
POST /v1/uptime-checks/{check_id}/runs | monitors:write | member | — |
usage#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/usage | usage:read | viewer | — |
workspace#
| Call | Scope | Role | Notes |
|---|---|---|---|
GET /v1/workspace | org:read | viewer | — |
Spotted something wrong or missing? Tell us: hello@belvador.dev