Skip to main content
These endpoints are not part of a domain RPC service — they sit at the root of the API surface and handle platform concerns.

Bootstrap

GET /api/bootstrap

Single round-trip hydration for the dashboard. Returns all bootstrap-registered Redis cache keys unwrapped from their seed envelopes in one response.
  • Auth: browser wm-session cookie, X-WorldMonitor-Key, or the X-Api-Key alias. User-issued keys are validated for current API access.
  • Anonymous weather: ?keys=weatherAlerts is public only when no API key header is sent. If you attach X-WorldMonitor-Key / X-Api-Key, the request is fully validated even for weather — a malformed key returns 401, a key without current API access returns 403. Callers that always send a key must send a valid, entitled key (or omit the header to use the anonymous weather path).
  • Server-to-server: call https://api.worldmonitor.app/api/bootstrap directly with X-WorldMonitor-Key: wm_.... There is no separate gateway host, token exchange, activation step, or IP allow-list requirement for this endpoint.
  • Cache: browser/session responses keep the default tier cache policy: all-keys responses use Cache-Control: public, s-maxage=600, stale-while-revalidate=120, stale-if-error=900 plus fast-tier CDN-Cache-Control; explicit ?tier=fast / ?tier=slow requests use browser max-age=60 / max-age=300 and CDN s-maxage=600 / s-maxage=7200. Key-authenticated responses use Cache-Control: no-store and do not emit CDN cache headers.
  • Rate limit: user API key validation on this endpoint has a fail-closed fixed 60 s per-IP pre-validation limit of 600 attempts, separate from the default API sliding-window limiter.
  • Shape: { "data": { "earthquakes": ..., "outages": ..., "marketQuotes": ... }, "missing": [] } — ~40+ unwrapped seeded-domain payloads nested under data, plus a missing list for cache keys not present in Redis.
Use this on initial page load to avoid 40 parallel RPC calls.

Version

GET /api/version

Returns the latest GitHub Release of koala73/worldmonitor. Used by the desktop app to detect a newer published release and prompt the user to update. It is not the currently-deployed Vercel commit.
Cached public, s-maxage=300, stale-while-revalidate=60, stale-if-error=3600. Returns 502 { "error": "upstream" } or 502 { "error": "fetch_failed" } when the GitHub API is unreachable.

Cache purge

POST /api/cache-purge

Internal. Invalidates Redis cache keys by explicit list or glob patterns.
  • Auth: Authorization: Bearer $RELAY_SHARED_SECRET (timing-safe compared). Anything else returns 401.
  • Body (at least one of keys / patterns required):
  • Limits: up to 20 explicit keys, up to 3 patterns (each must end in *, bare * rejected), up to 200 deletions total, up to 5 SCAN iterations per pattern.
  • Safety: keys with prefixes rl: / __ are always skipped; patterns that would match military:bases:*, conflict:iran-events:*, conflict:ucdp-events:* (durable seeds) are skipped.
  • Non-production: on preview / development deploys, keys are auto-prefixed with {env}:{git-sha}: so purges can’t affect production data.
  • Response:

Health

GET /api/health

Aggregated freshness report for all registered seed keys. Returns HEALTHY, WARNING, DEGRADED, UNHEALTHY, or REDIS_DOWN in the JSON status field. All states except REDIS_DOWN return HTTP 200; REDIS_DOWN returns HTTP 503 because Redis was unreachable and the endpoint could not assess seed state. Responses are not cached (private, no-store, max-age=0 plus CDN-Cache-Control: no-store). Monitor via UptimeRobot / Better Stack with ?compact=1 — alert on any status other than HEALTHY. The full detailed view requires an operator/enterprise API key because it includes canonical cache key names and freshness thresholds.

GET /api/seed-health

Parallel registry for Railway-cron-driven seeders with their own cadence thresholds. Distinct from /api/health — both must be updated when cadence changes. See health endpoints.

POST /api/seed-contract-probe

Internal probe that validates each seed producer’s envelope shape matches its consumers. Returns violations if any consumer reads a field the producer no longer emits.

User preferences

GET /api/user-prefs

POST /api/user-prefs

Per-user dashboard preferences (layout, toggles, filters). Clerk bearer required. Backed by Convex.
  • Idempotency: optional Idempotency-Key supported on POST /api/user-prefs. Retrying the same key with an identical body replays the original preferences response instead of applying the update again.

API key cache invalidation

POST /api/invalidate-user-api-key-cache

Invalidates a user’s entitlement cache after a subscription change (Dodo webhook → Convex → this endpoint). Internal — requires RELAY_SHARED_SECRET.

Geo utilities

GET /api/geo?iso2=US

Returns country metadata: centroid, bbox, capital, ISO codes.

GET /api/reverse-geocode?lat=40.7&lon=-74.0

Reverse geocodes a lat/lon to the nearest country + city using the bundled coordinate dataset.

GET /api/data/city-coords?q=Tokyo

City name → coordinates lookup.

Utilities

GET /api/download?platform=<id>&variant=<id>

Redirects to the matching asset on the latest GitHub release of koala73/worldmonitor. Returns 302 to the asset URL on success, or 302 to releases/latest on any failure (unknown platform, no match, GitHub error). platform (required, exact string): variant (optional): Caches the 302 for 5 minutes (s-maxage=300, stale-while-revalidate=60, stale-if-error=600).

POST /api/leads/v1/submit-contact

Public enterprise contact form. Turnstile-verified, rate-limited per IP. Part of LeadsService.

POST /api/leads/v1/register-interest

Captures email for Pro-waitlist signup. Writes to Convex and sends a confirmation email. Part of LeadsService. Browser callers must pass Turnstile. Desktop callers using source: "desktop-settings" bypass Turnstile only when the request is authenticated with the shared desktop secret:
  • X-WorldMonitor-Desktop-Timestamp: Unix epoch milliseconds, within 5 minutes of server time.
  • X-WorldMonitor-Desktop-Signature: sha256=<hex HMAC-SHA256>.
The HMAC input is <timestamp>\n<canonical JSON>, where canonical JSON contains email, source, appVersion, referredBy, website, and turnstileToken in that order. Configure WM_DESKTOP_SHARED_SECRET on both the desktop sidecar and the cloud API. During rollout, WM_DESKTOP_AUTH_ALLOW_LEGACY=true only accepts unsigned legacy desktop requests while the cloud API has no WM_DESKTOP_SHARED_SECRET configured. Once the cloud secret is set, desktop requests fail closed unless they include a valid signature, still subject to the tighter desktop rate limit.