---
title: Checks, uptime & run now
description: Uptime and response-time statistics, raw check history with a failure filter and per-location breakdown, and on-demand checks for a monitor.
canonical: https://watchfor.io/docs/api/checks-uptime
---

# Checks, uptime & run now

Uptime and response-time statistics, raw check history with a failure filter and per-location breakdown, and on-demand checks for a monitor.

A **check** is one execution of a monitor from one location. These
endpoints read the results and let you trigger one on demand.

| Method | Path | Scope | operationId |
| --- | --- | --- | --- |
| GET | `/v1/monitors/{id}/uptime` | read | `getMonitorUptime` |
| GET | `/v1/monitors/{id}/checks` | read | `listMonitorChecks` |
| POST | `/v1/monitors/{id}/check-now` | write | `runMonitorCheckNow` |

## Uptime & response times

`GET /v1/monitors/{id}/uptime?period=24h` — incident-based uptime and
response-time statistics for one period. `period` is `1h`, `24h`
(default), `7d`, `30d` or `90d`; an unknown value returns `400` listing
the valid periods.

```bash
curl "https://watchfor.io/api/v1/monitors/0b0f6a41-…/uptime?period=7d" \
  -H "Authorization: Bearer wf_live_YOUR_KEY"
```

```json
{
  "object": "uptime",
  "monitor_id": "0b0f6a41-…",
  "period": "7d",
  "uptime_percent": 100,
  "downtime_ms": 0,
  "check_success_percent": 99.983,
  "total_checks": 10080,
  "successful_checks": 10078,
  "failed_checks": 2,
  "avg_response_time_ms": 100,
  "min_response_time_ms": 67,
  "max_response_time_ms": 1216,
  "last_failure_at": "2026-08-22T04:12:00Z",
  "uptime_24h": 100,
  "uptime_7d": 99.983,
  "uptime_30d": 99.995
}
```

- `uptime_percent` uses the [one formula](/docs/monitors#how-uptime-is-calculated)
  the whole product uses: `100 − share of the period inside confirmed
  critical incidents`, with scheduled maintenance neutral and the window
  clamped to the monitor's creation time (or its last history reset). A failed check that never became
  a confirmed incident does **not** reduce it. `downtime_ms` is the time
  those incidents covered. `uptime_percent` is `null` only before the
  monitor existed.
- `check_success_percent` is the **reachability** signal, not a health
  signal: the share of checks where the probe reached the target and got a
  response. A response that then fails a rule — wrong status code, failed
  assertion, expired certificate — counts as reached here and surfaces as an
  incident instead, so a monitor can report `uptime_percent: 60` with
  `check_success_percent: 100`. Use it for flakiness (timeouts, refused
  connections, DNS failures), and `uptime_percent` for health. Like the
  response-time fields it is `null` when the period contains no checks (a
  paused or brand-new monitor has no data, and no data is **not** 100%).
- Time inside activated [maintenance windows](/docs/api/maintenance-windows)
  marked "exclude from uptime/SLA" is neutral for uptime and removed from
  both numerator and denominator of check success.
- `uptime_24h`, `uptime_7d` and `uptime_30d` are convenience headline
  numbers (same incident-based formula) regardless of the requested `period`.
- A monitor that has never been scheduled returns zeros/`null` without
  the headline fields.
- If the metrics store is temporarily unreachable the endpoint returns
  `500 internal_error` ("retry shortly") rather than partial numbers.

## Check history

`GET /v1/monitors/{id}/checks` — individual check results, newest
first, plus a per-location performance breakdown for the same window.

| Query | Meaning |
| --- | --- |
| `hours` | Window size, 1–720 (default 24); must be an integer |
| `limit` | Rows of raw checks, 1–100 (default 50); anything else returns `400` |
| `success` | `false` returns only failed checks (one-call failure forensics); `true` only passing ones; omit for all |
| `cursor` | The previous page's `next_cursor`, to keep reading the same window |

```bash
curl "https://watchfor.io/api/v1/monitors/0b0f6a41-…/checks?hours=48&success=false" \
  -H "Authorization: Bearer wf_live_YOUR_KEY"
```

```json
{
  "object": "list",
  "data": [
    {
      "object": "check",
      "timestamp": "2026-08-24 18:48:25Z",
      "success": false,
      "duration_ms": 30012,
      "location": "eu-frankfurt-1",
      "error": "request timed out after 30s",
      "status_code": 0
    }
  ],
  "locations": [
    {
      "location": "eu-frankfurt-1",
      "checks": 1440,
      "success_percent": 99.931,
      "uptime_percent": 99.931,
      "avg_response_time_ms": 100,
      "min_response_time_ms": 67,
      "max_response_time_ms": 1216
    }
  ],
  "has_more": true,
  "next_cursor": "MjAyNi0wOC0yNFQxODo0ODoyNVp8…"
}
```

- `location` is the probe's name; `status_code` is present for HTTP-style
  types only. `error` is `null` on success.
- `locations` summarizes every location that ran checks in the window,
  independent of `limit` and the `success` filter. `success_percent` is
  that location's successful ÷ total checks — a location has no
  incident-based uptime, which is why the older `uptime_percent` key there
  is a deprecated alias of the same value (removed in the next API version).
- Pagination is cursor-based within the `hours` window: when `has_more`
  is `true`, pass `next_cursor` as `?cursor=` with the **same** `hours`
  and `success` values to get the next `limit` rows — newest first, no
  overlap, no gaps. A malformed cursor returns `400`.
- The `success=false` view is what an AI agent (or you) should read
  first when investigating an incident — each failed check carries the
  location and the probe's error text.

## Run a check now

`POST /v1/monitors/{id}/check-now` — requires `write` scope. Dispatches
one immediate check without changing the schedule. The call is
asynchronous: it returns `202 Accepted` and the result appears in
[check history](#check-history) within the probe timeout (typically well
under a minute).

```bash
curl -X POST https://watchfor.io/api/v1/monitors/0b0f6a41-…/check-now \
  -H "Authorization: Bearer wf_live_YOUR_KEY"
```

```json
{
  "object": "check_now",
  "monitor_id": "0b0f6a41-…",
  "status": "dispatched",
  "message": "Check dispatched — the result appears in GET /v1/monitors/{id}/checks shortly"
}
```

The budget is your plan's *Run now* allowance — per monitor, per hour,
shared with the dashboard's "Run check now" action and visible as
`run_now_per_hour` on [`GET /v1/plan`](/docs/api/plan).

| Situation | Response |
| --- | --- |
| Allowance for this monitor used up | `429 rate_limited` with `Retry-After` |
| Plan has no on-demand checks | `403 forbidden` |
| Monitor is paused | `409 conflict` — resume it first |
| Monitor not scheduled yet (just created) | `409 conflict` — try again in a moment |
| `heartbeat` monitor | `400 invalid_request` — heartbeats are checked by your own pings |

Each dispatch is recorded in the [activity log](/docs/api/activity) as
`monitor.check_now`.

## Also via

MCP tools `get_monitor_uptime`, `get_monitor_checks`, `run_check_now`;
A2A skills `explain-monitor` and `manage-monitor` (`run-check`); CLI
`watchfor checks <monitor-id> --failed`.

---

Canonical page: https://watchfor.io/docs/api/checks-uptime · All docs: https://watchfor.io/docs · Site guide: https://watchfor.io/llms.txt
