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
/api/v1/signalsPaginated stream of intelligence signals, ordered by threat score.
| layers | string | Comma-separated threat layers (military,cyber,economic,disaster,political,criminal,health,supply_chain) |
| min_score | number | Minimum significance score 0β10 (default 0) |
| region | string | Region name: "Europe", "Middle East", "South Asia", "Asia-Pacific", "Sub-Saharan Africa", "North America", "Latin America" |
| country | string | ISO-2 country code (e.g. UA, IR, IN) |
| city | string | City name partial match (e.g. Kyiv, Tehran) |
| start | ISO8601 | Filter by published_at β₯ start |
| end | ISO8601 | Filter by published_at β€ end |
| search | string | Full-text search (websearch syntax supports AND/OR/phrase) |
| valence | string | crisis | update | resolution β filter by signal outcome classification |
| limit | integer | Max 100 (default 50) |
| offset | integer | Pagination offset (default 0) |
| bbox | string | Bounding 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) |
| anomaly | boolean | Set to true to return only anomalous signals (statistical spikes above baseline) |
| format | string | json (default) | csv β response format. CSV includes all fields as RFC 4180. |
/api/v1/signals/:idFull detail for a single signal including entity extraction and source metadata.
/api/v1/snapshotsThreat composite scores aggregated by region and layer over time. Useful for trend analysis.
| region | string | Filter by region name (e.g. "Middle East") |
| layer | string | Filter by threat layer |
| start | ISO8601 | Start of time window |
| end | ISO8601 | End of time window |
| limit | integer | Max 500 (default 100) |
/api/v1/sourcesList active intelligence sources with metadata and coverage information.
| tier | string | core | community | discovered |
| region | string | Filter by region coverage |
| layer | string | Filter by threat layer coverage |
/api/v1/trendingTop 8 threat layers and countries by activity spike ratio (current 6h vs 7-day baseline). Cached 10 min.
/api/v1/compound-crisesCountries where 2+ distinct threat layers have converged above the severity threshold. Cached 5 min.
| window_type | string | acute (7-day) | chronic (30-day). Omit for both. |
| min_score | number | Minimum composite severity score (default 0) |
| limit | integer | Max 100 (default 50) |
/api/v1/feedRSS 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.
| format | string | rss (default) | atom | json β output format |
| layers | string | Comma-separated threat layers |
| country | string | ISO-2 country code |
| region | string | Region name |
| valence | string | crisis | update | resolution β filter by signal valence |
| min_score | number | Minimum significance score 0β10 |
| search | string | Keyword filter |
| limit | integer | Max 50 (default 20) |
/api/v1/entityReturns signals mentioning a specific named entity (person, organisation, or location), with layer breakdown, 30-day timeline, and co-mentioned entity graph.
| name | string | Entity name to search for (required, min 2 chars) |
| days | integer | Lookback window in days (default 30, max 365) |
| limit | integer | Max signals to return (default 50, max 100) |
| offset | integer | Pagination offset (default 0) |
/api/v1/keysList all API keys associated with your email account. Returns prefix, name, tier, usage, and last-used time. Never returns the raw key value.
/api/v1/keys/:idRevoke an API key by its UUID. Must authenticate with a different active key from the same email account. Returns 204 No Content.
/api/v1/webhooksList all webhooks registered to your API key.
/api/v1/webhooksRegister a new outbound webhook. OpenWatch will POST matching signals to your URL as JSON (HMAC-SHA256 signed if secret provided). Max 5 per key.
| url | string | HTTPS endpoint to receive signal payloads (required) |
| name | string | Human-readable label for this webhook |
| secret | string | Signing secret (β₯16 chars) β HMAC-SHA256 sent as X-OpenWatch-Signature-256 header |
| layers | string[] | Threat layers to match (omit for all) |
| min_score | number | Minimum significance score 0β10 (omit for all) |
| country_codes | string[] | ISO-2 codes to match, e.g. ["UA","RU"] (omit for all) |
| valence | string | crisis | update | resolution (omit for all) |
/api/v1/webhooks/:idUpdate a webhook β any combination of url, name, layers, min_score, country_codes, valence, active.
/api/v1/webhooks/:idDelete a webhook. Returns 204 No Content.
/api/v1/briefAI-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.
/api/v1/clustersNarrative signal clusters β thematically related signals grouped by threat layer and scored by local significance. No authentication required.
| days | integer | Lookback window in days (default 3, max 30) |
| min_signals | integer | Minimum signals per cluster (default 2) |
| threat_layer | string | Filter to a single threat layer |
| country_code | string | ISO-2 country code filter |
/api/v1/statsPublic platform statistics β signal volumes, source counts, language coverage, and threat layer breakdown. No authentication required. Cached for 10 minutes at the edge.
/api/exportCSV 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.
| layer | string | Filter by threat_layer (military, cyber, economic, β¦) |
| country | string | ISO-2 country code in country_codes array |
| valence | string | crisis | update | resolution |
| minScore | number | Minimum significance_score (default 0) |
| format | string | csv (default) | json |
| limit | integer | Max 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>Get Your API Key
Manage API keys
View all keys on your account, see usage, and revoke keys. Enter any existing key to load your account.
Manage webhooks
View, pause, and delete your registered webhook endpoints. Requires your API key.
API Status
Real-time collector health and endpoint status.
Intelligence Sources
Browse the full source catalog: 1,200+ feeds, trust scores, language coverage, and collector health.