Siinqee Bank unavailable (9 days). Known, ongoing.Status →
links.et

Health / Status API

Two open endpoints for monitors and dashboards: a single-purpose health probe and a structured per-component status snapshot.

Both endpoints are open (no API key required), cached for ~15 s at the edge plus 30 s in-process so a flood of probes never burns through to the underlying checks, and safe to hit from any host (no rate-limit attribution).

GET /api/verify: minimal health

Use when all you need is "is links.et alive". Always returns 200 with a tiny JSON body.

curl https://links.et/api/verify
{ "ok": true, "ts": "2026-06-11T19:23:11.482Z" }

Don't use this to check whether an upstream (telebirr, CBE, …) is healthy; this endpoint only reports on links.et itself.

GET /api/status: structured per-component status

Use when you want to know which upstream is degraded or what response times look like right now.

curl https://links.et/api/status

Response

HTTPWhen
200Overall status is operational or slow
503Overall status is down (at least one component returned a 5xx or timed out)
{
	"ok": true,
	"status": "operational",
	"checkedAt": "2026-06-11T19:23:11.482Z",
	"cached": true,
	"components": [
		{
			"name": "verify-web (this service)",
			"host": "links.et",
			"group": "internal",
			"status": "operational",
			"responseMs": 0,
			"httpStatus": 200,
			"error": null
		},
		{
			"name": "Postgres (auth + API keys)",
			"host": "127.0.0.1:5432",
			"group": "internal",
			"status": "operational",
			"responseMs": 35,
			"httpStatus": null,
			"error": null
		},
		{
			"name": "Telebirr — transactioninfo.ethiotelecom.et",
			"host": "transactioninfo.ethiotelecom.et",
			"group": "upstream",
			"status": "operational",
			"responseMs": 522,
			"httpStatus": 200,
			"error": null
		}
	]
}

Field reference

FieldTypeNotes
okbooleantrue unless overall status is down
statusenumoperational | slow | down; worst across all components
checkedAtISO timestampWhen the underlying probe round was last taken
cachedbooleantrue if the snapshot came from the in-process 30 s cache
components[].namestringHuman label (e.g. "Telebirr — transactioninfo.ethiotelecom.et")
components[].hoststringUpstream host or internal address
components[].groupenuminternal (the links.et service itself) or upstream
components[].statusenumPer-component operational / slow / down
components[].responseMsnumber | nullProbe round-trip time
components[].httpStatusnumber | nullHTTP status the upstream returned (or null for non-HTTP probes like Postgres)
components[].errorstring | nullNetwork or timeout error message when the probe failed

Classification rules (same as the human-readable /status page)

  • down: probe failed or upstream returned HTTP >= 500
  • slow: probe succeeded but took longer than the per-component slow threshold (typically 1.5 s)
  • operational: probe succeeded under threshold

HEAD /api/status: uptime-monitor friendly

Same status code semantics as GET /api/status, no body. Cheapest possible probe; recommended for monitors that only need to react to 200 vs 503.

curl -I https://links.et/api/status
# HTTP/2 200
# cache-control: public, max-age=15, s-maxage=15

Polling cadence

The in-process snapshot refreshes every 30 s and the public response is cache-controlled for 15 s. A polling interval between 30 s and 5 minutes is plenty; anything faster gets you the same cached snapshot, just with extra bandwidth.

On this page