---
title: "Latest background health probe results"
method: GET
path: "/v1/health/probes"
tags: ["Health"]
---

# Latest background health probe results

`GET /v1/health/probes`

## Request

- Base URL: `https://api.registrum.co.uk`
- URL: `https://api.registrum.co.uk/v1/health/probes`
- Auth: none required

Return the latest result from each background health probe.

Probes run automatically on a schedule. The headline ones:

- **api_self_check** (every 5m) - calls `GET /v1/company/{reference}` on the
  public hostname, with a real API key, and requires all three of: HTTP 200,
  the right company in the body, and a response inside a 5-second budget.
  This is the only probe that asks the customer's own question. A 200 alone
  is not a pass: during the 2026-08-13 outage `/v1/health` answered 200 at
  12-15 seconds while ~90% of real traffic was 499/502.

- **event_loop_lag** (every 60s) - measures how long the API's event loop
  takes to reschedule a sleeping task. The API runs a single event loop, so
  this delay is paid by *every* concurrent request, including this one.
  Unlike per-request `duration_ms`, it sees work that blocks the loop after
  a response is sent or inside a background job (CH-Api#110).
  `max_lag_ms` under 250 is healthy; over 1000 means requests are queueing.

- **ch_api_profile** (every 6h) - fetches a real company profile and verifies
  the response fields our code depends on are still present and correctly typed.
  Detects silent CH API schema changes before they break customers.

- **rate_limit** (every 1h) - checks the `X-Ratelimit-Remain` header and
  alerts when the budget drops below 20% of the 600-per-5-minutes allowance.

- **document_api** (every 12h) - fetches filing history and hits the CH
  Document API to confirm iXBRL downloads are still accessible.

Possible statuses:
- **pass** - probe succeeded with no issues
- **degraded** - probe completed but detected a warning condition
- **fail** - probe failed (connection error, unexpected HTTP status, missing fields)

**Note:** Results are stored in memory. After a server restart, probes run once
immediately at startup and then on their normal schedule.

No authentication required. Safe to poll at low frequency (once per minute max).

**Upstream usage:** 0 - reads from memory only. No upstream calls made.

## Response `200`

Probe results returned (may be empty if probes haven't run yet)

- ProbesResponse: Latest results from all background health probes.
  - `probes` ProbeResult[]: One entry per probe, ordered by name
    - `probe_name` string, required: Probe identifier: 'event_loop_lag', 'ch_api_profile', 'rate_limit', or 'document_api'
    - `status` string, required: 'pass', 'degraded', or 'fail'
    - `response_time_ms` number, nullable: How long the probe took in milliseconds
    - `details` object: Probe-specific result data or error message
    - `checked_at` string, nullable: ISO 8601 timestamp of when this probe last ran
    - `age_seconds` number, nullable: Seconds since this probe last ran, or null if its timestamp is unreadable
    - `stale` boolean: True if this result is too old to describe the present - the probe has stopped running, and its last result must not be read as current
    - `source` string, nullable: Where this result was read from: 'local' (this process's own memory) or 'pulse' (the shared probe_pulse table, written by whichever process ran the probe - normally the worker)
  - `overall` string, required: 'pass' if all probes passed, 'degraded' if any degraded or stale, 'fail' if any failed
  - `pulse_error` string, nullable: Set when the shared probe_pulse table could not be read, meaning probes run by other processes are missing from this list rather than absent

---

[API](https://skmtc.dev/registrum/apis/registrum-api.md) · [All operations](https://skmtc.dev/registrum/apis/registrum-api/llms.txt) · [OpenAPI document](https://skmtc.dev/registrum/apis/registrum-api/revisions/2bf0ecf7cc02?raw)
