# What a monitor is

A **monitor** is one scheduled check of one target. It has a **type** (what kind of check), an **address**
(URL, host, host:port...), a **schedule** (an interval or a cron expression), the **locations** it runs from, a
**recheck strategy** that confirms failures, type-specific **settings**, and the **contacts** it alerts. Every
check produces a result; a confirmed change between up and down opens or closes an
[incident](/incidents/what-is-an-incident/).

This page is the reference for the monitor object itself. Each setting has its own page with the details.

## The parts of a monitor

| Setting (app label) | API field (v2) | Type / allowed values | Default | Plan limits | What it does for you |
|---|---|---|---|---|---|
| Monitor type (picked when you click **Add Monitor**) | `type` | One of `http`, `api`, `ping`, `port`, `waterfall`, `tran`, `cntCheck`, `database`, `counter`, `snmp`, `dnsbl`, `domainExp`, `sslExp`, `webRisk` (and `crawl` where your plan includes it) | - (required) | Some types are a plan feature | Decides what is checked and which settings exist. It cannot be changed later. See [Monitor types](/monitors/monitor-types/). |
| **URL, domain, or IP** | `url` | Text; format depends on the type | - (required for most types; Database and SNMP monitors build it from their settings, and a Counter monitor may send `settings.probeUrl` instead) | - | The target. HostTracker may normalise it (for example add a trailing `/`); the read then also shows `effectiveUrl`, the exact address checked. |
| **Monitor name** | `name` | Text, up to 255 characters | Empty (the address is shown instead) | - | The label used in alerts, reports, widgets and status pages. |
| **Monitoring enabled** | `enabled` | `true` / `false` | `true` | Enabled monitors count toward your plan's monitor limit | Off = paused: no checks, no alerts. See [Pause, enable and delete](/monitors/pause-enable-delete/). |
| **Interval schedule** / **Cron schedule** | `interval` (seconds) or `cronSchedule` | See [Check intervals](/monitors/intervals/) | 3 minutes for most types | Plan minimum interval; cron is a paid feature | How often the check runs. |
| **Timeout** | `settings.timeout` (milliseconds) | Per type | 40 seconds for web types | - | How long one check waits before it counts as failed. See [Timeouts and response size](/monitors/advanced/response-limits/). |
| **Tags** | `tags` (`addTags` / `removeTags` on update) | Array of strings | None | - | Grouping and filtering. See [Tags](/monitors/tags/). |
| **Full Log** | `fullLog` | `true` / `false` | `false` | Plan feature | Keeps every check result instead of grouped events. |
| **Open Stats** | `openStat` | `true` / `false` | `false` | - | Publishes an anonymous public statistics page for the monitor. |
| **Monitoring Locations** | `locations.pools`, `locations.fallback`, `locations.excludedAgents` | Pool ids, agent ids | In the app: your profile default. On the API: required on create for the types that run from locations (`http`, `api`, `ping`, `port`, `waterfall`, `tran`, `cntCheck`, `crawl`); the other types take none | - | Where the check runs from. See [Monitoring locations](/monitors/default-locations/). |
| **Recheck strategy** | `recheck.strategy`, `recheck.minNumDown` | See [Recheck strategy](/monitors/advanced/recheck-strategy/) | Majority vote | - | How a failure is confirmed before the monitor turns Down. |
| Type-specific settings (Request Configuration, Response Validation...) | `settings.*` | Per type | Per type | Keywords, assertion count, TLS policy and custom DNS can be plan features | Method, headers, keywords, assertions, TLS policy and so on. See the page for each [monitor type](/monitors/monitor-types/). |
| **Attached monitors** | `attached.dnsbl`, `attached.sslExp`, `attached.domainExp`, `attached.webRisk` | Booleans (or objects) | Off | Each sub-check is a plan feature | Extra sub-checks that ride on a web monitor. See [Attached sub-checks](/monitors/types/attached-sub-checks/). |
| - (API only) | `slaTarget` | Number 0-100, or `null` | `null` | - | Your SLA target percent, used by uptime summaries and reports. |
| **Alert Subscriptions** / **Report Subscriptions** | `alertSubscriptions`, `reportSubscriptions` (create only) | Contact ids + event or frequency lists | In the app: all contacts get Up/Down alerts and reports (configurable under **Profile -> Defaults**) | Contact types and report frequencies depend on your plan | Who hears about this monitor. See [Subscribe contacts to monitors](/alerts/subscribe-monitors/). |

Read-only members every monitor carries: `id`, `state`, `since` (when the current state began), `created`,
`updated`, and for certificate and domain expiry monitors `expirationDate` (plus `certNotBefore` for
certificates). All timestamps are Unix seconds.

## The four states

| `state` | Shown as | Meaning |
|---|---|---|
| `up` | green | The last confirmed result was a success. |
| `down` | red | A failure was confirmed by the [recheck](/monitors/down-detection/). An incident is open. |
| `maintenance` | maintenance marker | The monitor is inside a [maintenance window](/maintenance/overview/). Checks still run, but it is not reported as down. |
| `paused` | grey / Disabled | Not being checked. Either you switched it off (`enabled: false`) or it is over your plan's monitor limit. |

The state is derived with a fixed precedence: **paused, then maintenance, then up/down**. A monitor over your
plan limit keeps `enabled: true` but reads `state: "paused"`, so check both fields when you need to know why a
monitor is silent. The dashboard marks such rows **Over limit**.

## Where monitors live in the app

1. Open **Sites** in the left sidebar (`/sites`). Every monitor is a row; down monitors sort to the top.
2. Click **Add Monitor** to create one: pick a type, enter the address, adjust the settings groups, then **Save**.
3. Click a row (or its menu -> **Edit**) to open the monitor's panel. The editor is split into collapsible groups:
   **Main Settings** (enabled switch, schedule, timeout, tags, Full Log, Open Stats, attached monitors),
   **Monitoring Locations** (locations, recheck strategy, fallback), **Request Configuration** and **Response
   Validation** (web types), **Alert Subscriptions** and **Report Subscriptions**.
4. Use the search box (**Search by name or URL**), the type, status and tag filters, and the view switcher (Full,
   Card, Grouped, Simple, Tall) to find monitors. The Grouped view groups rows by monitor type.

## Read one monitor with the API or MCP

```bash
curl "https://api2.host-tracker.com/monitor/$MONITOR_ID" \
  -H "Authorization: Bearer $HT_TOKEN"
```

`GET /monitor/{id}` (scope `monitor:read`) returns the full configuration: `expand=settings` is its default.
Add more with `expand=` (the list below); sending `expand=` replaces the default set, so include `settings` if you
still want it. MCP: **`get_monitor`** (default expand `settings,uptime`).

Credentials inside `settings` (passwords, keys) are returned to the account owner and to subaccounts with edit
rights; a view-only subaccount sees `{ "set": true, "updatedAt": ... }` instead.

## List, filter and search monitors

`GET /monitor` (scope `monitor:read`) returns a lean row per monitor - `id`, `type`, `name`, `url`, `state`,
`since`, `enabled`, `tags`, `updated`, `created`, `openStat`, `fullLog`, `cronSchedule` and the expiry dates -
inside the standard page envelope `{ "data": [...], "nextCursor": "...", "hasMore": true }`.

```bash
# Down HTTP monitors tagged prod, 100 per page, with their settings and last incident
curl "https://api2.host-tracker.com/monitor?state=down&type=http&tag=prod&limit=100&expand=settings,lastIncident" \
  -H "Authorization: Bearer $HT_TOKEN"
```

| Parameter | Values | What it does |
|---|---|---|
| `q` | Text | Case-insensitive substring match over name and address. No wildcards: `*` is taken literally. |
| `type` | One or more type tokens | Unknown tokens are refused with `422`, never silently ignored. |
| `state` | `up`, `down`, `paused`, `maintenance` | Current state (see above). |
| `enabled` | `true` / `false` | The configured switch. Use `state=paused` to also catch over-limit monitors. |
| `tag` | One or more tags | A monitor matches if it carries **any** of the listed tags; each tag must match a whole tag. See [Tags](/monitors/tags/). |
| `id` | One or more monitor ids | Only these monitors. |
| `includeId` | One or more monitor ids | Always include these rows in addition to whatever the other filters match. |
| `url` + `like` | Address(es); `like=true` | Exact (case-insensitive) address match, or substring match with `like=true`. `like` without `url` is refused. |
| `preset` | `bl:ru` | Monitors built from a settings preset (the Russian blacklist check, stored as `type: "http"`). |
| `openStat` | `true` / `false` | Monitors whose public statistics page is on or off. |
| `updatedSince` | Unix seconds, or a previous response's `syncCursor` | Monitors created, changed state, or auto-disabled since then. A configuration edit or a manual pause does **not** move `updated` - subscribe to the `monitor.updated` webhook for those. |
| `sort` | `name`, `state`, `type`, `interval`, `lastChange`, `url`, `tags`, `created`, each optionally `:asc` / `:desc`; plus the one compound `state,lastChange` | Default `created` (newest first). `state` ascending puts down first, then maintenance, up, paused. |
| `pausedLast` | `true` | Moves every paused monitor after the rest, whatever the sort. |
| `limit` / `cursor` | 1-500 (default 50) / the previous `nextCursor` | Paging. Stop when `nextCursor` is `null`. Send the same filters and sort with every page: a cursor replayed under a different sort (or `pausedLast`) answers `422 invalid_cursor`, and changed filters give an inconsistent walk. |
| `expand` | See below | Adds blocks to each row or to the envelope. |
| `from` / `to` | Unix seconds | The window for `uptime`, `spans` and `summary` (default: the last 30 days). |
| `fields` | Comma-separated top-level member names | Returns only those members of each row (`id` is always kept). An unknown name answers `422 unknown_field`. |

Filters combine with AND. A list parameter can be repeated (`type=http&type=ping`) or comma-separated
(`type=http,ping`). Long filter sets can be sent as a JSON body to `POST /monitor/q` instead.

`expand` values (the same list works on `GET /monitor/{id}`):

| Value | Adds |
|---|---|
| `settings` | `interval`, `slaTarget`, `locations`, `recheck`, `settings`, `attached` |
| `attached` | `attachedResults` - the latest result of each attached sub-check |
| `subscription` | The monitor's alert subscriptions with the contact identity |
| `lastIncident` | The last up/down transition |
| `lastResult` | The newest check result (add `lastResult.metrics` / `lastResult.recheck` for the decoded measurements and the recheck locations) |
| `maintenance` | The maintenance windows covering the monitor |
| `uptime` | Uptime percent over `from`/`to` |
| `spans` | Up/down spans in the window, plus `disabledSpans` (paused periods) and `maintenanceSpans` |
| `summary` | Envelope block: account-wide counts, by type, by tag, the tag list, top domains, downtime |
| `count` | Envelope block: `{ total, matched }` |

MCP: **`list_monitors`** takes `q`, `state`, `type`, `tag`, `id`, `sort`, `limit` (1-50, default 20) and
`cursor`; use **`api_request`** for the parameters it does not expose (`expand`, `fields`, `updatedSince`...).
**`list_monitor_types`** returns the type catalogue.

## Limits and gotchas

- Unknown query parameters are refused (`422 unknown_parameter`), and so are unknown `expand` values
  (`422 unknown_expand`) - the error lists the allowed values.
- Deleted monitors simply disappear from the list; there is no tombstone. A client that mirrors your account
  should re-read the full list periodically or subscribe to the `monitor.deleted` webhook.
- `uptime` and response times are not sortable columns. To rank monitors by uptime, use
  `GET /monitor/result/summary` (MCP `get_uptime_summary`).

## Related

- [Anatomy of a check](/monitors/anatomy-of-a-check/)
- [Monitor types](/monitors/monitor-types/)
- [Monitor settings reference](/reference/monitor-settings/)
- [REST API v2](/integrations/rest-api/)
