Skip to main content

Health Endpoints

Three endpoints report whether the API is up, whether it is ready to take traffic, and whether the process is alive.

They are not under /api/v1, and they take no API key

The health paths are served at the root of the API, outside /api/v1, and they are the only paths excluded from the API-key security scheme. Sending a key is harmless; omitting one changes nothing. Because of that, a 200 from any of them says nothing at all about whether your credentials are valid โ€” use an authenticated endpoint for that.

Which one do I call?โ€‹

QuestionEndpointNotes
Is the API up, and which environment is this?GET /healthReports environment; the fastest way to tell test from production
Should this instance receive traffic?GET /health/ready200 when ready, 503 when not. Wire load balancers and uptime monitors here
Is the process alive?GET /health/liveAlways 200. Wire container orchestrator liveness probes here

GET /healthโ€‹

Basic health check. Unauthenticated.

curl -X GET https://app.goroute.ai/peppol-api/health
{
"status": "healthy",
"version": "1.0.0",
"environment": "production",
"timestamp": "2026-08-06T06:09:57.050723"
}
FieldMeaning
status"healthy"
versionAPI version
environmentWhich environment this base URL and deployment resolve to
timestampServer time the response was generated

Use environment to confirm which environment you are talking to before you go live. It is the field the Environments page tells you to check.

GET /health/readyโ€‹

Readiness. Answers 200 when ready and 503 when not ready โ€” a probe that always returned 200 could never take a half-initialised instance out of rotation. An instance that can serve but has something an operator should fix answers 200 with "status": "degraded".

curl -X GET https://app.goroute.ai/peppol-api/health/ready

Production answered this on 5 November 2026:

{
"status": "ready",
"version": "1.0.0",
"environment": "production",
"checks": {
"database": "connected",
"redis": "connected"
},
"cell_invariants": [],
"rule_files": {
"ae_tdd": {"status": "ok"},
"de_kosit_scenarios": {"status": "ok"},
"edec_mls_outbound": {"status": "ok"},
"fr_br_fr": {"status": "ok"},
"fr_cdar": {"status": "ok"},
"fr_extended_ctc_fr": {"status": "ok"},
"fr_facturx_basicwl": {"status": "ok"},
"fr_facturx_en16931": {"status": "ok"},
"fr_facturx_extended": {"status": "ok"},
"pint_ae_c2_outbound": {"status": "ok"},
"pint_ae_c3_inbound": {"status": "ok"},
"pint_om_c3_inbound": {"status": "ok"},
"zatca_sdk_3_4_8": {"status": "ok"}
},
"timestamp": "2026-11-05T06:31:53.677183"
}
FieldMeaning
status"ready"; "degraded" when the database is connected but cell_invariants is not empty or a rule set in rule_files is not "ok" (still HTTP 200); "not_ready" when the database check failed (HTTP 503)
versionAPI version
environmentWhich environment this deployment resolves to
checks.database"connected", or an error string when the database check failed
checks.redis"connected", "not_checked", or an error string
cell_invariantsA list of findings, each {"check": "<name>", "detail": "<what is wrong and what to do>"}. Empty when there is nothing to report
rule_filesOne entry per rule set the validators read, keyed by its name: {"status": "ok"}, {"status": "missing", "missing": [...]} naming the files the image lacks, or {"status": "unreadable", "detail": "..."}. If the list of rule sets itself cannot be read, the map holds a single _manifest entry with "status": "unreadable"
timestampServer time the response was generated

Findings in cell_invariantsโ€‹

On GoRoute's shared API the list is usually empty. It can hold:

  • mls_core_identity_missing or edec_mls_rules_missing, when the eDEC MLS service is switched on and not set up completely;
  • shipping_credential_refused, on a service where GoRoute Shipping is switched on, when a carrier refused that service's partner key at the latest check. The check runs shortly after the service starts and then daily. Only the instance running GoRoute's scheduled jobs reports this finding, so one answer can show it and the next not. It means GoRoute must correct the key: until then, no customer can connect that carrier or ship with it.

A dedicated cell (a separate GoRoute installation for one operator) can also report:

  • message_id_domain_default, notify_addresses_platform, cell_brand_default, cell_brand_incomplete and cell_brand_platform_value: a GoRoute default the cell's operator was meant to replace;
  • codelists_empty and codelists_unreadable: the Peppol code lists are not loaded or cannot be read;
  • org_hierarchy_path_null and org_hierarchy_path_unreadable: organisations the operator console cannot list.

Each finding's detail says what to fix.

What to alert onโ€‹

  • HTTP 503 ("status": "not_ready"): take the instance out of rotation. This is what a load balancer or readiness probe should act on.
  • "status": "degraded": an operator should look at cell_invariants and rule_files. The instance keeps serving. A monitor that alerts on any status other than "ready" fires on it; one that watches the HTTP code alone does not.
Redis is advisory; only the database gates readiness

A Redis failure degrades rate limiting but does not make an instance unready. checks.redis can therefore report an error string while the endpoint still answers 200 with "status": "ready". Do not alert on checks.redis alone, and do not treat a 200 as proof that Redis is healthy. Readiness is decided by checks.database and nothing else: it alone chooses between 200 and 503.

Behaviour change

This endpoint previously answered 200 in every case, including when the database check failed. It now answers 503 when it is not ready. If you wired a load balancer, an uptime monitor or an orchestrator readiness probe against the old behaviour and treated any response as healthy, revisit it โ€” instances will now be pulled from rotation when the database check fails, which is the intended behaviour.

GET /health/liveโ€‹

Liveness. Always 200.

curl -X GET https://app.goroute.ai/peppol-api/health/live
{
"status": "alive",
"timestamp": "2026-08-06T06:09:20.524903"
}

It deliberately runs no dependency checks: reaching the handler proves the process is serving. Failing a liveness probe because a dependency is merely not ready yet would restart-loop otherwise-healthy instances, and that judgement belongs to /health/ready.

ConsumerEndpointTreat as failure when
Load balancer target group/health/readynon-200
Uptime / status monitoring/health/readynon-200
Container orchestrator liveness probe/health/livenon-200
Environment confirmation in a deploy script/healthenvironment is not what you expected
  • Environments โ€” confirming test versus production
  • First API Call โ€” where /health fits in the first few requests
  • Support โ€” diagnosing an authentication problem, which these endpoints cannot do for you