---
title: "Get monitor"
method: GET
path: "/api/v1/monitors/{monitorID}"
tags: ["Monitors"]
---

# Get monitor

`GET /api/v1/monitors/{monitorID}`

## Request

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

Returns a monitor with its full runtime state including evidence buffer.

## Path parameters

- `monitorID` integer, required

## Response `200`

Monitor with state.

- MonitorDetail
  - `monitor` Monitor
    - `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
  - `state` MonitorState
    - `monitor_id` integer
    - `status` 'up' | 'down' | 'unknown' | 'flapping'
    - `last_check_at` string, date-time, nullable
    - `last_transition_at` string, date-time, nullable
    - `suspect_since` string, date-time, nullable
    - `flap_count_1h` integer
    - `flapping` boolean
    - `evidence_buffer` CheckResult[]
      - `timestamp` string, date-time
      - `region` string
      - `status_code` integer
      - `error_class` string
      - `dns_ms` number
      - `tls_ms` number
      - `connect_ms` number
      - `ttfb_ms` number
      - `download_ms` number
      - `content_length` integer
      - `response_hash` string
      - `packet_loss_pct` number: Ping-only packet loss percentage (0-100). Omitted (not present in the object) when not measured — every non-ping check result, and a ping probe-side failure that never reached the target. A measured 0% loss is present with value 0, distinct from omitted.
    - `primary_region` 'EU' | 'US-E' | 'US-W' | 'ASIA' | 'OCE' | 'SA' | 'null', nullable: The region assigned as primary for this monitor's checks. Null until the first check is dispatched.
  - `notice` SoftCapNotice: Advisory attached to `POST /api/v1/monitors` when the post-insert per-account monitor count falls in the soft-cap window (51..100). Clients should branch on `code` rather than parsing `message`.
    - `code` 'soft_cap_reached', required
    - `message` string, required: Human-readable advisory text. Wording is set by SPEC and may evolve.
    - `monitors_current` integer, required: Per-account monitor count after the create.
    - `soft_cap` integer, required: Soft cap threshold; crossing it triggers the notice.
    - `hard_cap` integer, required: Hard cap; reached → 409 on subsequent creates.
  - `last_check_skipped` string: Populated only on `POST /monitors` when the create-time initial check did not produce a usable result — either short-circuited before any probe ran, or the probe started but did not finish within the create-time budget, leaving the first check pending. The state row's `last_check_at` remains `null` in either case; clients distinguish "no data yet" from "skipped on purpose" via this field. Vocabulary: * `domain_rate_limited` — the per-domain dispatch cap (`DomainLimiter`) consumed the slot; the next scheduled tick will retry once the bucket refills. * `initial_check_timeout` — the create-time probe did not return within the server's bounded wait; the monitor is registered normally and the next scheduled tick resolves it.
  - `recipient_ids` integer[]: Attached recipient ids (issue #212). Always present, `[]` for none. On `POST /monitors`, reflects any account default recipients attached inside the create transaction — though a monitor born down does not notify them at creation; see `Recipient.default`.

## Other responses

- `400`: Invalid request.
- `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.
- `404`: Monitor not found or belongs to another account.
- `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)
