---
title: "List monitors"
method: GET
path: "/api/v1/monitors"
tags: ["Monitors"]
---

# List monitors

`GET /api/v1/monitors`

## Request

- Base URL: `https://api.uptimemonitoring.com`
- URL: `https://api.uptimemonitoring.com/api/v1/monitors`
- Auth: HTTP bearer

Returns all monitors for the authenticated account with current status,
ordered by creation date (newest first).

## Response `200`

List of monitors with inline status.

- MonitorListItem[]
  - `id` integer
  - `account_id` integer
  - `name` string
  - `url` string: Target URL. Format depends on `type`: * `http` — full http(s) URL, e.g. `https://api.example.com/health`. * `tcp` — always returned/stored as `tcp://host:port`, port restricted to a whitelist (see `MonitorInput.url` for the accepted input shapes). * `ping` — a bare hostname or IP literal (e.g. `api.example.com`, `1.1.1.1`) — no scheme, path, query, userinfo, or port. * `dns` / `ssl` — reserved formats (a bare hostname for `dns`) for a `type` that is defined but not yet serviced by the check engine; see the `type` field.
  - `type` 'http' | 'tcp' | 'ping': `http`, `tcp`, and `ping` can appear here. `dns` and `ssl` are reserved for a check engine that does not exist yet (issue #209); no monitor of one of those two types can be created, updated, or persisted.
  - `interval_sec` integer
  - `expected_status` string: Single HTTP status code, expressed as a string, 100–599. Defaults to "200".
  - `body_match` string, nullable
  - `enabled` boolean
  - `response_time_threshold_ms` integer, nullable: Alert if response time exceeds this (ms). Null = disabled.
  - `maintenance` MaintenanceWindow: A monitor's single alert-silencing window (issue #361). Always present on a `Monitor`; `{"type":"none"}` (the default) silences nothing. Accepted on `MonitorInput`/`MonitorCreateInput` as one of three discriminated shapes — each accepts ONLY the fields listed for it, plus `type`; any other field (including one that belongs to a different shape) is `400` naming it, e.g. `maintenance.timezone: not allowed for type "once"`. * `none` — no other fields. * `daily` — `start_time`, `end_time`, `timezone` all required. Repeats every day in that IANA zone; may span midnight (`start_time > end_time`). `start_time` must differ from `end_time`. The zone must be a real IANA name — empty, `Local`, and anything `LoadLocation` can't resolve are all rejected. * `once` — `starts_at`, `ends_at` both required, `ends_at` after `starts_at`. A single absolute span; no zone, since both instants are already pinned by their offsets. Both timestamps are normalized to UTC at microsecond precision (PostgreSQL's `timestamptz` precision) before being validated or stored, so two timestamps that differ only below a microsecond collapse to equal and are rejected as `ends_at` not being after `starts_at`. On `PUT`, omitting `maintenance` entirely leaves the stored window unchanged; an explicit JSON `null` is `400` (`maintenance must not be null`) — the same rule `recipients` follows elsewhere. `POST` omitting it defaults to `{"type":"none"}`.
    - `type` 'none' | 'daily' | 'once'
    - `start_time` string: "HH:MM", daily only. Canonical: zero seconds, below 24:00.
    - `end_time` string: "HH:MM", daily only.
    - `timezone` string: IANA zone name, daily only.
    - `starts_at` string, date-time: RFC3339, once only. Echoed back UTC-normalized at microsecond precision.
    - `ends_at` string, date-time: RFC3339, once only. Echoed back UTC-normalized at microsecond precision.
  - `method` 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS': HTTP request method (issue #364). Always `GET` for `tcp`/`ping`/ `dns`/`ssl` monitors, regardless of what might once have been stored — a non-http monitor's custom-request fields are always reset to their defaults on write.
  - `body` string: Request body, verbatim (issue #364). Always `""` for a non-http monitor. Unlike `headers`, the body is NOT write-only — it is returned verbatim on every read to anyone who can read the monitor. It must not contain credentials or other sensitive data unless that exposure is acceptable; `headers` is the write-only place for secrets.
  - `headers` RequestHeader[]: Custom request headers (issue #364), write-only: each entry reports only `name` and `value_set`, never the value itself. Always `[]` for a non-http monitor.
    - `name` string, required
    - `value_set` boolean, required: Whether this header carries a non-empty value.
  - `timeout_sec` integer: Request timeout in seconds (issue
  - `created_at` string, date-time
  - `updated_at` string, date-time
  - `status` 'up' | 'down' | 'unknown' | 'flapping'
  - `last_check_at` string, date-time, nullable
  - `recipient_ids` integer[]: Attached recipient ids (issue

## Other responses

- `401`: Missing or invalid credentials.
- `403`: Account is currently suspended. On `POST /api/v1/monitors`, and on a `PUT /api/v1/monitors/{monitorID}` that changes `url` or `type` (issue #335), this can also be returned by the per-account port-scan heuristic when the triggering request crossed the port-fan threshold inside the sliding window (10 minutes by default; `SCAN_WINDOW`). A host-fan trip does NOT suspend the account — see the 429 response instead.
- `405`: The HTTP method is not supported for this path. The `Allow` response header lists the methods this endpoint accepts.
- `429`: Per-account dispatcher rate limit exceeded (200 requests/minute). The `Retry-After` header gives the integer seconds until at least one token has refilled. The `X-RateLimit-*` trio reflects the bucket whose rejection produced this response — usually the global 200/min cap; on `POST /api/v1/monitors` a 429 may instead reflect the per-route 20/min creation limit.

---

[API](https://skmtc.dev/uptimemonitoring/apis/uptimemonitoring-com-api.md) · [All operations](https://skmtc.dev/uptimemonitoring/apis/uptimemonitoring-com-api/llms.txt) · [OpenAPI document](https://skmtc.dev/uptimemonitoring/apis/uptimemonitoring-com-api/revisions/ddcb2a8bc70f?raw)
