✦ Blog

How to Monitor an API Endpoint: Health Checks That Work

What to check on an API (availability, status codes, latency, SSL), how to design a /health endpoint, sensible thresholds, and alerts that don't cry wolf.

Upmonora team4 min read

Overview - How to Monitor an API Endpoint: Health Checks That Work

Your API can be "up" and still broken: returning 500s to every third request, taking four seconds to answer, or serving an expired certificate that every client library rejects. Good API monitoring catches all three - without paging you every time a single request drops.

What to check

SignalWhy it mattersTypical threshold
AvailabilityCan clients connect at all? DNS, TCP and TLS all have to work.Any connection failure
Status codeA 200 means success; 5xx means the service is failing. A redirect to a login page is a silent failure.Expect exactly 200 (or 204)
LatencySlow APIs cause client timeouts and cascading failures downstream.2-3× your normal response time
SSL certificateAn expired or mismatched certificate breaks every client at once.Alert 30/14/7/1 days before expiry

Checking the content of the response (for example that a JSON field has the right value) is a useful extra layer. Upmonora doesn't support JSON assertions yet - it's on the roadmap - so design your health endpoint to put the verdict in the status code, as described below.

Design a health endpoint worth monitoring

Monitoring your homepage or a random GET endpoint tells you little. A dedicated endpoint does better:

GET /health
200 OK            → the service can handle real requests
503 Unavailable   → it can't (database down, required dependency missing, draining)

Rules that keep it useful:

  • Check what you need to serve traffic. A database ping and the cache connection, yes. Every third-party API you call, no - otherwise their outage becomes your outage.
  • Keep it fast. Aim for under 100 ms. Put a short timeout on each dependency check.
  • Put the verdict in the status code. Returning 200 with {"status":"down"} in the body defeats most monitors and load balancers.
  • Don't leak internals. No versions, hostnames or stack traces in a public endpoint.
  • Don't cache it. Send Cache-Control: no-store so a CDN doesn't keep serving a stale "healthy".

A minimal example in Node.js (Express):

app.get('/health', async (req, res) => {
  res.set('Cache-Control', 'no-store');
  try {
    await db.query('SELECT 1');           // what we need to serve traffic
    res.status(200).json({ status: 'ok' });
  } catch {
    res.status(503).json({ status: 'unavailable' });
  }
});

And in PHP:

header('Cache-Control: no-store');
try {
    $pdo->query('SELECT 1');
    http_response_code(200); echo '{"status":"ok"}';
} catch (Throwable) {
    http_response_code(503); echo '{"status":"unavailable"}';
}

Liveness vs readiness

If you run on Kubernetes you'll meet both. Liveness asks "is the process stuck - should it be restarted?" and should almost never fail. Readiness asks "should this instance receive traffic right now?" and fails when a dependency is down. For external monitoring, the readiness-style endpoint is the one to watch.

Pick an interval and a failure threshold

  • Interval: 30-60 seconds for customer-facing APIs, 5 minutes for internal ones.
  • Timeout: a little above your worst acceptable latency (often 5-10 seconds). A request that takes 30 seconds is effectively down for clients with shorter timeouts.
  • Failure threshold: open an incident after 2-3 consecutive failures. At 30-second checks that's a 60-90 second detection time with almost no false alarms. (Why one failed check should never wake you up.)
  • Multiple regions: checking from more than one location separates "our API is down" from "one network path is broken".

Watch latency against your own baseline

Static thresholds ("alert above 1 second") are either too loose to catch a real slowdown or too tight to stay quiet. Comparing each check with the endpoint's own recent baseline works better: 150 ms rising to 450 ms is worth knowing about even though both numbers sound fine. Upmonora's anomaly detection does this automatically and explains what changed in plain language.

Route alerts where developers already are

Send API alerts to Slack or Microsoft Teams for the team, email for the owner, and a signed webhook into your incident tool. Include the status code, the error and the response time in the alert itself so nobody has to open a dashboard to triage.

Automate it

If you create services often, create their monitors from CI too. The Upmonora REST API lets a pipeline add a monitor on deploy and pause it during maintenance - see Create monitors from CI. To set one up by hand, point an API monitor at your /health endpoint - the free plan covers 5 monitors.

Frequently asked questions

What is API monitoring?

Regularly calling your API from outside your infrastructure and checking that it responds, returns the expected status code, and answers fast enough - then alerting someone when it does not.

What should a health check endpoint return?

A fast 200 response when the service can do its job, and a 503 when it cannot. Keep it cheap, avoid calling slow third parties, and do not expose sensitive details in the body.

How often should I check my API?

Every 30 to 60 seconds for production APIs that customers depend on, every 5 minutes for internal or low-traffic ones. Combine frequent checks with a failure threshold so single blips do not page anyone.

What is a good API response time?

For simple reads, under 200-300 ms at the server is good. What matters most is your own baseline: a sudden rise from 120 ms to 600 ms is a problem even though 600 ms sounds acceptable.