Developer API

Programmatic access to the global intelligence signal stream. Free tier: 100 req/hour. All responses are JSON.

Total signals

β€”

loading…

Active sources

β€”

loading…

Countries covered

β€”

loading…

Anomalies / 7d

β€”

loading…

Authentication

# Pass your key in either header:

X-Api-Key: osk_your_key_here

# or

Authorization: Bearer osk_your_key_here

# Rate-limit headers returned on every authenticated response:

X-RateLimit-Limit: 100

X-RateLimit-Remaining: 94

X-RateLimit-Reset: 1746716400 # Unix epoch of next window reset

X-RateLimit-Tier: free

Rate Limits

OpenWatch enforces two rate-limit layers. Both surface standard X-RateLimit-* headers on every response, and both return 429 Too Many Requests with Retry-After when exceeded.

Unauthenticated (per IP)

60 req / min

Applies to public endpoints like /api/v1/stats, /api/v1/clusters, /api/v1/freshness, /api/v1/health, /api/v1/docs. Sliding 60-second window keyed on client IP.

Authenticated (per API key)

100 req / hour Β· free

Rolling hourly window keyed on your API key. Pro tier raises this to 2,000 req/hour. Higher limits available on request.

# Headers on a rate-limited (429) response:

X-RateLimit-Limit: 60

X-RateLimit-Remaining: 0

X-RateLimit-Reset: 1746716400

Retry-After: 60 # seconds until window resets

Need higher throughput? Manage keys or contact us for a Pro key β€” paid tiers also bypass the per-IP cap once authenticated.

Endpoints

GET/api/v1/signals

Paginated stream of intelligence signals, ordered by threat score.

layersstringComma-separated threat layers (military,cyber,economic,disaster,political,criminal,health,supply_chain)
min_scorenumberMinimum significance score 0–10 (default 0)
regionstringRegion name: "Europe", "Middle East", "South Asia", "Asia-Pacific", "Sub-Saharan Africa", "North America", "Latin America"
countrystringISO-2 country code (e.g. UA, IR, IN)
citystringCity name partial match (e.g. Kyiv, Tehran)
startISO8601Filter by published_at β‰₯ start
endISO8601Filter by published_at ≀ end
searchstringFull-text search (websearch syntax supports AND/OR/phrase)
valencestringcrisis | update | resolution β€” filter by signal outcome classification
limitintegerMax 100 (default 50)
offsetintegerPagination offset (default 0)
bboxstringBounding box geo filter: minLat,minLng,maxLat,maxLng β€” returns only signals with coordinates within the box (e.g. 48.0,22.0,52.0,40.0 for eastern Europe)
anomalybooleanSet to true to return only anomalous signals (statistical spikes above baseline)
formatstringjson (default) | csv β€” response format. CSV includes all fields as RFC 4180.
GET/api/v1/signals/:id

Full detail for a single signal including entity extraction and source metadata.

GET/api/v1/snapshots

Threat composite scores aggregated by region and layer over time. Useful for trend analysis.

regionstringFilter by region name (e.g. "Middle East")
layerstringFilter by threat layer
startISO8601Start of time window
endISO8601End of time window
limitintegerMax 500 (default 100)
GET/api/v1/sources

List active intelligence sources with metadata and coverage information.

tierstringcore | community | discovered
regionstringFilter by region coverage
layerstringFilter by threat layer coverage
GET/api/v1/trending

Top 8 threat layers and countries by activity spike ratio (current 6h vs 7-day baseline). Cached 10 min.

GET/api/v1/compound-crises

Countries where 2+ distinct threat layers have converged above the severity threshold. Cached 5 min.

window_typestringacute (7-day) | chronic (30-day). Omit for both.
min_scorenumberMinimum composite severity score (default 0)
limitintegerMax 100 (default 50)
GET/api/v1/feed

RSS 2.0 / Atom / JSON Feed of intelligence signals for use in RSS readers, dashboards, or webhook pipelines. Supports the same filters as /api/v1/signals.

formatstringrss (default) | atom | json β€” output format
layersstringComma-separated threat layers
countrystringISO-2 country code
regionstringRegion name
valencestringcrisis | update | resolution β€” filter by signal valence
min_scorenumberMinimum significance score 0–10
searchstringKeyword filter
limitintegerMax 50 (default 20)
GET/api/v1/entity

Returns signals mentioning a specific named entity (person, organisation, or location), with layer breakdown, 30-day timeline, and co-mentioned entity graph.

namestringEntity name to search for (required, min 2 chars)
daysintegerLookback window in days (default 30, max 365)
limitintegerMax signals to return (default 50, max 100)
offsetintegerPagination offset (default 0)
GET/api/v1/keys

List all API keys associated with your email account. Returns prefix, name, tier, usage, and last-used time. Never returns the raw key value.

DELETE/api/v1/keys/:id

Revoke an API key by its UUID. Must authenticate with a different active key from the same email account. Returns 204 No Content.

GET/api/v1/webhooks

List all webhooks registered to your API key.

POST/api/v1/webhooks

Register a new outbound webhook. OpenWatch will POST matching signals to your URL as JSON (HMAC-SHA256 signed if secret provided). Max 5 per key.

urlstringHTTPS endpoint to receive signal payloads (required)
namestringHuman-readable label for this webhook
secretstringSigning secret (β‰₯16 chars) β€” HMAC-SHA256 sent as X-OpenWatch-Signature-256 header
layersstring[]Threat layers to match (omit for all)
min_scorenumberMinimum significance score 0–10 (omit for all)
country_codesstring[]ISO-2 codes to match, e.g. ["UA","RU"] (omit for all)
valencestringcrisis | update | resolution (omit for all)
POST/api/v1/webhooks/:id

Update a webhook β€” any combination of url, name, layers, min_score, country_codes, valence, active.

DELETE/api/v1/webhooks/:id

Delete a webhook. Returns 204 No Content.

GET/api/v1/brief

AI-synthesized Watch Brief: headline, executive summary, active theaters, emerging threats, and key entities from the past 4 hours. Falls back to heuristic summary when AI synthesis is unavailable. Cached 15 min.

GET/api/v1/clusters

Narrative signal clusters β€” thematically related signals grouped by threat layer and scored by local significance. No authentication required.

daysintegerLookback window in days (default 3, max 30)
min_signalsintegerMinimum signals per cluster (default 2)
threat_layerstringFilter to a single threat layer
country_codestringISO-2 country code filter
GET/api/v1/stats

Public platform statistics β€” signal volumes, source counts, language coverage, and threat layer breakdown. No authentication required. Cached for 10 minutes at the edge.

GET/api/export

CSV or JSON export of filtered signals β€” convenience endpoint for spreadsheet / model input. No authentication required (subject to the 60 req/min IP rate limit). Capped at 1,000 rows.

layerstringFilter by threat_layer (military, cyber, economic, …)
countrystringISO-2 country code in country_codes array
valencestringcrisis | update | resolution
minScorenumberMinimum significance_score (default 0)
formatstringcsv (default) | json
limitintegerMax rows, capped at 1000 (default 200)

Quick Examples

# High-severity military signals

curl -H "X-Api-Key: osk_your_key" "https://openwatch.io/api/v1/signals?layers=military&min_score=7&limit=10"

# RSS feed β€” Ukraine conflict signals for your RSS reader

curl -H "X-Api-Key: osk_your_key" "https://openwatch.io/api/v1/feed?country=UA&layers=military,political"

# JSON Feed format for webhooks / dashboards

curl -H "X-Api-Key: osk_your_key" "https://openwatch.io/api/v1/feed?format=json&layers=cyber&min_score=6"

# CSV export β€” economic signals for spreadsheet / model input

curl -H "X-Api-Key: osk_your_key" "https://openwatch.io/api/v1/signals?layers=economic&format=csv&limit=100" -o signals.csv

Outbound Webhooks

Register HTTPS endpoints to receive matching signals β€” no polling required. OpenWatch POSTs a batched JSON payload to your URL on a 5-minute cadence whenever new matching signals have been ingested since your last delivery. Optionally sign payloads with HMAC-SHA256 for authenticity verification.

// Example webhook payload (POST application/json)

{
  "webhook_id": "3fa85f64-...",
  "fired_at": "2026-05-09T14:30:00+00:00",
  "signal_count": 2,
  "signals": [
    {
      "id": "uuid",
      "threat_layer": "military",
      "significance_score": 8.4,
      "signal_valence": "crisis",
      "content_display": "...",
      "country_codes": ["UA"],
      "published_at": "2026-05-09T14:23:00+00:00",
      "collected_at": "2026-05-09T14:24:11+00:00",
      "is_anomaly": false,
      "source_url": "https://..."
    },
    { "..." }
  ]
}

# Verify HMAC-SHA256 signature (Python / Flask)

import hmac, hashlib

def verify(body: bytes, secret: str, signature: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

# Header name: X-OpenWatch-Signature-256
sig = request.headers.get("X-OpenWatch-Signature-256", "")
ok  = verify(request.get_data(), "your_signing_secret", sig)

# Register a webhook β€” military signals in Ukraine, severity β‰₯ 7

curl -X POST https://openwatch.io/api/v1/webhooks \
  -H "X-Api-Key: osk_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url":    "https://your-server.example.com/openwatch-hook",
    "name":   "Ukraine Military Alerts",
    "secret": "your_signing_secret_32chars+",
    "layers":        ["military", "political"],
    "country_codes": ["UA"],
    "min_score":     7
  }'

Embed Widget

Add a live OpenWatch signal feed to any website or dashboard using a single <iframe>. Supports layer, country, and theme filters.

<iframe src="https://openwatch.io/embed?layers=military,cyber&hours=24&theme=dark" width="320" height="480" frameborder="0"></iframe>
Open embed configurator β†’

Get Your API Key

Free tier: 100 requests/hour. No credit card required.

Manage API keys

View all keys on your account, see usage, and revoke keys. Enter any existing key to load your account.

Manage β†’

Manage webhooks

View, pause, and delete your registered webhook endpoints. Requires your API key.

Manage β†’

API Status

Real-time collector health and endpoint status.

Status β†’

Intelligence Sources

Browse the full source catalog: 1,200+ feeds, trust scores, language coverage, and collector health.

Browse β†’
vΒ·5e5c918