Guides

How to monitor an API endpoint, not just whether it answers

Check an API's status code, its response body and how long it takes, so a 200 with an error inside does not pass for healthy.

Check what users do · 4 min read · Updated Oct 12, 2026

An API can be down while answering every request. The load balancer returns its own error page with a 200. The service is up but its database is not, and every response is {"status":"error"}. An authentication change makes every call return 401, which is a perfectly prompt answer.

A check that only asks "did something reply?" passes all three. Monitoring an API means saying what a correct reply looks like.

How it works

There are three questions, each stricter than the last.

  1. Does it answer? A connection is made and a response comes back in time.
  2. Is the status right? The response code is the one a healthy service gives.
  3. Is the content right? The body contains what a healthy response contains.
GET api.example.com/health
HTTP 200 · 184 ms{"status":"error","database":"unreachable"}
Does it answer?yes
Is the status right?200
Is the content right?"status":"ok" not found
A check on the status alone passes this response. A check on the body does not.

A good API check asks all three of one endpoint that is cheap to call and tells the truth about the service.

Step 1: Pick an endpoint that tells the truth

The best target is a health endpoint written for the purpose. It should:

  • Test what the service depends on, such as its database and its queue, and not only that the process is running.
  • Say the result in the body, and with the status code: 200 when healthy, 503 when not.
  • Be cheap and read-only, so calling it every minute changes nothing and costs little.
{ "status": "ok", "database": "ok", "queue": "ok" }

If you cannot add one, choose a real read endpoint whose answer you can predict. Avoid the root address: / often returns a welcome message whatever state the service is in.

Step 2: Say what healthy looks like

See what a check will see:

curl -sS -w '\n%{http_code} %{time_total}s\n' -H 'Authorization: Bearer YOUR_KEY' https://api.example.com/health

Then pin two things:

  • The status. Expect the one code a healthy response gives. For an API, do not accept redirects as healthy: a redirect to a login page is not health.
  • A piece of the body. Choose text that only a healthy response has, such as "status":"ok".

Body matching is usually exact, including upper and lower case and spaces: "status":"ok" does not match "status": "ok". Copy the text from the curl output, not from memory, and pick text that does not change between calls. Not a timestamp, a count or an id.

Step 3: Give the check its own key

If the endpoint needs a key, make one for monitoring. Read-only, nothing else, and revocable without breaking anything. A monitoring tool is one more place a secret is stored, so it should hold the least powerful one you have.

Never use a personal or administrator key. When that person leaves or rotates it, the check fails, and until then a powerful key sits in a setting.

Step 4: Decide what slow means

An API that answers correctly in six seconds is not healthy either. There are two separate limits:

  • The timeout. A response slower than this counts as a failure. Set it to the slowest answer you would still call working.
  • A latency alert. A warning when responses have been slower than normal for several minutes, well before the timeout.

Slow is a warning; down is an emergency. Send the latency alert somewhere less urgent than the down alert.

Step 5: Check from more than one place

A single checker cannot tell "the API is down" from "my network path to it is down". Run the check from several regions, and alert only when more than one agrees. That removes most false alarms without hiding a real outage.

Then test it: point a second check at the same address with body text the response does not contain. It should fail, name the missing text, and reach a person.

Common mistakes

  • Matching text that changes. A body check on a timestamp or a version number fails on the next deploy.
  • Monitoring a cached response. If a CDN serves the endpoint from cache, the check passes while the service behind it is down. Check an address that is not cached.
  • Calling something expensive every few seconds. The monitor becomes part of the load. Use a cheap endpoint or a longer interval.
  • Checking a write endpoint. A check that creates an order every minute is a new problem. Keep checks to reads.
  • A health endpoint that always says ok. If it does not test the database, it is an uptime check with extra steps.

Doing this in saysOK

An HTTP monitor asks all three questions. Expected response takes the status (200, any 2xx, 2xx or 3xx, or a code you enter) and a Body contains text, which is matched exactly. Up to five redirects are followed and the last response is the one judged, so a redirect to a login page that answers 200 passes on status alone: the body text is what catches it. One custom header can be sent with each check, for the key; it is not passed on if the endpoint redirects to another host. The check sends no request body, so it suits endpoints read with GET.

Recent checks
FrankfurtOct 12, 12:04:10 · 182ms
200
VirginiaOct 12, 12:03:10 · 240ms
200
SingaporeOct 12, 12:02:10 · 310msExpected text ""status":"ok"" was not found in the response
200
Each check records where it ran, how long the answer took and why it failed. The last one answered 200 with the wrong body.

Time out after is the timeout from step 4, and an alert rule with the condition Latency exceeds threshold is the warning; the Latency budget template sets one up. The monitor form shows how many of the regions you chose must agree before it counts as down.

HTTP checks are in every plan. The Keyword check type, which can also fail when unwanted text appears, is not; see pricing.

Next

An endpoint check tells you one request works. For a whole journey through a web page, see how to check that a login or checkout flow still works. For jobs that run behind the API, see how to monitor a cron job.

Set this up in saysOK

Start on the free plan. The guide says where a step needs a paid one.