Check Status
The current status of every check in your account, in one response. Built for monitoring systems that poll, such as Zabbix, Nagios or Prometheus exporters, where webhooks can’t reach the box.
Endpoint
GET /v1/public/checks/statusThere are no query parameters and no pagination. Every check is returned.
Response
{
"data": [
{
"id": "abc123",
"name": "Production Website",
"status": "offline",
"lastStatusChange": 1736951400000,
"lastError": "Connection timed out",
"disabled": false,
"maintenanceMode": false,
"regions": {
"primary": "vps-eu-1",
"peer": "vps-us-1",
"regionsTotal": 2,
"regionsDown": 2,
"confirmedDown": true
}
},
{
"id": "def456",
"name": "API",
"status": "online",
"lastStatusChange": 1736865000000,
"lastError": null,
"disabled": false,
"maintenanceMode": false,
"regions": {
"primary": "vps-us-1",
"peer": null,
"regionsTotal": 1,
"regionsDown": 0,
"confirmedDown": false
}
}
],
"meta": {
"total": 2
}
}Checks are returned in the same order as in your dashboard.
Status Object
| Field | Type | Description |
|---|---|---|
id | string | Unique check identifier |
name | string | Display name. Falls back to the URL when no name is set |
status | string | online, offline, degraded or unknown |
lastStatusChange | number | null | Epoch ms when status last changed. null for a check whose status has not changed since this field was introduced |
lastError | string | null | Error from the failing probe. Only set while status is offline |
disabled | boolean | true if the check is paused |
maintenanceMode | boolean | true while the check is in maintenance mode. Alerts are suppressed and status does not change during maintenance |
regions | object | Which regions observed the latest result (see below) |
regions
When a probe fails, exit1.dev asks a second region to re-check before it treats the failure as real. regions tells you what that second region saw.
| Field | Type | Description |
|---|---|---|
primary | string | null | Region that ran the check, for example vps-eu-1 (Frankfurt) or vps-us-1 (Boston) |
peer | string | null | Second region that re-checked the failure. null when no second region was consulted |
regionsTotal | number | Regions that reported on the latest result: 1, or 2 when a peer was consulted |
regionsDown | number | How many of those saw the check down |
confirmedDown | boolean | true when the check is offline and the peer region agreed |
A healthy check is normally regionsTotal: 1. The peer is only consulted when the primary region sees a failure, and a peer that could not be reached does not count.
Polling
This endpoint is meant to be called often:
- It has its own rate limit of 6 requests/minute per API key (12/minute per user across all keys). That allows polling every 10 seconds.
- Requests to it do not count toward the daily quotas or the per-key limit of the other endpoints.
- Responses carry an
ETagheader. Send it back asIf-None-Matchand you get304 Not Modifiedwith no body until something changes.
The response contains no timestamps that move on their own, so the ETag only changes when a check’s status, error, pause, maintenance or region verdict changes.
Results can lag the dashboard by a few seconds.
Code Examples
cURL
curl -i -H "X-Api-Key: ek_live_your_key_here" \
-H 'If-None-Match: "previous-etag"' \
"https://us-central1-exit1-dev.cloudfunctions.net/publicApi/v1/public/checks/status"Python
import time
import requests
URL = "https://us-central1-exit1-dev.cloudfunctions.net/publicApi/v1/public/checks/status"
headers = {"X-Api-Key": "ek_live_your_key_here"}
etag = None
checks = []
while True:
if etag:
headers["If-None-Match"] = etag
response = requests.get(URL, headers=headers)
if response.status_code == 200:
etag = response.headers.get("ETag")
checks = response.json()["data"]
down = [c["name"] for c in checks if c["status"] == "offline"]
print("down:", down)
elif response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", "10")))
continue
time.sleep(15)JavaScript
let etag;
let checks = [];
async function poll() {
const response = await fetch(
"https://us-central1-exit1-dev.cloudfunctions.net/publicApi/v1/public/checks/status",
{
headers: {
"X-Api-Key": "ek_live_your_key_here",
...(etag ? { "If-None-Match": etag } : {}),
},
}
);
if (response.status === 200) {
etag = response.headers.get("ETag");
checks = (await response.json()).data;
}
// 304: nothing changed, keep the previous `checks`
}
setInterval(poll, 15_000);