← WAR ROOM

DEVELOPERS

World War Watcher API — Developer Documentation

Everything on the dashboard is available as JSON from https://api.worldwarwatcher.com. There is no API key, no signup, and no developer account—the API CORS is open (*), responses are cached at the edge, and all content is licensed CC BY-NC 4.0. For commercial use, get in touch.

curl 'https://api.worldwarwatcher.com/api/v1/search?q=hormuz&limit=3'
curl 'https://api.worldwarwatcher.com/api/v1/score'
curl -H 'Accept: text/markdown' https://worldwarwatcher.com/commentary/day-175

ENDPOINTS

All paths are relative to https://api.worldwarwatcher.com. Search syntax, intents, and the citation object are documented in full on the Query API page; this table is the index.

EndpointReturnsRefresh
GET /api/v1/search?q=BM25 full-text search over ~1,500 editorial passages; every result carries a citation object with a stable anchor URL.each deploy
GET /api/v1/search/answer?q=Intent-classified, templated answer (dispatch day, latest dispatch, region bio, etymology, tradition, silences). Never LLM-generated.each deploy
GET /api/v1/search/healthIndex build timestamp and per-surface passage counts.
GET /api/v1/scoreComposite escalation score, alert level, war day, 9-factor breakdown.on each Mazkir merge
GET /api/v1/score/history?days=7Daily score snapshots.daily
GET /api/v1/badge?style=phosphor&metric=scoreEmbeddable SVG badge with the Tanit sigil (`metric=day|score|alert`).15 min cache
GET /api/v1/econ61 tickers across 8 groups with 30-day history, pre-war baseline, and percentage deltas.15 min
GET /api/v1/infra10 cloud services, 3 latency probes, Iran connectivity consensus, battle damage assessment.10 min
GET /api/v1/ordnanceWeapon stockpiles, burn rates, interceptor status, depletion projections.6 h
GET /api/v1/oil-supplyEIA WPSR inventories, SPR fill, refinery utilization, Brent-WTI spread.6 h

Static JSON (timeline, sources, globe geometry, cables, corridor risk) is served from worldwarwatcher.com/data/*.json; see the research page for the full file catalog.

DISCOVERY

RATE LIMITS

60 requests per minute per IP on every public endpoint, enforced at the edge. Every response carries the IETF draft rate-limit policy header; a rejected request adds the current state and a legacy Retry-After.

RateLimit-Policy: "default";q=60;w=60          # on every response
RateLimit: "default";r=0;t=60                  # only on 429
Retry-After: 60                                # only on 429

The limiter reports only pass/fail, so the remaining count is advertised only when it is known to be zero. Responses are cacheable (Cache-Control: public, max-age=300–900); cache them and you will rarely approach the limit.

VERSIONING & DEPRECATION POLICY

  • /api/v1/ is the canonical prefix. The unversioned /api/ paths are permanent aliases of v1 and will not be removed.
  • Additive changes (new fields, new endpoints, new query parameters) ship within v1 without notice; consumers must tolerate unknown fields.
  • Breaking changes—removed or renamed fields, changed semantics—ship only under a new major prefix (/api/v2/). v1 keeps serving.
  • Before any endpoint is retired it emits RFC 9745 Deprecation and Sunset headers plus a Link rel="deprecation" to a migration note, with a sunset date at least 90 days out. The changelog below is updated first.
  • The OpenAPI document's info.version tracks the schema; endpoint paths track the major version.

ERROR MODEL

Every error is RFC 9457 application/problem+json with Cache-Control: no-store. The code member is stable and safe to switch on; error is kept for pre-v1 consumers. Search errors add syntax_help.

{
  "type": "https://worldwarwatcher.com/developers#errors-missing_query",
  "title": "Bad Request",
  "status": 400,
  "detail": "Missing required query parameter q.",
  "instance": "/api/v1/search",
  "code": "missing_query",
  "error": "Missing required query parameter q.",
  "syntax_help": "Terms are ANDed; use \"double quotes\" for exact phrases. …"
}
StatuscodeMeaning
400missing_queryRequired `q` parameter absent or blank.
400query_too_long`q` exceeds 500 characters.
400invalid_surface`surface` is not one of dispatches, regions, library.
400query_parse_failedQuery rejected by the syntax parser (see `syntax_help`).
400fts_parse_failedQuery rejected by FTS5 (see `syntax_help`).
404not_foundNo endpoint at this path; body lists `endpoints` and `docs`.
405method_not_allowedOnly GET (and OPTIONS preflight) is accepted; `Allow` header set.
429rate_limit_exceeded60 requests/minute per IP exceeded; `Retry-After: 60`.
500answer_failedAnswer retrieval failed upstream.
502score_corruptStored score failed validation.
503score_unavailableScore not yet published for this deployment.

MARKDOWN FOR AGENTS

Every HTML page negotiates to Markdown. Send Accept: text/markdown and the response is Content-Type: text/markdown; charset=utf-8 with Vary: Accept; or fetch the twin directly by appending .md (/commentary/day-175.md, /regions/iran.md, /methodology.md). Dispatch twins are the verbatim source Markdown, frontmatter included. A 404 under the Markdown header returns a Markdown body with recovery links.

CLI

wwatcher is a Typer/Rich terminal client (score, timeline <query> over FTS5, ask <question>). It is not yet on PyPI; install from source:

uv tool install "git+https://github.com/tdimino/worldwarwatcher#subdirectory=cli"
wwatcher score
wwatcher timeline "kharg island"

MCP

There is no MCP server yet. The /api/v1/search and /answer endpoints are deterministic and keyless, so a single tool wrapping them is a ten-line adapter; when an official server ships it will be announced here and in llms.txt.

CHANGELOG

  • 2026-08-21/api/v1/ prefix introduced; unversioned paths become permanent aliases. RFC 9457 errors and IETF rate-limit headers on search and score APIs. API root index, /openapi.json, RFC 9727 catalog. Markdown content negotiation site-wide. This page.
  • 2026-07 — Query API (/api/search, /answer) launched over D1/FTS5.
  • 2026-05 — Score API and SVG badge.
  • 2026-03 — Econ, infra, ordnance, and oil-supply Workers with KV-backed caching.