API Monitors
Base URL: https://api.okstatus.eu/api/v1/monitors — every request needs an Authorization: Bearer oks_live_... header, see Authentication.
List monitors
Section titled “List monitors”GET /api/v1/monitors?page=1&per_page=50Returns a paginated list scoped to your organization (per_page up to 100).
Response
{ "monitors": [ { "id": "...", "name": "...", "url": "...", "type": "http", "interval": 60, "status": "active", "tags": ["prod"] } ], "total": 12, "page": 1, "perPage": 50, "pages": 1}Create a monitor
Section titled “Create a monitor”POST /api/v1/monitorsContent-Type: application/json| Field | Type | Required | Description |
|---|---|---|---|
name | string | ✅ | Monitor name (1–100 chars) |
url | string | ✅ | The target: an http(s):// URL for http and llm, a host for ping, tcp and dns (example.com), a connection URL for databases — see each monitor type |
type | enum | http, tcp, ping, dns, grpc, llm, push, group, postgres, mysql, mongodb, smtp, imap or redis — defaults to http | |
interval | number | Seconds between checks, min 30 — defaults to 60. Your plan’s floor still applies (300 s on Free, 60 s on Pro) | |
regions | string[] | Region codes, 1–5 of them — defaults to ["fr-dc3"]. See Regions | |
acceptedStatusCodes | string[] | http: codes or ranges counted as up, e.g. ["200-299", "301"] — defaults to ["200-299"] | |
tags | string[] | Up to 5 tags of 30 characters. Stored in lowercase if your organization chose that in Settings → Tags | |
keyword | string | http: text the response body must contain | |
followRedirects | boolean | http: follow 3xx redirects — defaults to true. With false, the redirect response itself is judged | |
httpMethod | enum | http: GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS | |
httpHeaders | object | http: request headers. Never returned: reading the monitor gives "***" | |
httpBody | string | http: request body, with httpBodyEncoding = json, form, xml or text | |
ignoreTls | boolean | http: accept an invalid or self-signed certificate | |
port | number | tcp: port to connect to | |
dnsRecordType | enum | dns: A, AAAA, CNAME, MX, NS, TXT, SOA, CAA or SRV | |
dnsExpectedValue | string | dns: value the answer must contain | |
dnsServer | string | dns: resolver to query instead of the default one | |
retries | number | Consecutive failed checks tolerated before the monitor is down (0–5) — defaults to 1 | |
severity3xx | enum | http: a redirect that is not accepted counts as degraded (default) or down | |
latencyThresholdMs | integer | Response time (50–60000 ms) above which the monitor turns degraded and alerts, after max(2, retries + 1) slow checks in a row; null turns it off. See Response time alerts | |
latencyPublic | boolean | false keeps slowness off public status pages (default true) | |
latencyAnomaly | boolean | Alert when the response time leaves its learned usual range (Max and Enterprise, 7 days of learning; refused with 403 below Max). See Response time alerts | |
sloTarget | number | SLO objective in percent over 30 rolling days (50 to 99.999, e.g. 99.9); null removes it. Max and Enterprise, refused with 403 below. See SLOs and error budget | |
keywordInvert | boolean | http: the monitor is down when keyword is found | |
jsonPath, jsonOperator, jsonExpectedValue | http: assertion on a JSON response (==, !=, >, <, >=, <=, contains). Not combinable with keyword | ||
basicAuthUser / basicAuthPass | string | Basic auth, and the credential pair of database, SMTP, IMAP and Redis monitors. Stored encrypted | |
authConfig | object | Non-Basic authentication — see below | |
dbQuery | string | postgres, mysql, mongodb: query run on each check | |
gracePeriod | number | push: seconds without a ping before the monitor is down. The response carries the pushUrl to call | |
childMonitorIds | string[] | group: the monitors it aggregates | |
llmProvider, llmApiKey, llmConfig | llm: see the interactive reference |
Returns 201 with { "data": Monitor }.
A monitor is always created running and unmuted: pause or mute it with a PATCH.
Authentication of the monitored endpoint
Section titled “Authentication of the monitored endpoint”authConfig carries one method, discriminated by type (full reference: Authentication):
{ "type": "bearer", "token": "…" }{ "type": "apikey", "in": "header", "name": "X-API-Key", "value": "…" }{ "type": "apikey", "in": "query", "name": "api_key", "value": "…" }{ "type": "cookie", "cookie": "session=…; csrf=…" }{ "type": "oauth2", "tokenUrl": "https://login.example.com/token", "clientId": "…", "clientSecret": "…", "scope": "…", "audience": "…", "authStyle": "basic" }{ "type": "mtls", "cert": "-----BEGIN CERTIFICATE-----…", "key": "-----BEGIN PRIVATE KEY-----…", "ca": "…" }Reading a monitor back returns the method and its non-secret settings, with each secret replaced by "***". Sending that mask back on PATCH keeps the stored value — which is what lets you round-trip a monitor through GET then PATCH without wiping its credentials. "authConfig": null clears the authentication.
Get / update / delete a monitor
Section titled “Get / update / delete a monitor”GET /api/v1/monitors/:idPATCH /api/v1/monitors/:idDELETE /api/v1/monitors/:idPATCH accepts the fields of create except type (all optional — only the fields you send change), plus:
| Field | Type | Description |
|---|---|---|
status | enum | "paused" stops the checks, "active" resumes them |
isMuted | boolean | true stops the alerts while the checks keep running |
To remove a value, send null: "keyword": null, "dnsExpectedValue": null, "port": null, "authConfig": null, "basicAuthUser": null. "tags": [] removes every tag.
curl -X PATCH https://api.okstatus.eu/api/v1/monitors/$ID \ -H "Authorization: Bearer $OKSTATUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": "paused", "tags": ["prod", "payments"], "keyword": null }'DELETE returns { "data": { "deleted": true } }.
Alert channels of a monitor
Section titled “Alert channels of a monitor”GET /api/v1/monitors/:id/alert-channelsPUT /api/v1/monitors/:id/alert-channelsGET returns the ids of the channels attached to the monitor:
{ "data": { "channelIds": ["3f6e2b1a-...", "9c1d4e7f-..."] } }PUT replaces that set — an empty list detaches every channel:
{ "channelIds": ["3f6e2b1a-..."] }The ids are those of GET /api/v1/alert-channels. An id that is not one of your organization’s channels is refused with 404 NOT_FOUND, and nothing is changed. A channel that stays attached keeps its per-monitor settings (which kinds of alert it receives).
Regions and private agents
Section titled “Regions and private agents”regions takes public region codes (see Regions and intervals), and on plans with private agents:
"private"— any of your private agents runs the check;"private:<agent id>"— that agent only.
GET /api/v1/private-agentslists your agents, each with the region value to use:
{ "data": [ { "id": "5a0c…", "name": "dc-paris", "site": "Paris", "region": "private:5a0c…", "status": "up", "suspended": false, "version": "1.0.0", "hostname": "probe-1", "platform": "linux/amd64", "lastHeartbeatAt": "2026-10-10T07:00:00.000Z" } ], "meta": { "eligible": true, "limit": 5, "latestVersion": "1.0.0" }}The list is read-only: an agent is enrolled from the dashboard, because enrolling hands out a credential. Enrollment tokens are never returned.
Check results and uptime
Section titled “Check results and uptime”GET /api/v1/monitors/:id/checks?page=1&per_page=50GET /api/v1/monitors/:id/uptime?range=24hSLO and error budget
Section titled “SLO and error budget”GET /api/v1/slos?status=at_riskGET /api/v1/monitors/:id/slo?target=99.9GET /slos lists every SLO of the organization, monitors and groups, worst
first: kind (monitor or group), id, name, target, budgetMinutes,
consumedMinutes, remainingMinutes, remainingPercent, availability30d,
incidents (outages in the window), status (ok, at_risk, exhausted)
and exhaustsAt (when the budget runs out at the last 7 days’ pace, or
null). status filters the list.
GET /monitors/:id/slo returns the same figures for one monitor, plus
series (the budget left over the last 30 days). target previews an
objective on a monitor that has none. Both answer 403 below Max. See
SLOs and error budget.
Errors
Section titled “Errors”404 NOT_FOUND if the monitor doesn’t exist in your org. When a create or an update is refused, the error carries the reason — for example:
| Code | Meaning |
|---|---|
VALIDATION_ERROR | A field is invalid; message names it |
PLAN_LIMIT_REACHED | Your plan’s number of monitors is reached |
PLAN_INTERVAL_TOO_LOW | The interval is below your plan’s minimum |
PLAN_REGION_NOT_ALLOWED | A region is not included in your plan |
PLAN_REGIONS_PER_MONITOR | Too many regions for one monitor on your plan |
INVALID_URL | The target is a private or reserved address |
UPSTREAM_ERROR | The monitoring engine failed without giving a reason |
See Authentication for the shared error format and rate limits.
Plan limits
Section titled “Plan limits”| Plan | Max monitors | Min interval | Regions per monitor |
|---|---|---|---|
| Free | 5 | 300s | 2 |
| Pro | 20 | 60s | 3 |
| Max | 80 | 30s | 5 |
| Enterprise | 500 (more on request) | 30s | 5 |
Limits are enforced on create: an organization already above a lowered limit keeps what it has, it just can’t add more.