> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dnzwithazee.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Uptime API

> Endpoints for uptime monitors, incidents and the public status page.

For what monitors, incidents and the public status page do, see
[Uptime and public status page](https://docs.dnzwithazee.com/dashboard/uptime.md). The endpoints take a signed-in session or an API
token (see [API overview](https://docs.dnzwithazee.com/api/overview.md)).

> [!NOTE]
>
> Reading needs `monitoring.manage`, `proxy.manage` or `incidents.manage`; changing needs
> `monitoring.manage`. Creating, editing and updating incidents also accepts `incidents.manage`
> (the built-in Helpdesk role); deleting one doesn't. On a DNZ
> secondary following a primary, changes are refused: manage monitors on the primary.

## Endpoints

| Method | Path | Description |
| - | - | - |
| `GET` | `/api/uptime` | Monitors (state, 90 days, last checks, uptime), incidents of the last 90 days and open ones, the page's settings, who runs the checks. `?light=true` (what the Uptime page polls): monitors without their days and last checks, open incidents only |
| `GET` | `/api/uptime/monitors?q=&status=&page=&per_page=` | The monitors in their order; with `page` / `per_page` a page (50, at most 200) as `{monitors, total, page, per_page, counts}`. `q` is text in the name, public name or what it checks; `status` is `up`, `degraded`, `down`, `unknown` or `paused`; `counts` per status are of every monitor |
| `POST` | `/api/uptime/monitors` | Add a monitor (201; 409 when the name is taken) |
| `GET` | `/api/uptime/monitors/{id}` | One monitor and its incidents |
| `PUT` | `/api/uptime/monitors/{id}` | Replace a monitor (send every field) |
| `DELETE` | `/api/uptime/monitors/{id}` | Remove a monitor and its history (204) |
| `POST` | `/api/uptime/monitors/{id}/check` | One check now, not kept; with places, `places`: what each saw |
| `POST` | `/api/uptime/test` | One check of an unsaved monitor (a monitor body), not kept |
| `GET` | `/api/uptime/places?q=&page=&per_page=` | The nodes and regions a monitor can check from (50, at most 200): `place`, `kind` (`node`, `region`), `proxy`, `region`, `nodes`, `connected`, `can_check` |
| `GET` | `/api/uptime/hosts` | Hostnames proxies serve, `dnz_proxy` when a DNZ Proxy serves one |
| `GET` | `/api/uptime/incidents?days=30&monitor=3` | Incidents: open ones and those of the last days; `resolved=true` or `false` for only one kind. With `page` / `per_page` (50, at most 200): `{items, total, page, per_page}` |
| `POST` | `/api/uptime/incidents` | Write an incident (201) |
| `GET` | `/api/uptime/incidents/{id}` | One incident and its updates |
| `PUT` | `/api/uptime/incidents/{id}` | Change its title, impact, monitors, `on_page`, `started_at` or (resolved) `resolved_at` |
| `POST` | `/api/uptime/incidents/{id}/updates` | Add to its timeline: `{"status": "identified", "message": "…", "at": "2026-11-01 13:20"}` (`at`: default now) |
| `GET` | `/api/uptime/gaps` | Times DNZ wasn't checking in the last 90 days: `started_at`, `ended_at`, `incident_id`, `dismissed`. `GET /api/uptime` carries the ones still offered as `gaps` |
| `POST` | `/api/uptime/gaps/{id}/dismiss` | No incident for it: it is no longer offered (204) |
| `DELETE` | `/api/uptime/incidents/{id}` | Delete it and its updates (204) |
| `GET`, `POST` | `/api/uptime/watches` | Watched groups of routes and every group with its hostnames; watch one (`route_group`, `path` and a monitor's settings) |
| `PUT`, `DELETE` | `/api/uptime/watches/{id}` | Change its monitors' settings; stop watching (`?keep_monitors=true` keeps them) |
| `GET`, `PUT` | `/api/uptime/page` | The public page's settings; `route: { proxy_id, upstream }` makes its hostname's route and DNS record while the page is on, and deletes them when it's off |
| `GET` | `/api/uptime/page/hostname` | The hostname's DNS records and routes now (`?host=`), DNZ's suggested address, the proxies |
| `GET` | `/status`, `/status.json` | The public page and its JSON; no sign-in |

## A monitor

```json theme={null}
{
  "name": "Website",
  "kind": "http",
  "url": "https://www.example.com/",
  "host": "",
  "method": "GET",
  "expect_status": "",
  "keyword": "Welcome",
  "degraded_ms": 0,
  "interval_secs": 60,
  "timeout_secs": 10,
  "confirm": 2,
  "skip_tls_verify": false,
  "enabled": true,
  "on_page": true,
  "public_name": "Website",
  "public_group": "Web",
  "position": 0
}
```

| Field | Meaning |
| - | - |
| `kind` | `http` (DNZ requests `url`) or `service` (the DNZ Proxy servers behind `host`) |
| `expect_status` | Codes that pass, e.g. `200,301-302`; empty: 200–399 |
| `keyword` | Text the answer must contain (not with `HEAD`) |
| `degraded_ms` | Slower answers count as degraded; 0: never |
| `interval_secs`, `timeout_secs` | 20–3600 seconds; the timeout 1–60 and shorter than the interval |
| `confirm` | Failed checks in a row before down, 1–10 |
| `on_page`, `public_name`, `public_group` | On the public page under this name (required when `on_page`) and group |

Answers add `status` (`up`, `degraded`, `down`, `unknown`, `paused`), `state_since`, `checked_at`,
`latency_ms`, `status_code`, `error`, `recent` (`[unix seconds, ms or null]`, newest last), `days`
(90 days: `checks`, `down`, `degraded`, `uptime`, `latency_ms`, `level`, `incidents`, and `filled`: how many of the checks stand for time DNZ wasn't checking, filled in by incidents), `uptime_24h`,
`uptime_7d`, `uptime_30d`, `uptime_90d`, `avg_latency_ms` and `open_incident`.

A check (`/check`, `/test`) answers `{"ok": true, "slow": false, "latency_ms": 42, "status_code": 200, "error": ""}`.

## An incident

```json theme={null}
{
  "title": "Database maintenance",
  "status": "investigating",
  "impact": "maintenance",
  "monitors": [3],
  "on_page": true,
  "started_at": "2026-10-29T15:00:00Z",
  "message": "Planned, 22:00–23:00."
}
```

`impact` is `minor`, `major`, `critical` or `maintenance`; `status` is `investigating`,
`identified`, `monitoring` or `resolved`; `message` is the first update.

Written afterwards, it takes `started_at`, `resolved_at` (it is then resolved) and `at` (the first
update's time; default: when it was resolved, else now), or `gap` (a gap's id: its times unless
given). Times are RFC 3339 or a wall-clock time on the server's clock (`2026-11-01 13:04`, what a
`datetime-local` field sends), never in the future (up to 2 minutes ahead counts as now), and in
order: started, updates, resolved; else 400 says which. The newest update sets the status; an `at`
before it fills in the timeline and leaves the status as it is (not as `resolved`). Answers add `automatic`,
`cause` (what a failing check saw, never on the public page), `resolved_at`, `duration_secs` and
`updates` (newest first: `status`, `message`, `at`, `author`; an empty author is DNZ).

## The public page's settings

```json theme={null}
{ "enabled": true, "title": "Company status", "description": "", "hostname": "status.example.com", "incident_days": 14 }
```

## The page as JSON

`/status.json` carries what the public page shows, for scripts and widgets, and nothing more. It
needs no sign-in, answers with `Access-Control-Allow-Origin: *`, and a page that is off answers 404.

```json theme={null}
{
  "title": "Example status",
  "description": "",
  "status": { "level": "ok", "label": "All systems operational" },
  "groups": [{
    "name": "Web",
    "level": "ok",
    "components": [{
      "name": "Shop",
      "status": { "level": "ok", "label": "Operational" },
      "uptime_90d": 99.98,
      "uptime_30d": 100.0,
      "days": [{ "day": "2026-11-01", "uptime": 100.0, "level": "ok" }]
    }]
  }],
  "incidents": { "active": [], "past": [] },
  "scheduled_maintenance": [{
    "title": "Weekly backups",
    "starts_at": "2026-11-08T15:00:00Z",
    "ends_at": "2026-11-08T17:00:00Z",
    "affected": ["Shop"]
  }],
  "updated_at": "2026-11-01T10:00:00Z"
}
```

| Field | |
| - | - |
| `level` | `ok`, `degraded`, `partial`, `major`, `maintenance` or `none` (no data yet); `label` is the words the page shows for it |
| `groups[].components` | The monitors on the page under their public names: `status`, `uptime_90d`, `uptime_30d` and `days` (each day's uptime and level) |
| `incidents.active`, `incidents.past` | Open incidents, and those of the page's past days: `title`, `status` (`investigating`, `identified`, `monitoring`, `resolved`), `impact`, `started_at`, `resolved_at`, `affected` (public names) and `updates` (`status`, `message`, `at`) |
| `scheduled_maintenance` | The occurrences of [scheduled maintenance](https://docs.dnzwithazee.com/proxy/status-pages.md#scheduled-maintenance) windows shown on the public page that start in the next 7 days and cover a monitor on it, soonest first: the window's name as `title`, `starts_at` and `ends_at` in UTC, and `affected`, the public names of the monitors it covers. Empty when there are none |
| `updated_at` | When the page was built (UTC) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.