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: None required. Open to all origins (Access-Control-Allow-Origin: *). HTTP Method: GET

Query Parameters

ParameterValuesDescription
compact1Omit per-key details; only return keys with problems

Response Status Codes

HTTP StatusOverall StatusMeaning
200HEALTHYAll checks OK, no warnings
200WARNINGSome keys stale or on-demand keys empty, but no critical failures
503DEGRADED1-3 bootstrap keys empty
503UNHEALTHY4+ bootstrap keys empty
503REDIS_DOWNCould not connect to Redis

Response Body

{
  "status": "HEALTHY | WARNING | DEGRADED | UNHEALTHY | REDIS_DOWN",
  "summary": {
    "total": 57,
    "ok": 52,
    "warn": 5,
    "crit": 0
  },
  "checkedAt": "2026-03-11T14:00:00.000Z",
  "checks": {
    "earthquakes": {
      "status": "OK",
      "records": 142,
      "seedAgeMin": 8,
      "maxStaleMin": 30
    }
  }
}
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:
TierSeverity when emptyDescription
BootstrapCRITSeeded data required at startup. Empty means the dashboard is missing critical data
StandaloneCRIT (seeded) / WARN (on-demand)Populated by seed loops or RPC handlers. On-demand keys are expected to be empty until first request
On-demandWARNPopulated lazily by RPC calls. Empty is normal if nobody has requested the data yet

Per-Key Statuses

StatusSeverityMeaning
OKGreenData present, seed fresh
OK_CASCADEGreenKey empty but a sibling in the cascade group has data (e.g., theater posture fallback chain)
STALE_SEEDWarnData present but seed-meta age exceeds maxStaleMin
EMPTY_ON_DEMANDWarnOn-demand key has no data yet
EMPTYCritBootstrap or standalone key has no data
EMPTY_DATACritKey exists but contains zero records

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

Staleness Thresholds (maxStaleMin)

Selected thresholds from SEED_META:
DomainMax Stale (min)Notes
Market quotes, crypto, sectors30High-frequency relay loops
Earthquakes, unrest, insights30Critical event data
Predictions15Polymarket, fast-moving
Military flights15Near-real-time tracking
Flight delays (FAA)60Airport delay snapshots
Wildfires, climate anomalies120Slower-moving natural events
Cyber threats480APT data updated less frequently
BIS data, World Bank, minerals2880-10080Institutional data, weekly/monthly updates

Example Requests

# Full health check
curl -s https://api.worldmonitor.app/api/health | jq .

# Compact (problems only)
curl -s "https://api.worldmonitor.app/api/health?compact=1" | jq .

# UptimeRobot / monitoring: check HTTP status code
curl -o /dev/null -s -w "%{http_code}" https://api.worldmonitor.app/api/health
# Returns 200 (healthy/warning) or 503 (degraded/unhealthy)

/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

HTTP StatusOverall StatusMeaning
200healthyAll seed loops reporting on time
200warningSome seeds stale (age > 2x interval)
200degradedSome seeds missing entirely
401-Invalid or missing API key
503-Redis unavailable

Response Body

{
  "overall": "healthy | warning | degraded",
  "checkedAt": 1710158400000,
  "seeds": {
    "seismology:earthquakes": {
      "status": "ok",
      "fetchedAt": 1710158100000,
      "recordCount": 142,
      "sourceVersion": null,
      "ageMinutes": 5,
      "stale": false
    },
    "market:stocks": {
      "status": "stale",
      "fetchedAt": 1710150000000,
      "recordCount": 85,
      "sourceVersion": null,
      "ageMinutes": 140,
      "stale": true
    }
  }
}

Staleness Logic

A seed is considered stale when its age exceeds 2x the configured interval. This accounts for normal jitter in cron/relay timing.
DomainInterval (min)Stale After (min)
Predictions, military flights816
Market quotes, earthquakes, unrest1530
ETF flows, stablecoins, chokepoints3060
Service statuses, spending, wildfires60120
Shipping rates, satellites90-120180-240
GPS jamming, displacement360720
Iran events, UCDP210-5040420-10080

Example Request

curl -s https://api.worldmonitor.app/api/seed-health \
  -H "Origin: https://worldmonitor.app" | jq .

Integration with Monitoring Tools

UptimeRobot

Use /api/health as the monitor URL. UptimeRobot checks HTTP status:
  • 200 = up
  • 503 = down
For keyword monitoring, check for "status":"HEALTHY" in the response body.

Custom Alerting

Parse the JSON response to build granular alerts:
# Alert on any critical keys
STATUS=$(curl -s "https://api.worldmonitor.app/api/health?compact=1")
CRIT=$(echo "$STATUS" | jq '.summary.crit')
if [ "$CRIT" -gt 0 ]; then
  echo "CRITICAL: $CRIT data keys empty"
  echo "$STATUS" | jq '.problems'
fi

Differences Between Endpoints

Aspect/api/health/api/seed-health
ScopeData keys + seed metadataSeed metadata only
AuthNone (public)API key or allowed origin
Data fetchedFull Redis values (to count records)Only seed-meta:* keys
HTTP 503Yes (DEGRADED/UNHEALTHY)No (always 200 unless Redis down)
Best forUptime monitoring, dashboard healthDebugging seed loop issues
Response sizeLarger (57+ keys with record counts)Smaller (42 seed domains)