API Checks
Call an endpoint on a schedule and check what comes back — the status code and the values in the JSON body — or chain several calls and pass values from one to the next.
API endpoint or API workflow
Two monitor types check APIs. Pick the one that matches what the check needs to do.
| Type | Use it when |
|---|---|
| API endpoint monitor | One request, optionally with a header, basic authentication or a proxy. You want to check the status code, the content type and fields in the JSON response. |
| API workflow monitor | Several requests in order — log in, then call an endpoint with the token you got back — or more than one custom header. |
Authorization and Header value to Bearer <token>, or use the API key header your endpoint expects. When the token has to be fetched first, use an API workflow.Create an API endpoint monitor
- 1Choose the type
On the Monitors page, click New, open the type picker and choose API endpoint monitor.
- 2Enter the endpoint
Fill in API endpoint URL with the full URL, for example
https://api.example.com/v1/health. If you leave off the scheme,https://is added. - 3Add assertions (optional)
Under Response assertions (optional), click Add assertion for each value you want to check: a path into the JSON body, an operator, and the expected value. See Assertions.
- 4Set the request and the expected status
Open Advanced settings. The Request & validation section holds the options below. Then click Create monitor.
| Setting | Default | What it does |
|---|---|---|
| HTTP method | GET | GET, POST, PUT, PATCH, DELETE, HEAD or OPTIONS. |
| Expected status code | 200 OK | The status the response must have: 200 OK, 201 Created, 202 Accepted, 204 No Content, or Any 2xx (200–299). Any other status fails the check. |
| Request body (optional) | Empty | Sent with the request as you type it, except that {timestamp} is replaced with the current Unix time in milliseconds on every check. |
| Max response time | 30 seconds | 5, 10, 20, 30 or 60 seconds. A response that takes longer fails the check with a timeout. |
| Expected content type | application/json | The media type the response's Content-Type header must have: application/json, text/html, text/plain, or Any to skip the check. Parameters such as ; charset=utf-8 and letter case are ignored. |
| Follow redirects | On | Follow up to five redirects and judge the final response. |
| Check frequency | 3 minutes | How often each region calls the endpoint. |
Every request carries a User-Agent header that starts with Zharp Uptime Bot. Below Request & validation, the Request headers and HTTP authentication sections add one request header, HTTP Basic credentials, and an HTTP proxy for endpoints on a private network — they work the same as for website monitors, as do the SSL & domain verification settings.
201 or 204 fails. Choose that code or Any 2xx. The same goes for redirects when Follow redirects is off: a 301 never matches an expected 2xx code.Assertions
Assertions are checked against the JSON response body, after the status code has passed. They run in order, and the first one that fails fails the check. With no assertions, the status code is the only thing checked.
Paths
- Dots walk into objects:
data.statusreads{"data": {"status": "ok"}}. - Brackets pick an array item:
items[0].id. *matches every item of an array (or every value of an object):items.*.status.$on its own is the whole body.
When a path matches several values, an assertion passes if at least one of them satisfies it. The count operators are the exception: they count how many values the path matched. To count the items in an array, end the path with * — items.* — because items on its own matches one value, the array.
Operators
| Operator | Passes when the value… |
|---|---|
| Equals | is the same as the expected value, compared as text (so 200 equals "200"). |
| Not equals | differs from the expected value, compared as text. |
| Contains / Not contains | includes, or doesn't include, the expected text. |
| Starts with / Ends with | begins or ends with the expected text. |
| Greater than, Less than and the or equal forms | compares as a number with the expected value. |
| Exists | is present and not null. |
| Not exists | is missing or null. |
| Is null / Is not null | is, or isn't, exactly null. |
| Is empty | is an empty string, an empty array or an empty object. |
| Is not empty | is a non-empty string, array or object. |
| Count equals, Count greater than, Count less than and the or equal forms | — here the number of values the path matched is compared with the expected number. |
Exists, Not exists, Is null, Is not null, Is empty and Is not empty take no value, so the value box is hidden for them.
Create an API workflow
Choose API workflow monitor in the type picker. Under Workflow Configuration, pick Designer to build the workflow from steps, or Script Editor to write it as a script.
Designer
Click New Step for each request. Steps run from top to bottom; drag them to change the order. Each step has:
- Step Name, Method (GET, POST, PUT, PATCH or DELETE) and Endpoint URL.
- Payload — Request Headers (Add Header) and, for POST, PUT and PATCH, Request Body (JSON). A body that is valid JSON is sent as JSON.
- Assertions — New Assertion adds a path, operator and value, with the same paths and operators as above. In a workflow step the path
statusmeans the HTTP status code, not a field in the body, and a path starting withheaders.reads a response header —headers.content-type, with the header name matched regardless of case. The value can use{{NAME}}like the request does. - Variables — Extract Value saves something from the response under a name. Choose JSON Body and give a path such as
session.token, or Header and give a header name such asLocation. If a path matches several values, the first is kept.
Use a saved value in any later step by writing {{NAME}} in its URL, a header value, the body or an assertion value. Names under Environment Variables work the same way from the first step on. A name that hasn't been set is left in the request as written.
A step fails when one of its assertions fails or when its response status is 400 or higher. Add an assertion on status to decide the status yourself — for example to expect a 404. The workflow stops at the first failed step. Each request times out after 30 seconds, follows up to five redirects and sends User-Agent: Zharp/1.0 (Multi-Step Bot) unless you set your own. A workflow with no steps — or a script editor workflow with an empty script — is reported as down, since it checked nothing.
Script Editor
The script editor takes a Playwright test, run in headless Chromium on Zharp's servers. Use the request fixture for API calls. Import lines are ignored, and the whole script must finish within 30 seconds. Store secrets under Environment Variables and read them as process.env.NAME. The script runs in an isolated sandbox: process.env holds only these variables, and there is no access to Node.js modules (require), files or anything else on the server. Requests the script makes — the request fixture, fetch and axios — can't reach private, loopback or cloud-metadata addresses. Run Script runs the script once, with the same environment variables, and shows its output. Supported expect checks are toBe, toEqual, toContain, toBeTruthy, toBeOK, toHaveURL, toContainText, toBeVisible and toHaveTitle.
Example: log in, then call an authenticated endpoint
This workflow checks that users can sign in and load their profile. It logs in with a dedicated monitoring account, keeps the token from the response, and uses it on the next call.
- 1Step 1 — Log in
Method
POST, Endpoint URLhttps://api.example.com/v1/auth/login. Request Body (JSON):{ "email": "monitor@example.com", "password": "your-monitor-password" }Assertions:
statusEquals200, andtokenExists. Variables: nameAUTH_TOKEN, from JSON Body, pathtoken. - 2Step 2 — Load the profile
Method
GET, Endpoint URLhttps://api.example.com/v1/me. Add a headerAuthorizationwith the valueBearer {{AUTH_TOKEN}}.Assertions:
statusEquals200, andemailEqualsmonitor@example.com.
The same workflow in the Script Editor, with the password stored as the environment variable MONITOR_PASSWORD:
import { test, expect } from '@playwright/test';
test('log in and read the profile', async ({ request }) => {
const login = await request.post('https://api.example.com/v1/auth/login', {
data: { email: 'monitor@example.com', password: process.env.MONITOR_PASSWORD },
});
expect(login).toBeOK();
const { token } = await login.json();
const me = await request.get('https://api.example.com/v1/me', {
headers: { Authorization: `Bearer ${token}` },
});
expect(me).toBeOK();
const profile = await me.json();
expect(profile.email).toBe('monitor@example.com');
});When it goes down
Expand a failed row under Recent checks or Recent runs on the monitor page to see the message. The incident describes the cause in plain words.
| What happened | Message on the check |
|---|---|
| The status didn't match Expected status code | HTTP Error: 503 (Expected: 200) |
| An endpoint assertion failed | Assertion Failed: Assertion [data.status equals ok] failed. Actual: degraded |
| The response's Content-Type wasn't the expected one | Unexpected content type: text/html (Expected: application/json) |
| The endpoint took longer than Max response time | The timeout error, for example timeout of 30000ms exceeded |
| A workflow step got a status of 400 or more | Step failed with status 500 |
| A workflow step assertion failed | Assertion [token exists ] failed. Actual: undefined |
| A workflow step got no response | Step 2 Error: |
| A workflow script threw or timed out | Script Execution Failed: |
| The workflow has no steps | Workflow has no steps — add at least one request. |
The last two are followed by the underlying error. An API endpoint monitor's page shows the Last response — status, time, size and content type — with each assertion marked passed or failed. Its Recent checks rows open into the request headers, the response status and time, and which assertions passed. An API workflow's page lists Recent runs; open one to see its duration, how many steps completed and the request of the step that failed.
Troubleshooting
- An assertion fails although the field is there. Assertions read the parsed JSON body. If the endpoint doesn't return JSON, only
$refers to anything. Call the endpoint yourself and check the shape of what comes back — paths are case-sensitive. - A count assertion always sees 1. End the path with
*, as initems.*. - A body field named status can't be checked in a workflow. In a workflow step
statusis the HTTP status code. Use an API endpoint monitor for that field. - The second step gets
{{AUTH_TOKEN}}literally. The variable wasn't set. Check the extraction path against what the first step's endpoint returns, and that the name in{{…}}matches the variable name exactly. - Only some regions fail. The monitor stays up and its page shows which regions are failing; nobody is alerted. See Core Concepts.