Skip to content

Monitor an API response (API monitor)

View as Markdown

The API monitor (API type api, shown in the app as API monitoring/text analysis) is a Website / HTTPS check that also reads the response body: it parses it as JSON, XML or text, picks one value out of it and compares that value with what you expect. Use it when “the endpoint answered 200” is not proof enough - you want $.status to be "ok", a queue length to stay under 100, or a price field to exist.

API type token api
Runs from HostTracker’s public checkpoint fleet - you pick the locations
Intervals in the app 1 minute to 24 hours, or a cron schedule
Default interval 3 minutes
Plan gates the API monitoring type is a package feature (apiTask); the Http options keep their own gates

Everything the Website monitor checks (DNS, connection, TLS, status below 400, your status-code rules), and then:

  1. The body must parse in the chosen Response format.
  2. The Selector picks a value (empty selector = the whole body).
  3. The Condition must hold for that value. If the selector matches nothing, every condition except no and null fails with “No value selected”.

With Assertion mode on, the rule list replaces steps 1-3. A failure is re-checked from other locations before the monitor turns Down - see How down detection works.

The API editor is the Website editor with a different Response Validation group. Everything in Common monitor fields, Main Settings, Request Configuration and Monitoring Locations works exactly as on the Website page, with these differences:

  • The address field is labelled API endpoint.
  • Request body offers Raw body (settings.body) and POST parameters (settings.postParameters, one KEY=VALUE per line, sent form-encoded).
  • Attached monitors offers Domain Expiration, Certificate Expiration and Web Risk. DNSBL and Indexability are not available on API monitors.
  • Keywords and Successful content check condition are not part of the API editor. The HTTP Policies picker is, but it has no API member yet.
Setting (app label) API field Type / allowed values Default Plan limits What it does for you
Response format settings.contentType application/json (JSON analysis), text/xml (XML analysis), text/plain (String analysis) application/json in the app; required in the API unless assertMode is on - How the body is parsed before the selector runs. Needs GET (or another method that returns a body).
Selector settings.valueSelector JSON: property selector or JSONPath ($.data.status); XML: XPath; text: a regular expression with a capture group (multiline, case-insensitive) empty = the whole body - Picks the value to test. It is compiled when you save, so a broken selector is refused then, not at check time.
What to check settings.expectation.change, settings.expectation.cpt Check the obtained value itself (change: 0); Check the value change between checks (change: 1); Change per second (change: 1, cpt: "s"); Change per minute (change: 1, cpt: "m") the value itself - Judge the value, or how much a number moved since the previous check. Change modes work on numbers only.
Condition settings.expectation.func + settings.expectation.args see the table below any (no validation) - no expectation - The comparison that decides Up or Down.
Ignore HTTP Errors, Error on these HTTP statuses settings.ignoredStatuses, settings.errorStatuses up to 20 codes each, 100-599 none - As on the Website monitor.
Assertion mode settings.assertMode + settings.assertsSource or settings.asserts up to 20 rules; your package may allow fewer off assertion count and stateful rules are package features A rule list instead of format/selector/condition. See Assertions.
TLS Handshake switches, Expected IPs Validation, Max response size as on the Website monitor

The whole expectation object is limited to 1024 characters.

Condition values:

App option func args The check fails when
any (no validation) omit expectation - never on the value - only parsing and transport are judged
equal to eq one value the value differs
not equal to neq one value the value matches
in set of in one or more values the value is none of them
out of set out one or more values the value is one of them
less than / less or equal ls / le one number the value is not below (or at most) it
greater than / greater or equal gt / ge one number the value is not above (or at least) it
in range inr two ascending numbers the value is outside [args[0], args[1]]
out of range outr two ascending numbers the value is inside the range
json null null none the selected value is not null (nothing selected counts as null)
absent in content no none never - the check extracts the value and does not compare it

args are strings in JSON (["ok"], ["100"]). eq, neq, in and out compare the value as it is; the other conditions, and every condition in a change mode, compare numbers.

  1. On the Sites dashboard, click Add Monitor and choose API monitoring/text analysis in Monitoring Type.
  2. Enter the API endpoint and a name.
  3. In Request Configuration, set the HTTP Method, any HTTP Headers (for example an API key) and the Request body if the endpoint needs one.
  4. In Response Validation, choose the Response format, type the Selector, pick What to check and a Condition with its value.
  5. Review Alert Subscriptions and Monitoring Locations, then click Save.

POST /monitor (scope monitor:write), base URL https://api2.host-tracker.com:

Terminal window
curl -X POST https://api2.host-tracker.com/monitor \
-H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \
-d '{
"type": "api",
"url": "https://api.example.com/health",
"interval": 60,
"locations": { "pools": ["allworld"] },
"settings": {
"contentType": "application/json",
"valueSelector": "$.status",
"expectation": { "func": "eq", "args": ["ok"] }
}
}'

The same check written as assertion rules instead:

{
"type": "api",
"url": "https://api.example.com/health",
"interval": 60,
"locations": { "pools": ["allworld"] },
"settings": {
"assertMode": true,
"assertsSource": "status eq 200\nbody.json.path(\"$.status\") eq \"ok\""
}
}

Update - for example, alert when a queue grows past 100:

Terminal window
curl -X PATCH https://api2.host-tracker.com/monitor/<monitor-id> \
-H "Authorization: Bearer $HT_TOKEN" -H "Content-Type: application/json" \
-d '{ "settings": { "valueSelector": "$.queue.length",
"expectation": { "func": "ls", "args": ["100"] } } }'

MCP (interval is passed to the API as-is, in seconds):

create_monitor(type="api", url="https://api.example.com/health", interval=60, pools="allworld",
settingsJson="{\"contentType\":\"application/json\",\"valueSelector\":\"$.status\",\"expectation\":{\"func\":\"eq\",\"args\":[\"ok\"]}}")
update_monitor(id="<monitor-id>", settingsJson="{\"expectation\":{\"func\":\"ls\",\"args\":[\"100\"]}}")
  • A JSON field equals a value - contentType: application/json, valueSelector: $.status, expectation: {func: eq, args: ["ok"]}.
  • A number stays in range - valueSelector: $.latency_ms, expectation: {func: inr, args: ["0", "500"]}.
  • A counter keeps growing - expectation: {func: gt, args: ["0"], change: 1} (fails if it stops moving up).
  • An XML element - contentType: text/xml, valueSelector: /response/status, func: eq.
  • A value in plain text - contentType: text/plain, valueSelector: version=(\d+), func: ge.
  • Several conditions at once - use assertion mode; one rule per line.
  • Authenticated API - add headers: [{"name": "Authorization", "value": "Bearer ..."}].

Each check downloads the body (up to Max response size), parses it and records the selected value in the check log, so you can see what was compared. A failed condition is re-checked from other locations, then opens an incident and alerts the subscribed contacts.

  • 403 package_limit - your package does not include the API monitoring type.
  • 422 invalid_settings - a malformed selector, a wrong number of args for the func (two ascending numbers for inr/outr, at least one for in/out, exactly one for the comparisons), or contentType missing while assertion mode is off.
  • assertMode refuses contentType, valueSelector and expectation in the same monitor, as well as the Http status and keyword fields.
  • HEAD returns no body, so use GET (or POST/PUT/PATCH) for a format and selector check.
  • The absent in content option (no) does not test absence; to fail when a field is missing, use any comparison - a missing value fails it.