Errors & status codes
The error envelope, every status code the StatusOwl API returns, and what each one means.
The API uses standard HTTP status codes and one stable JSON envelope. Every endpoint follows the rules below.
Envelope
Errors always carry an error field:
{ "error": "Descriptive error message" }
Some errors add structured fields — the missing-scope 403 and the quota 429s. Treat unrecognised extras as forward-compatible additions.
Success uses the data envelope:
{ "data": { ... } }
Collections nest results in data and add a top-level pagination object. See
Monitors API.
Status codes
| Status | Meaning |
|---|---|
| 400 Bad Request | A query or path parameter is malformed. The message names the offending field. |
| 401 Unauthorized | Missing, malformed, unknown, revoked or expired key. |
| 403 Forbidden | Authenticated but not allowed: missing scope, IP not on the allowlist, or organization not active. |
| 404 Not Found | No such resource in the calling organization. |
| 429 Too Many Requests | Per-key rate limit or per-organization quota exceeded. |
| 500 Internal Server Error | Unhandled server-side error. Retry with backoff. |
| 503 Service Unavailable | A backend dependency is degraded. Retry shortly. |
There is no 422 — validation failures return 400.
400 — validation
{ "error": "Invalid query parameter: per_page must be between 1 and 100" }
The first failing field is reported. Fix it and resubmit.
401 — authentication
{ "error": "Invalid API key" }
{ "error": "API key revoked" }
{ "error": "API key expired" }
Invalid API key covers "no header", "malformed" and "unknown" alike — the
cases are not distinguished on the wire so a valid prefix cannot be probed. When
debugging, check the key's status in the dashboard first.
403 — forbidden
IP allowlist mismatch:
{ "error": "IP not allowed for this API key" }
Organization deactivated:
{ "error": "Organization is not active" }
Missing scope:
{
"error": "Missing required scope",
"required_scope": "monitors:read",
"granted_scopes": ["account:read"]
}
Or, when several scopes would satisfy the endpoint:
{
"error": "Missing required scope",
"required_scopes_any_of": ["monitors:read", "monitors:write"],
"granted_scopes": ["account:read"]
}
See Scopes.
404 — not found
{ "error": "Monitor not found" }
The API does not distinguish "this does not exist" from "this exists but is not yours". Both are 404, which prevents enumerating UUIDs you do not own.
429 — rate limit or quota
Rate limit, per key per minute:
{
"error": "Rate limit exceeded",
"limit_rpm": 600,
"retry_after_seconds": 42
}
Quota, per organization:
{
"error": "Daily API quota exceeded",
"limit": 100000,
"resets_at": "2026-08-06T00:00:00.000Z"
}
They need different handling — see Rate limits & quotas.
500 — server error
{ "error": "Internal server error" }
Safe to retry with exponential backoff. Production responses never include server-side detail. If it reproduces, send support the endpoint and the timestamp.
503 — service unavailable
{ "status": "degraded", "db": "down" }
Returned by /readyz when a backend dependency is failing. Back off 30–60
seconds. If it persists, check StatusOwl's own status page.
Idempotency
The whole surface is GET, so it is idempotent by construction. There is no
idempotency-key support, because there is nothing to make idempotent.
See also
- Authentication — bearer tokens.
- Rate limits & quotas — 429 handling.
- Monitors API — the endpoints and their errors.