Health & version probes
Bare-path liveness, readiness, and build-fingerprint endpoints for Kubernetes, Fly.io, and uptime monitoring.
Hatched exposes three top-level probe paths intended for ops tooling.
They serve the same purpose as the prefixed /api/v1/health/*
endpoints — but they are separate handlers, not the same backend, and
they skip the API prefix so K8s/Fly probes work out of the box without
remapping paths. The human-readable multi-component report lives at
GET /api/v1/health.
| Endpoint | Purpose | Status code |
|---|---|---|
GET /healthz | Liveness — "the process is up" | always 200 |
GET /readyz | Readiness — DB + Redis reachable | 200 ready, 503 not ready |
GET /version | Build fingerprint | always 200 |
The detailed multi-component breakdown (queues, image provider, latency
per dependency) still lives at GET /api/v1/health for dashboards or
on-call debugging.
GET /healthz
curl https://api.hatched.live/healthz
# {"ok":true,"uptime":4623}Returns immediately. Uptime is in seconds since process start. Use this
as your Kubernetes livenessProbe — restart the container only if the
process is genuinely wedged.
GET /readyz
curl -i https://api.hatched.live/readyz
# HTTP/1.1 200 OK
# {"ready":true,"db":true,"redis":true}Returns 503 with {"ready": false, ...} if Postgres or Redis is
unreachable. Use as the Kubernetes readinessProbe so the pod is removed
from the load balancer until both deps are green.
GET /version
curl https://api.hatched.live/version
# {
# "version": "1.42.0",
# "git_sha": "a1b2c3d4",
# "built_at": "2026-05-25T09:14:30Z",
# "node_version": "v20.11.0"
# }Useful as a deployment fingerprint:
- Diff
git_shabetween expected and actual to confirm a rollout succeeded across all instances. - Compare the SDK consumer's
client.auth.whoami()plan against the API'sversionwhen reproducing a bug — "I'm on 1.42.0 with plan growth" is a lot easier to triage than "I think it broke yesterday."
The three env vars API_VERSION, GIT_SHA, and BUILT_AT are injected
at build time by the deployment pipeline. Either may be "unknown" on
local dev or in test environments where the build step is skipped.
Why two paths per probe
/api/v1/health/live (prefixed) and /healthz (bare) are separate
handlers serving the same purpose — not the same handler. SDK calls and
human dashboards use the prefixed form; ops tooling uses the bare form.
Removing one of them would break either the SDK contract or the standard
probe playbook — both are kept stable.
Their response shapes and readiness semantics also differ, so do not treat them as interchangeable:
- Liveness: bare
/healthzreturns{"ok":true,"uptime":...}, while prefixed/api/v1/health/livereturns{"alive":true,"uptime":...}. - Readiness: bare
/readyzchecks only DB + Redis, while prefixed/api/v1/health/readyadditionally checks the queue and image provider (returning{"ready":...,"checks":{...}}). The prefixed endpoint can therefore report503while bare/readyzstill reports200.