API reference
Everything the dashboard can do with monitors, incidents and channels is available over HTTPS at https://uptimeroom.com/api/v1. Create keys under API & Developers; probe egress addresses are listed on Probe IPs.
Authentication
Send the key as a Bearer token. Keys look like urm_live_…, are shown once at creation and are stored hashed. A request carrying an Authorization: Bearer header is authenticated by that key alone - an unknown or revoked key returns 401 even from a signed-in browser.
Scopes
| Scope | Grants |
|---|---|
| monitor:read | list/read monitors, incidents, alert jobs, series, alert routes, channels |
| monitor:write | create/edit/delete monitors, run checks, edit alert routes, create/test channels |
Envelope
Successful responses are { "data": … }; list endpoints return an array in data. Errors are { "error": { "code", "message", "details"? } } with the HTTP status carrying the class of failure. Ids are UUIDs; timestamps are ISO-8601 UTC.
Rate limits, idempotency, caching
- Rate limits: there is no per-key rate limit on /api/v1 yet. Sign-in, password-reset and verification endpoints are rate-limited; a 429 carries the reason in error.message. Be a good neighbour: poll monitors no more often than their interval.
- Idempotency: only POST /posts/bulk honours an Idempotency-Key header (scoped to your org; a replay answers with idempotent-replay: true). Every other write is not idempotent - retry only after a network failure with no response.
- Caching: authenticated responses are Cache-Control: private, no-store.
Error codes
| Status | Code | When |
|---|---|---|
| 400 | bad_request | Body is not valid JSON, or the multipart/JSON shape is wrong |
| 401 | unauthorized | Missing, unknown or revoked Bearer key (a Bearer header never falls back to a browser session) |
| 403 | forbidden | The key lacks the required scope, or the dashboard role is too low |
| 403 | channel_gated | The channel type is not included in the org's plan |
| 404 | not_found | Unknown id, or an id that is not a UUID |
| 409 | quota_exceeded | Monitor limit for the plan reached |
| 409 | slug_conflict | A post with that slug already exists |
| 409 | paused | Run-check on a paused monitor |
| 409 | channel_disabled | Alert route references a channel disabled on the plan |
| 413 | payload_too_large | Media upload over 10 MB |
| 415 | unsupported_media_type | Media upload that is not a raster image |
| 422 | validation_error | Field validation failed; `details` carries zod's { fieldErrors, formErrors } |
| 422 | invalid_regions | Unknown region code(s) for this deployment |
| 422 | unsafe_target | Target resolves to a private/loopback/link-local address (SSRF guard) |
| 422 | ssrf_rejected | A channel config URL fails the SSRF guard |
Monitors
Monitors are the checks the probes run. Types: http, api, keyword, tcp, dns, ping, udp, ssl, domain, heartbeat.
| Endpoint | Scope | Description |
|---|---|---|
| GET /api/v1/monitors | monitor:read | List the org's monitors with their latest state. No parameters. |
| POST /api/v1/monitors | monitor:write | Create a monitor. JSON: name (1–120), type, target, intervalSec (30–86400; plan floor applies), regions (1–5 region codes from GET /api/regions), optional port, method, expectedStatus[], assertions[], keyword, keywordMatch, dnsRecordType, dnsExpected, timeoutMs (1000–120000), responseTimeThresholdMs (50–120000), alertAfterCycles (1–10), headers, body, followRedirects, certWarnDays, maintenanceWindows[], paused. Errors: 400 bad_request / no_plan · 409 quota_exceeded · 422 validation_error / invalid_regions / unsafe_target Region count, interval floor and slow-response thresholds are gated by the plan. Not idempotent - two identical POSTs create two monitors. |
| GET /api/v1/monitors/{id} | monitor:read | Read one monitor. Errors: 404 not_found |
| PATCH /api/v1/monitors/{id} | monitor:write | Update any subset of the monitor fields. JSON: the same fields as POST, all optional; nullable fields accept null to clear. Errors: 404 not_found · 422 validation_error / invalid_regions / unsafe_target |
| DELETE /api/v1/monitors/{id} | monitor:write | Delete a monitor and its history. Errors: 404 not_found |
| POST /api/v1/monitors/{id}/check | monitor:write | Request an immediate re-check in every configured region. Errors: 404 not_found · 409 paused |
| GET /api/v1/monitors/{id}/series | monitor:read | Bucketed p50/p95/p99 + availability for charts. Query: window=1h|24h|7d|30d (default 24h) and region=<code>|all, or from=<iso>&to=<iso> (≤ 31 days). Errors: 404 not_found · 422 validation_error |
| GET /api/v1/monitors/{id}/routes | monitor:read | The monitor's alert routes (channels, re-alert cadence, recovery/degraded toggles). Errors: 404 not_found |
| PUT /api/v1/monitors/{id}/routes | monitor:write | Replace the full set of alert routes. JSON: { routes: [{ channelId, reAlertEveryMin (0–1440; 0 = alert once), notifyOnRecovery, notifyOnDegraded }] } (max 50). Errors: 404 not_found · 409 channel_disabled · 422 validation_error |
Incidents & alert delivery
Incidents open when quorum confirms a monitor down/degraded and close on recovery.
| Endpoint | Scope | Description |
|---|---|---|
| GET /api/v1/incidents | monitor:read | Newest incidents first. Query: limit (default 50, clamped). Bearer key only - dashboard sessions read incidents through the app pages. |
| GET /api/v1/incidents/{id} | monitor:read | One incident with its alert delivery jobs. Errors: 404 not_found |
| PATCH /api/v1/incidents/{id} | monitor:write | Acknowledge an incident (idempotent; records who acknowledged). JSON: { acknowledgedAt?: iso }. Errors: 404 not_found · 422 validation_error |
| GET /api/v1/incidents/export | monitor:read | CSV of up to 5,000 incidents, newest first. Query: state=all|ongoing|resolved, monitor=<uuid>, kind=down|degraded. Errors: 422 validation_error Responds with text/csv, not the JSON envelope. |
| GET /api/v1/alert-jobs | monitor:read | Alert delivery queue with per-status counts (dead-lettered jobs carry last_error). Query: status=pending|processing|delivered|failed|dead, limit (default 50). Errors: 422 validation_error |
Channels
Alert channels (email, Slack, webhook, PagerDuty, web push, SMS, voice, ...). Third-party channels are plan-gated.
| Endpoint | Scope | Description |
|---|---|---|
| GET /api/v1/channels | monitor:read | List channels (secrets redacted). |
| POST /api/v1/channels | monitor:write | Create a channel. JSON: { type, name?, config } - required config keys depend on the type. Errors: 400 bad_request / no_plan · 403 channel_gated · 422 validation_error |
| GET /api/v1/channels/{id} | monitor:read | Read one channel. Errors: 404 not_found |
| PATCH /api/v1/channels/{id} | monitor:write | Update the channel config (clears verified until re-tested). JSON: { config }. Errors: 400 bad_request · 404 not_found · 422 validation_error |
| DELETE /api/v1/channels/{id} | monitor:write | Delete a channel (dashboard sessions need the admin role). Errors: 403 forbidden · 404 not_found |
| POST /api/v1/channels/{id}/test | monitor:write | Deliver a representative alert through the channel and mark it verified on success. Errors: 404 not_found SMS/voice tests are real sends and debit credits. |
| POST /api/v1/channels/test-config | monitor:write | Test an unsaved channel config before creating it. JSON: { type, config }. Errors: 400 bad_request · 422 validation_error / ssrf_rejected |
API keys
Keys are org-level credentials: minting, listing and revoking them is a dashboard (admin+) action, so no key can mint another key.
| Endpoint | Scope | Description |
|---|---|---|
| GET /api/v1/keys | dashboard session | List live keys (prefix, scopes, last used) - never the secret. |
| POST /api/v1/keys | dashboard session | Create a key; the plaintext secret is returned exactly once. JSON: { name (1–120), scopes: [...] }. Errors: 422 validation_error · 403 forbidden (content:* on a non-staff account) |
| DELETE /api/v1/keys/{id} | dashboard session | Revoke a key; calls using it fail with 401 immediately. Errors: 404 not_found |
Public, unauthenticated endpoints
- GET /api/regions - probe locations and the egress allow-list (also on /docs/probe-ips).
- GET /api/credits/rates - SMS/voice credit rates.
- POST /api/heartbeat/<token> - heartbeat pings (token-authenticated, no key needed).