Public APIs
All posts

API Health Check Endpoints: What Real Public APIs Expose

Quick answer: A health check endpoint is a URL, usually /health or /healthz, that returns 200 when the service can take traffic and an error when it cannot. Public APIs rarely agree on the path: on 29 October 2026, CoinGecko answered at /api/v3/ping, npm at /-/ping, and 0 of the 4 APIs where we guessed a /health path answered there.

Most guides explain how to build one. We run Public APIs, a crowdsourced API directory for developers, so we called 15 real URLs instead: 8 documented health, ping, heartbeat or status routes, the conventional /health guessed on 4 keyless APIs from the directory, and 3 controls. One GET each, on 29 October 2026 at 10:39 UTC, from one machine.

What is a health check endpoint?

It is a cheap, unauthenticated route that answers one question for a load balancer, an orchestrator or an uptime monitor: should traffic go here? Two flavours exist. A liveness check says the process is running and should not be restarted. A readiness check says the instance can serve requests right now, which may depend on a database connection or a warmed cache.

The word "health" also collides with a category. In the 28 days to 22 October 2026, our Search Console showed about 200 impressions for /api/health and api/health, all landing on the health APIs category, which lists medical-data APIs. This page is the one those searchers wanted.

What do real public APIs expose?

| Route type | URL path | Status | Bytes | Content type | Cache-Control | |---|---|---|---|---|---| | Documented ping | CoinGecko /api/v3/ping | 200 | 34 | application/json | max-age=0, private, must-revalidate | | Documented ping | npm registry /-/ping | 200 | 2 | application/json | not sent | | Status page JSON | githubstatus.com /api/v2/status.json | 200 | 215 | application/json | max-age=10, public, s-maxage=10, stale-while-revalidate=20, stale-if-error=3600 | | Status page JSON | cloudflarestatus.com /api/v2/status.json | 200 | 230 | application/json | not sent | | Status page JSON | status.openai.com /api/v2/status.json | 200 | 202 | application/json | public, max-age=0, must-revalidate | | Info route | Spaceflight News /v4/info/ | 200 | 663 | application/json | max-age=600 | | Health route | Openverse /healthcheck/ | timed out after 30 s, 0 bytes | | | | | Heartbeat | Crossref /heartbeat | 200 | 41 | application/json | not sent | | Guessed /health | PokéAPI /health | 404 | 4,235 | text/html | max-age=3600 | | Guessed /health | REST Countries /health | 404 | 20,046 | text/html | not sent | | Guessed /health | Agify /health | 404 | 9 | text/html | max-age=0, private, must-revalidate | | Guessed /health | Dog API /api/health | 404 | 0 | not sent | no-store | | Control: API root | api.github.com / | 200 | 2,396 | application/json | public, max-age=60, s-maxage=60 | | Control: API root | api.discogs.com / | 200 | 186 | application/json | public, must-revalidate | | Control: fixed status | httpbin /status/200 | 200 | 0 | text/html | not sent |

Source: our http-probe, 29 October 2026, one GET per URL following redirects.

The split is clean. 7 of the 8 vendor-specific routes answered 200 with JSON (88%), and the eighth, Openverse, did not answer within 30 seconds. 0 of the 4 guessed /health paths returned 200. Those four are guesses: none of these APIs told us /health exists, and a 404 there says nothing about whether the API itself was up. The working routes were small, between 2 and 663 bytes.

What should /health return?

Copy the shape of the 200s above and fix what they skip:

  1. Status code first. 200 when healthy, 503 when not. Monitors and load balancers read the code, not the body.
  2. A small JSON body. Something like {"status":"ok"}, plus a version string if you want one. CoinGecko's ping is 34 bytes; npm's is 2. Every vendor route we probed answered application/json.
  3. No secrets. No hostnames, connection strings, dependency versions or stack traces on a public URL.
  4. Cache-Control: no-store. None of the 7 routes that answered 200 sent it. 3 sent no Cache-Control at all, and Spaceflight News sent max-age=600, which lets a cache report "healthy" for 10 minutes after the service fell over. The only no-store in the whole sample came from Dog API's 404.

The controls show why the code alone is not enough. httpbin returned 200 with an empty body, and REST Countries returned a 20,046-byte HTML page with its 404. A monitor that only checks "got a response" passes both. Check the status code and one field of the body, and keep the route out of your API caching rules.

Should a health check test dependencies?

Split it. A shallow check (liveness) answers from the process alone and stays fast and public. A deep check (readiness) pings the database, the queue and the upstream APIs, and belongs behind your network or an auth token.

A deep check on a public URL is two risks. Anyone can call it, so each request fans out into database and upstream calls you pay for; put it under the same API rate limiting as everything else, or do not expose it. And a detailed failure body tells an attacker which dependency is down.

The opposite failure is the one to design against: a shallow check returning 200 while the API behind it fails. Public APIs runs a weekly link sweep over its listings and quarantines unreachable ones; in the sweep reported in our API monitoring tools ranking, 80 of 1,569 listed APIs (5.1%) were unreachable on 25 August 2026, and only 7 of those were genuine 5xx responses. Most broken APIs do not fail politely, so the readiness check should exercise one real code path, not just the web server.

/health, /healthz, /ping or a status page: which path?

None of them is standard, and our probe found four styles in 8 routes: /ping, /heartbeat, /healthcheck/ and an info route. Three status pages shared one path, /api/v2/status.json, which makes them the most predictable thing in the sample. That JSON is a published incident status, though, not a probe of the API.

Pick one path, document it next to your authentication and errors, and keep it stable. /health is the most guessable, /healthz reads as Kubernetes-style to anyone who has used it, and a version prefix like CoinGecko's /api/v3/ping is fine if the docs say so. The guessed paths failed because nobody wrote them down, which our REST API best practices treat as part of the contract. Browse the development APIs in the directory to see how other builders document their routes.

What to do as an API consumer

When you depend on an API with no health route, monitor a real, cheap request instead. A keyless call such as a single forecast from Open-Meteo proves the path you rely on works, and its timing feeds your API response time budget. Assert on the status code and one field of the body, and treat a timeout like Openverse's as down.

How we measured it

On 29 October 2026 at 10:39 UTC we sent one curl GET to each of 15 URLs from one machine, following redirects, with a browser user agent, English Accept-Language and a 30-second timeout. We recorded the status code, decompressed body size, Server, Content-Type and Cache-Control. One run from one location is a small sample: a route that timed out for us may answer for you, and none of these numbers is an uptime figure.

FAQ

What is a health endpoint?

A health endpoint is an API route that reports whether the service can handle requests, usually with 200 for healthy and 503 for unhealthy. Load balancers, Kubernetes probes and uptime monitors call it on a schedule. It should be fast, small and free of secrets.

What is the difference between liveness and readiness checks?

Liveness asks whether the process is alive; if it fails, the orchestrator restarts it. Readiness asks whether the instance can serve traffic now; if it fails, traffic is routed elsewhere without a restart. Keep liveness shallow so a slow database does not trigger a restart loop.

Should a health check endpoint require authentication?

A shallow liveness check can be public, as all 7 routes that answered in our probe were. A deep readiness check that touches dependencies should sit behind authentication or an internal network, since it costs you resources and reveals your architecture.

What status code should a failing health check return?

503 Service Unavailable is the usual choice, optionally with a Retry-After header. Avoid returning 200 with an error in the body, because most monitors and load balancers read only the status code.

Is a status page the same as a health check?

No. A status page such as githubstatus.com publishes incidents that people declare, while a health check is a machine answer from the service itself. Use both: the health route for automation, the status page for humans.