Skip to main content

/api/health

Primary health endpoint. Checks all Redis-backed data keys and seed freshness metadata in a single pipeline call. Authentication: Compact health (?compact=1) is public for uptime and keyword monitors. Detailed health (/api/health without compact=1) and the operator history view (?history=1) require a valid operator/enterprise API key because they expose canonical Redis key names, record counts, and freshness thresholds. Browser origins must still pass the CORS allowlist in api/_cors.js; requests with no Origin header, such as server-side monitors, are allowed only for compact health unless they include an operator key. Health responses are never cached (Cache-Control: private, no-store, max-age=0 and CDN-Cache-Control: no-store). HTTP Method: GET

Query Parameters

Response Status Codes

The overall health verdict lives in the JSON status field, not the HTTP code. Every state except REDIS_DOWN returns 200 so warn-level seed jitter doesn’t flap HTTP-status monitors (see PR #2699). REDIS_DOWN returns 503 because with Redis unreachable the endpoint can assess nothing, so a plain HTTP probe must see a failure.

Response Body

summary fields: total is one entry per probed key (currently ~194 and growing as panels are added). warn excludes on-demand-empty keys — those are surfaced separately as onDemandWarn so they don’t drive the overall verdict to WARNING. staleContent is a subset of warn (fresh seeder but the upstream feed stopped advancing). Only crit (EMPTY/EMPTY_DATA) drives DEGRADED/UNHEALTHY. With ?compact=1, the checks object is replaced by problems containing only non-OK keys.

Key Classifications

Keys are grouped into three tiers that determine alert severity:

Per-Key Statuses

China Coverage Projection

chinaCoverage projects the hourly Railway summary at health:china-coverage:v1. The evaluator checks each launched China contract for both a fresh producer heartbeat and fresh, substantive China content; a fresh seed cannot hide stale or missing source content. CHINA_DEGRADED is a warning projection for partial or stale coverage, while CHINA_UNAVAILABLE is critical when the summary is invalid or the launched content is unavailable. The final public composition is monitored separately as chinaDecisionSignals. Its canonical payload must contain all six stable groups even when individual groups are explicitly unavailable. Health requires six group records and a seed no older than 60 minutes. Per-source transport details for policy, exchanges, and cross-Strait publishers remain visible only in this authenticated operator view; they are not copied into the public country summary or Pro MCP result. Blocked China contracts remain visible in the audit with their stable reason code but are excluded from the strict launched-entry health count. The launched cross-Strait activity contract audits the durable archive military:cross-strait-activity:v1 independently for producer transport and latest Taiwan MND reporting-window freshness. A fresh seed with a stale official report therefore remains degraded. Japan Joint Staff reviewed observations are regional augmentation and do not satisfy the Taiwan MND content requirement. /api/health separately monitors military:cross-strait-activity-bootstrap:v1; fresh canonical data cannot hide a missing compact UI projection. It also exposes dedicated MND and Japan Joint Staff transport records. Japan Joint Staff alone reports SOURCE_BLOCKED, and only when retained reviewed records exist and one of two evidenced conditions holds. HTTP_403 means the direct request and an upstream response received after a successful proxy CONNECT both returned HTTP 403 — the publisher itself refused both paths. PROXY_TARGET_FORBIDDEN means the direct request returned HTTP 403 and the proxy refused CONNECT for the target while a control CONNECT to a different contracted host succeeded in the same run through the same credentials — the proxy provider forbids this destination specifically, so no configured transport path exists. An uncorroborated CONNECT refusal, a control tunnel that also fails, PROXY_AUTH_FAILED, stale metadata, a missing source record, or any other source using the blocked state still fail closed through the existing STALE_SEED, EMPTY, or SEED_ERROR statuses. The distinction matters operationally: PROXY_TARGET_FORBIDDEN is durable and needs a different egress to change, whereas a bare CONNECT refusal is a proxy fault to remediate. Other current fetch failures report SEED_ERROR while the last-good archive remains available. The bundle freshness gate advances only after the archive, projection, and both source-health records publish successfully. The public bootstrap retains the bounded reason codes used for disclosure but omits proxy response diagnostics; full sanitized diagnostics remain in the authenticated operator source record. Operators can obtain the same sanitized, read-only audit with node scripts/audit-china-coverage.mjs --json; add --strict to return a nonzero exit code unless every launched entry is healthy. The audit reads only the compact Redis contracts and emits status, age, and reason-code summaries— never credentials or raw upstream payloads.

Cascade Groups

Some keys use fallback chains. If any sibling has data, empty siblings report OK_CASCADE:
  • Theater Posture: theaterPostureLive -> theaterPosture (stale) -> theaterPostureBackup
  • Military Flights: militaryFlights -> militaryFlightsStale
  • Displacement: displacement (current UTC year) -> displacementPrev (prior year, covers the Jan-1 window before the new-year seed runs)
riskScores is intentionally stricter than a raw feed heartbeat. Its recordCount is realtime signal-density coverage: the count of score-relevant Tier-1 conflict, news, and cyber signal families present during the CII refresh. The conflict family is satisfied by either the ACLED path or the UCDP event feed, matching the CII v8 scorer. When those feeds are reachable but quiet, riskScores can still report COVERAGE_PARTIAL; underlying feed freshness is tracked by the source-specific health entries where those feeds publish seed metadata. portwatchPortActivity also uses minRecordCount. A fresh seed-meta:supply_chain:portwatch-ports record below 174 countries reports COVERAGE_PARTIAL instead of OK; partial runs may still refresh per-country PortWatch cache entries, but the canonical country list and healthy seed-meta signal do not advance until full 174-country coverage returns. predictionMarkets also requires at least one published market in each geopolitical, tech, and finance pool. Its seed metadata publishes poolCounts; missing, malformed, or under-floor counts report COVERAGE_PARTIAL even when the aggregate market count is healthy.

Staleness Thresholds (maxStaleMin)

Selected thresholds from SEED_META:
These are illustrative; SEED_META in api/health.js is the source of truth and each entry documents its own cadence rationale.

Example Requests

/api/seed-health

Focused endpoint for seed loop freshness. Checks only seed-meta:* keys without fetching actual data payloads. Authentication: Requires valid API key or allowed origin. HTTP Method: GET

Response Status Codes

Response Body

Staleness Logic

A seed is considered stale when its age exceeds 2x the configured interval. This accounts for normal jitter in cron/relay timing. Seeds below an aggregate minRecordCount report coverage_partial and stale: true. Seeds below a subgroup floor such as prediction-market minPoolCounts also report coverage_partial, but retain stale: false while their producer heartbeat remains fresh so freshness and coverage stay distinct. Consumers: treat status and overall as authoritative for coverage. Do not rely on stale alone — pool shortfalls keep stale: false by design. When either coverage floor fails, the entry also sets coveragePartial: true so clients that only inspect booleans still see the shortfall.

History ingestion (intel-history:*)

Domains prefixed intel-history: do not describe a seeder’s canonical publish. They track whether that collector’s post-publish append to the historical intelligence store is still landing: The append is fail-open by design — the canonical publish has already committed when it runs, so a failure must never fail the run. That means the collector’s own entry (conflict:acled-intel, …) stays ok while history silently stops accumulating. These entries are the separate signal:
  • fetchedAt is the last healthy append, never the last attempt. A run that reached the relay advances it; a run that delivered nothing (every chunk rejected, or the wall-clock budget died before the first request) does not. So a broken relay freezes it and the entry goes stale on the ordinary 2x-interval rule.
  • status: "error" means the append failed on two consecutive runs — or, on the very first tick, that a relay credential present during an earlier successful append has since been removed.
  • lastErrorCode names the cause when there is one: http_401, budget_exhausted, all_chunks_failed, config_removed, or a clamped error-class name. Absent when the ingest has never failed.
  • status: "not_configured" means this deployment has never had relay credentials. It is visible but never an alarm — no operator action clears it except provisioning the relay. Losing credentials after a successful append is not this state; it reports error with lastErrorCode: "config_removed".
  • recordCount is the volume the relay accepted on the last successful append. Zero is valid: a run whose records were all deduped still proves the pipeline works.
The richer per-run detail — lastErrorReason, consecutiveFailures, missingConfig, and the inserted/deduped/abandoned counts — is not returned by either endpoint. It lives in the Redis record intel-history:ingest-health:<domain>:<resource>:v1, which the endpoints project from. A stale or error here alongside an ok collector means canonical data is fine and the history store is the thing to investigate.

Example Request

Integration with Monitoring Tools

UptimeRobot

Use /api/health?compact=1 as the public monitor URL. The HTTP status code only distinguishes a total Redis outage from everything else:
  • 503 = REDIS_DOWN (Redis unreachable — a true hard outage)
  • 200 = every other state, including DEGRADED and UNHEALTHY
So an HTTP-status-only monitor catches a full backend outage but not degraded/unhealthy data. For those, add a keyword monitor. Point the keyword monitor at https://api.worldmonitor.app/api/health?compact=1 and alert when the compact token "status":"HEALTHY" (no space after the colon) is absent from the response body. Compact mode serializes with no indentation, so this exact token is stable regardless of formatting.
The bare /api/health URL is now an operator view and returns 401 without an API key. Public monitoring should always use ?compact=1.

Custom Alerting

Parse the JSON response to build granular alerts:

Differences Between Endpoints