Skip to main content

Worked health samples

The liveness probes report one thing: whether the API process is up and answering requests. They do not probe the database or any upstream dependency — use GET /health/email below when monitoring an individual channel instead of the origin’s alive signal. The 200 body carries three fields:
  • status — the string "ok". Assert on this exact value; anything else (or a non-2xx status) means the probe is failing.
  • timestamp — the ISO-8601 wall time on the API at response time.
  • version — the git SHA of the running build. Poll this after a deploy to confirm every pod rolled out before you shift traffic.
All three aliases return the identical body, and none require the X-API-Key header — send it if your template cannot omit headers, it is ignored either way. The two versioned aliases (/api/health and /api/v1/health) expand the same data into a per-subsystem register — a top-level status plus one components row each for the API, database, cache, voice gateway, worker, and storage — so status pages can attribute a degraded interval to the failing piece. The worked responses in the two operation sections below show that shape; section 6 shows the degraded variant.

1. Liveness probe

200

2. The three aliases

GET /health, GET /api/health, and GET /api/v1/health all run the same liveness handler and return the same body. Point your checker at whichever path it already polls — listing all three on one load balancer adds nothing. Kubernetes liveness, external uptime monitors, and most health-check configurations each conventionally guess a different one, which is why all three exist.
Each alias returns the same body shape as section 1 — one probe result, no per-alias variation to branch on.

3. Reading the probe in a load balancer or CI

Assert on status === "ok"; the timestamp and version fields are context, not gates:
A non-2xx (or a body whose status is not "ok") tells the load balancer to pull the pod out of rotation. A version that does not match the SHA your deploy pipeline just shipped tells CI a stale pod is still serving, so the rollout has not finished — keep checking until it converges before draining the old pool.

4. Errors

The unversioned probes never validate credentials, so the failure modes are transport-level rather than API-level:
  • 5xx / connection refused — the process is not answering; the load balancer’s retry policy applies.
  • 429 — rate limited — shared-rate monitors probe too frequently; raise the interval.

5. Email-channel liveness

GET /health/email is a separate probe for the email channel’s outbound path, so a tenant email outage does not read as an API-wide outage. Use the generic /health above for the origin and /health/email only when you track email as its own component; the public status page wiki documents one health-check URL per component. The API request logs console covers the deeper tenant-side monitoring path when a probe flaps but the endpoint keeps returning "ok".
A reachable email channel returns 200:
200
When the provider is unreachable the same call returns 503, with status reading "degraded" and a detail string describing the underlying failure — the status page records that interval as downtime instead of the 100%-uptime reading the bare /health probe would give during a real email outage.

6. The degraded variant of the origin probes

When a subsystem fails its probe, GET /api/health and GET /api/v1/health return the same components register with that component reading "red" and the top-level status flipped to "degraded":
200
Read the two levels apart: status is the rollup (every component green ⇒ "ok"; any red ⇒ "degraded"), while each component row names the failing piece and, once degraded, carries degraded_since plus a short detail. A yellow component alone keeps the top-level status at "ok" and only flags the row. The HTTP code stays 200 in both cases — gate your status page on the body, not on the status code.