Quick Start
Get up and running with the POLYCRISIS API in three steps.
Get your API key
Create an account from the dashboard, then mint keys in your account settings. Keys are prefixed pk_. Treat them like passwords — don’t embed them in client-side JavaScript.
Make your first call
Hit the /v1/crises endpoint to discover all tracked crisis theaters and their current status.
Explore endpoints
Use /v1/events for geolocated data, /v1/connections for cross-crisis links, /v1/scenarios for probability analysis, or /v1/signals for composite alerts.
# Discover all crises curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/crises" # Get Iran military events curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/events?crisis=iran&type=military&limit=5"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} # Discover all crises crises = requests.get( "https://polycrisis.world/api/v1/crises", headers=headers ).json() # Get Iran military events events = requests.get( "https://polycrisis.world/api/v1/events", headers=headers, params={"crisis": "iran", "type": "military", "limit": 5} ).json() for event in events["events"]: print(f"{event['event_type']}: {event['title']}")
5,000 req/day at 60 req/min. See Rate Limits for details.
Authentication
All API requests require a Bearer token in the Authorization header. API keys are prefixed pk_. You can generate keys from your dashboard after creating an account. Treat keys like passwords — never commit them to source control or embed them in client-side code.
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ https://polycrisis.world/api/v1/events
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} response = requests.get( "https://polycrisis.world/api/v1/events", headers=headers ) data = response.json()
Include this header with every request. Requests without a valid key receive a 401 Unauthorized response. Keys are tied to a pricing tier that determines rate limits and endpoint access.
Base URL
All API endpoints are served from a single base URL:
https://polycrisis.world/api/v1/
All requests must use HTTPS. HTTP requests will be redirected. API versioning is included in the path — the current version is v1.
Response Format
Successful responses are flat JSON objects whose top-level keys are endpoint-specific. There is no envelope — the requested payload is the response body. Endpoints that paginate include a meta object alongside their primary key (e.g. events + meta for /events); endpoints that don't paginate omit it. Rate-limit information is delivered via response headers (see Rate Limits below), not in the body.
Example: /v1/events
{
"events": [
{ "id": "evt_12345", "crisis": "iran", "event_type": "military", /* ... */ }
],
"meta": {
"total": 1234,
"returned": 100,
"offset": 0,
"limit": 100
}
}
Example: /v1/crises
{
"crises": [
{ "id": "iran", "name": "Iran", /* ... */ }
],
"last_updated": "2026-04-07T15:30:00Z"
}
Error responses return a single error field with a human-readable string. HTTP status codes carry the machine-readable signal — check the status before reading the body.
{
"error": "Rate limit exceeded",
"limit": 15,
"plan": "sandbox",
"retry_after": 60
}
Rate Limits
Rate limits are enforced per API key. The window depends on which key you use: the public sandbox key uses a 60-second sliding window per IP, while paid keys use a daily quota that resets at UTC midnight. Every response includes rate-limit headers so you can track your usage programmatically.
Response Headers
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests allowed in the active window for your tier. |
| X-RateLimit-Remaining | Requests remaining in the current window. |
| X-RateLimit-Reset | Unix timestamp (seconds since epoch) when the active window resets. For sandbox this is roughly now+60s; for paid it is the next UTC midnight. |
| Retry-After | Set on 429 responses only. Number of seconds to wait before retrying. |
Tier Limits
| Tier | Quota | Window | Notes |
|---|---|---|---|
| Developer ($79/mo) | 5,000 | per day | Full /api/v1/: events, scenarios, correlations, markets, signals, analogs, patterns. Webhooks, SSE streaming. Unlimited keys. 60 req/min. |
When you exceed your rate limit, the API returns 429 Too Many Requests. The Retry-After header tells you how many seconds to wait; the X-RateLimit-Reset header gives an absolute timestamp. Always honor whichever is more conservative.
Errors
The API uses standard HTTP status codes. The status code is the canonical machine-readable signal — check it before parsing the body. Error response bodies are flat JSON objects with an error string and, depending on the error, additional context fields (limit, plan, retry_after, valid, etc.).
| Status | When | How to recover |
|---|---|---|
| 400 | Missing required query parameter, invalid value, or malformed request body. | Read the error field for the specific issue. Fix and retry. |
| 401 | Missing or invalid Authorization: Bearer header. | Provide a valid API key from your dashboard. |
| 404 | Unknown endpoint or resource not found. | Check the URL against this docs page or openapi.json. |
| 429 | Rate limit exceeded for your key. | Wait for the time in Retry-After or X-RateLimit-Reset, then retry. |
| 500 | Server-side error processing the request. | Retry with exponential backoff. If persistent, contact support. |
| 503 | Database temporarily unavailable. | Retry after a few seconds. |
Examples
400 Bad Request — missing required parameter:
{
"error": "type and crisis query params are required"
}
401 Unauthorized:
{
"error": "Unauthorized. Provide Authorization: Bearer <api_key> header."
}
429 Rate Limited:
{
"error": "Rate limit exceeded",
"limit": 15,
"plan": "sandbox",
"retry_after": 60
}
500 Internal:
{
"error": "Internal server error"
}
GET /v1/crises All
Discovery endpoint. Returns all tracked crisis theaters with current status, event counts, intensity scores, geographic bounds, and center coordinates. This is the entry point to the API — use the id field to query all other endpoints.
Parameters
None required.
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/crises"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} response = requests.get( "https://polycrisis.world/api/v1/crises", headers=headers ) crises = response.json()["crises"] for c in crises: print(f"{c['emoji']} {c['name']}: intensity {c['intensity']}")
Response
{
"crises": [
{
"id": "iran",
"name": "Iran",
"emoji": "🇮🇷",
"color": "#dc2626",
"status": "active",
"event_count": 847,
"latest_event": "2026-03-21T14:23:00Z",
"intensity": 7.2,
"center": { "lat": 32.4, "lng": 53.7 },
"bounds": { "lat_min": 12, "lat_max": 42, "lng_min": 28, "lng_max": 66 }
}
],
"last_updated": "2026-03-21T14:30:00Z",
"generated_at": "2026-03-21T14:30:00Z",
"meta": { "count": 7 }
}
GET /v1/events All
Retrieve geolocated crisis events. Events are extracted from 150+ sources every 15 minutes using AI, with coordinates verified by gazetteer lookup and geocorrection. Supports full-text search and offset pagination.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Crisis theater: iran, ukraine, gaza, scs, climate, usa (United States), agi. Use /v1/crises for the full list. Omit for all. |
| type | string | No | Single event type: military, naval, nuclear, political, economic, protest, humanitarian, enforcement, climate, cyber, news. Note: economic covers oil prices, sanctions, trade disruptions, supply chain events, and market impacts. Previously classified as political. |
| cluster_id | string | No | Filter events by story cluster. Returns only events in the specified cluster. |
| since | string | No | ISO 8601 timestamp. Return events on or after this time. |
| until | string | No | ISO 8601 timestamp. Return events before this time. |
| min_confidence | number | No | Minimum confidence score (0–1). Also accepts confidence_min. Default: 0. |
| q | string | No | Full-text search query across title and description. Also accepts search. |
| sort | string | No | Sort order: chronological (default), newest, or confidence. |
| limit | integer | No | Max events to return. Default: 100, range 1–500. |
| offset | integer | No | Offset for pagination. Default: 0. Combine with meta.total in the response. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/events?crisis=scs&type=naval&since=2026-03-15T00:00:00Z&limit=50"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} response = requests.get( "https://polycrisis.world/api/v1/events", headers=headers, params={ "crisis": "scs", "type": "naval", "since": "2026-03-15T00:00:00Z", "limit": 50 } ) events = response.json()["events"] for event in events: print(f"{event['event_type']}: {event['title']}")
Response
{
"events": [
{
"id": "evt_7823",
"crisis": "scs",
"event_type": "naval",
"title": "Philippine Coast Guard reports water cannon incident near Scarborough Shoal",
"description": "Chinese coast guard vessels deployed water cannons against Philippine resupply mission near Scarborough Shoal.",
"lat": 15.228,
"lng": 117.764,
"timestamp": "2026-03-15T08:23:00Z",
"source": "ai",
"source_url": "https://www.rappler.com/nation/...",
"source_name": "Rappler",
"confidence": 0.92,
"cluster_id": "story_scs_8842"
}
],
"meta": {
"total": 847,
"returned": 50,
"offset": 0,
"limit": 50,
"generated_at": "2026-03-21T14:30:00Z"
},
"generated_at": "2026-03-21T14:30:00Z"
}
Response Fields
The source field indicates the ingestion method (ai or static). For the news outlet name, use source_name.
| Field | Type | Description |
|---|---|---|
| id | string | Unique event ID (prefixed with evt_, e.g. "evt_7823"). |
| crisis | string | Crisis theater the event belongs to. |
| event_type | string | Canonical type: military, naval, nuclear, political, economic, protest, humanitarian, enforcement, climate, cyber, news. |
| title | string | Short headline. |
| description | string | Longer description of the event. |
| lat | number | Latitude (WGS 84). |
| lng | number | Longitude (WGS 84). |
| timestamp | string | ISO 8601 timestamp of when the event occurred (e.g. "2026-03-15T08:23:00Z"). |
| source | string | Ingestion method: ai (extracted by AI) or static (manually seeded). Not the outlet name. |
| source_url | string | URL of the original article. |
| source_name | string | Name of the news source (e.g. “Reuters”, “BBC”). Use this instead of source for the outlet name. |
| confidence | number | Composite confidence score (0–1). |
| cluster_id | string | null | Story-level grouping ID. Events about the same story share a cluster_id (e.g. "story_iran_12345"). Filter with ?cluster_id=. |
GET /v1/event-stats All
Track record (Brier calibration) for an event type within a crisis. Returns per-ticker UP-rate, average pct move, and Brier score across the 15m, 1h, 4h, and 1d horizons. Lookback: 90 days. Response cached server-side for 6 hours.
Why Brier?
Brier score measures how well calibrated the system's directional predictions are. Lower is better. A coin flip = 0.25; a well-calibrated forecaster typically scores around 0.15. We compute Brier per (event type × crisis × ticker × horizon) using a rolling self-referential baseline: the predicted UP probability for an event is the rolling UP-rate of prior events of the same type. Cells with fewer than 5 events suppress the Brier number to avoid meaningless precision.
Move thresholds: ±0.3% for equities, ±0.5% for commodities (CL=F, NG=F, BZ=F). Smaller moves count as NO_MOVE and are treated as not-UP for the binary Brier target.
Parameters
type(required) — one of:military,naval,nuclear,political,economic,protest,humanitarian,enforcement,climate,cyber,newscrisis(required) — one of:iran,ukraine,climate,usa,agi,gaza,scsticker(optional) — if set, returns stats only for this ticker. Otherwise returns the matrix for all anchor tickers for the crisis.breakdown(optional) —summary(default) orfull.fulladds asamplesarray with the 5 most recent past events and their per-ticker outcomes (the “receipts” list).
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/event-stats?type=military&crisis=iran&breakdown=full"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} response = requests.get( "https://polycrisis.world/api/v1/event-stats", params={"type": "military", "crisis": "iran", "breakdown": "full"}, headers=headers ) stats = response.json() for ticker, data in stats["tickers"].items(): h1h = data["horizons"]["1h"] print(f"{ticker} 1h: UP-rate {h1h['up_rate']*100:.0f}%, Brier {h1h['brier']}")
Response
{
"type": "military",
"crisis": "iran",
"n": 47,
"tickers": {
"CL=F": {
"n": 47,
"horizons": {
"15m": { "n": 45, "up_rate": 0.58, "avg_move_pct": 0.003, "brier": 0.21 },
"1h": { "n": 45, "up_rate": 0.62, "avg_move_pct": 0.008, "brier": 0.18 },
"4h": { "n": 44, "up_rate": 0.55, "avg_move_pct": 0.011, "brier": 0.22 },
"1d": { "n": 44, "up_rate": 0.49, "avg_move_pct": 0.004, "brier": 0.27 }
}
}
},
"samples": [
{
"id": 12345,
"label": "IRGC strike on convoy",
"source_url": "https://example.com/article",
"source_name": "Reuters",
"t": 1740000000,
"outcomes": {
"CL=F": {
"15m": { "movement": "UP", "pct": 0.004 },
"1h": { "movement": "UP", "pct": 0.009 }
}
}
}
],
"as_of": "2026-04-07T15:30:00Z"
}
GET /v1/connections All
Cross-crisis connections with real-time intensity tracking and cluster-driven alignment scoring. Each connection is enriched from three signal layers: event-detected (Haiku pipeline analysis), cluster-boosted (embedding space proximity), and scenario-derived (scenario tree parent links, including systemic crises).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to connections involving this crisis |
| limit | integer | No | Max results (1–50). Default: 20 |
Request
curl https://polycrisis.world/api/v1/connections?crisis=iran \ -H "Authorization: Bearer pk_YOUR_KEY"
resp = requests.get(
"https://polycrisis.world/api/v1/connections",
params={"crisis": "iran"},
headers={"Authorization": "Bearer pk_YOUR_KEY"}
)
Response
{
"connections": [
{
"source_crisis": "iran",
"target_crisis": "gaza",
"strength": 0.82,
"intensity": {
"level": "elevated",
"event_velocity": 4.2,
"baseline_velocity": 1.1,
"trend": "rising",
"window": "7d"
},
"cluster_alignment": 0.78,
"mechanisms": ["Hezbollah/Hamas axis", "Regional military escalation"],
"evidence_count": 14,
"sources": ["event_detected", "cluster_boosted"]
}
],
"meta": {
"total": 12,
"signal_layers": ["event_detected", "cluster_boosted", "scenario_derived"]
}
}
GET /v1/scenarios All
Returns AI-generated scenario assessments for a crisis theater. Each scenario includes a probability integer 0–100, a band label (REMOTE/UNLIKELY/PLAUSIBLE/LIKELY/IMMINENT/CONFIRMED), the most recent justification, and the URL that moved it last. Assessments are generated by Claude Sonnet and refreshed every few hours based on the live event stream.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Crisis theater (e.g. iran). If omitted, returns a map keyed by crisis. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/scenarios?crisis=iran"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/scenarios", headers=headers, params={"crisis": "iran"} ).json() for s in data["scenarios"]: print(f"{s['title']}: {s['probability']}% [{s['band']}]")
Response
{
"crisis": "iran",
"scenarios": [
{
"id": "iran_strike",
"title": "US/Israel strike on nuclear facilities",
"description": "Kinetic action targeting enrichment sites.",
"probability": 25,
"previous_probability": 18,
"band": "UNLIKELY",
"color": "#f97316",
"justification": "IAEA non-compliance finding and Israeli cabinet leaks indicate rising strike risk.",
"source_url": "https://www.reuters.com/...",
"cluster_momentum": {
"growth_rate": 0.42,
"coherence_delta": 0.81,
"alignment_score": 0.67
}
}
],
"intensity": { "value": 7.2, "band": "high" },
"generated_at": "2026-03-21T14:30:00Z",
"meta": { "count": 8 }
}
GET /v1/scenarios/{id} All
Get a single scenario with its full ancestry (path to root) and descendants (child branches in the scenario tree).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id required | string | Yes | Scenario node ID (e.g., iran_hormuz) |
Request
curl https://polycrisis.world/api/v1/scenarios/iran_hormuz \ -H "Authorization: Bearer pk_YOUR_KEY"
resp = requests.get(
"https://polycrisis.world/api/v1/scenarios/iran_hormuz",
headers={"Authorization": "Bearer pk_YOUR_KEY"}
)
Response
{
"scenario": {
"id": "iran_hormuz",
"crisis": "iran",
"label": "Strait of Hormuz closure",
"risk": "plausible",
"probability": 35
},
"ancestors": [
{ "id": "iran_escalation", "label": "Military escalation" }
],
"descendants": [
{ "id": "iran_oil_shock", "label": "Global oil price shock" }
],
"path": ["iran_escalation", "iran_hormuz"]
}
GET /v1/scenarios/tree All
Full scenario tree with all nodes. Confirmed events at center, speculative futures branching outward through risk levels: confirmed → high → likely → plausible → speculative → remote.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter tree to nodes from this crisis (includes cross-crisis connections) |
Request
curl https://polycrisis.world/api/v1/scenarios/tree?crisis=iran \ -H "Authorization: Bearer pk_YOUR_KEY"
resp = requests.get(
"https://polycrisis.world/api/v1/scenarios/tree",
params={"crisis": "iran"},
headers={"Authorization": "Bearer pk_YOUR_KEY"}
)
Response
{
"tree": {
"nodes": [
{
"id": "iran_hormuz",
"crisis": "iran",
"label": "Strait of Hormuz closure",
"risk": "plausible",
"probability": 35,
"parent": "iran_escalation"
}
]
},
"meta": {
"total_nodes": 142,
"updated_at": "2026-03-28T06:00:00Z"
}
}
GET /v1/scenarios/paths All
Ranked escalation chains from confirmed events through to speculative/remote outcomes. Each path traces a sequence of scenarios from center to edge of the tree.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to paths from this crisis |
Response
{
"paths": [
{
"nodes": [
{ "id": "iran_strike_confirmed", "risk": "confirmed" },
{ "id": "iran_retaliation", "risk": "likely" },
{ "id": "iran_hormuz", "risk": "plausible" }
],
"terminal_risk": "plausible",
"terminal_probability": 35
}
]
}
GET /v1/scenarios/changes All
Recent tree mutations — nodes added, removed, or risk levels changed.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| since | string | No | ISO date. Default: last 24 hours. |
| crisis | string | No | Filter to changes in this crisis |
Response
{
"changes": [
{
"node_id": "iran_hormuz",
"type": "risk_changed",
"old_value": "speculative",
"new_value": "plausible",
"changed_at": "2026-03-28T06:00:00Z"
}
]
}
GET /v1/scenarios/history All
Probability change history for scenarios over time. Track how scenario likelihoods have evolved.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis required | string | Yes | Crisis to get history for |
| scenario_id | string | No | Filter to specific scenario |
| days | integer | No | Lookback window. Default: 30 |
Response
{
"history": [
{
"scenario_id": "iran_hormuz",
"title": "Strait of Hormuz closure",
"data_points": [
{ "date": "2026-03-01", "probability": 25 },
{ "date": "2026-03-15", "probability": 35 }
]
}
]
}
GET /v1/scenarios/ripple All
Scenario-to-scenario chain reactions across crises. Shows how one scenario triggering could ripple into scenarios in other crisis theaters. This is the scenario-level equivalent of crisis-level connections.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to ripples from this crisis |
| scenario_id | string | No | Show ripples from a specific scenario |
Response
{
"ripples": [
{
"src_crisis": "iran",
"src_scenario": "iran_hormuz",
"src_title": "Strait of Hormuz closure",
"tgt_crisis": "climate",
"tgt_scenario": "climate_energy_shock",
"tgt_title": "Global energy price shock",
"mechanism": "Oil supply disruption triggers energy crisis",
"weight": 0.75
}
]
}
GET /v1/patterns All
Returns all spatial-temporal event clusters (patterns) detected by DBSCAN clustering across the event corpus. Each cluster represents a group of related events that share geographic and thematic proximity.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter clusters involving this crisis theater. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/patterns"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/patterns", headers=headers ).json() for p in data["patterns"]: print(f"{p['label']}: {p['event_count']} events (coherence {p['coherence_score']})")
Response
{
"patterns": [
{
"id": "clst_0",
"label": "Eastern Mediterranean Military Buildup",
"description": "Cluster of military and naval events across Gaza and Iran theaters.",
"crises": ["gaza", "iran"],
"event_count": 47,
"coherence_score": 0.82,
"top_events": ["IDF airstrike Khan Younis", "Iran proxy naval incident"]
}
],
"meta": { "count": 12 },
"generated_at": "2026-03-21T14:30:00Z"
}
GET /v1/patterns/{cluster_id} All
Deep dive into a specific event cluster. Returns all events in the cluster, crisis breakdown, and event type distribution.
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/patterns/clst_0"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/patterns/clst_0", headers=headers ).json() cluster = data["cluster"] print(f"{cluster['label']}: {cluster['event_count']} events") for event in cluster["events"]: print(f" {event['event_date']}: {event['title']}")
Response
{
"cluster": {
"id": "clst_0",
"label": "Eastern Mediterranean Military Buildup",
"description": "Cluster of military and naval events across Gaza and Iran theaters.",
"crises": ["gaza", "iran"],
"event_count": 47,
"type_breakdown": { "military": 22, "naval": 15 },
"events": [
{
"id": 1234,
"title": "IDF strikes southern Gaza",
"crisis": "gaza",
"event_type": "military",
"event_date": "2026-03-20T00:00:00Z"
}
]
}
}
GET /v1/patterns/similar All
Vector-similarity search over historical events. Given an event type and region, returns the closest matches from the archive using embedding distance.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| event_type required | string | Yes | Canonical event type (e.g. military, naval). |
| region | string | No | Crisis theater to bias the search toward. |
| lookback | integer | No | Lookback in days for the candidate pool. Default: 180. |
| threshold | number | No | Minimum cosine similarity (0–1) to return. Default: 0.7. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/patterns/similar?event_type=military®ion=iran"
import requests data = requests.get( "https://polycrisis.world/api/v1/patterns/similar", headers={"Authorization": "Bearer $POLYCRISIS_KEY"}, params={"event_type": "military", "region": "iran"} ).json()
Response
{
"query": { "event_type": "military", "region": "iran", "lookback": 180, "threshold": 0.7 },
"matches": [
{ "id": 8231, "label": "IRGC drone strike on oil facility", "event_date": "2025-11-04", "similarity": 0.91 }
],
"generated_at": "2026-03-21T14:30:00Z"
}
GET /v1/analogs All
Find historical analogs to current crisis conditions. Returns the top past periods with similar event patterns, along with what happened next — cascading effects, market outcomes, and scenario probability changes.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis required | string | Yes | Crisis theater to find analogs for. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/analogs?crisis=scs"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/analogs", headers=headers, params={"crisis": "scs"} ).json() for a in data["analogs"]: print(f"{a['period']}: {a['title']} (similarity {a['similarity']:.2f})")
Response
{
"crisis": "scs",
"current_type_mix": { "naval": 18, "military": 6, "political": 4 },
"current_event_count": 28,
"analogs": [
{
"period": "2025-03-08 to 2025-03-15",
"similarity": 0.89,
"title": "PLAN exercises near Scarborough Shoal",
"event_count": 12,
"outcome": "De-escalation after 9 days. USN carrier redeployed.",
"market_outcome": { "CL=F": "+1.8%", "TSM": "-4.2%" },
"resolution_days": 9
}
],
"historical_conflicts": [],
"generated_at": "2026-03-21T14:30:00Z",
"meta": { "top_k": 10 }
}
GET /v1/actors All
Entity-centric intelligence. Tracks organizations, governments, military groups, and key individuals across all crisis theaters. Shows who is active, where they appear, and whether their activity is rising or falling.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to actors in this crisis |
| limit | integer | No | Max results (1–50). Default: 20 |
Response
{
"actors": [
{
"name": "IRGC",
"crises": ["iran", "gaza"],
"event_count_7d": 12,
"event_count_30d": 45,
"trend": "rising",
"last_seen": "2026-03-28T14:30:00Z",
"primary_event_types": ["military", "naval"]
}
],
"meta": { "total": 15 }
}
GET /v1/actors/{name} All
Deep profile for a specific entity. Event timeline, crisis presence, and co-occurring actors.
Response
{
"name": "IRGC",
"crises": ["iran", "gaza"],
"event_count": 45,
"timeline": [
{
"id": 4521,
"crisis": "iran",
"event_type": "military",
"date": "2026-03-28T14:30:00Z"
}
],
"connections": [
{ "name": "Hezbollah", "co_occurrences": 18 }
]
}
GET /v1/hotspots All
Geographic convergence zones where multi-crisis activity concentrates. Uses spatial clustering to identify areas where events from different crises overlap geographically.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to hotspots in this crisis |
| days | integer | No | Lookback window (1–90). Default: 7 |
| limit | integer | No | Max results (1–25). Default: 10 |
Response
{
"hotspots": [
{
"id": "hs_0",
"name": "Strait of Hormuz",
"center": { "lat": 26.5, "lng": 56.2 },
"radius_km": 85,
"crises": ["iran", "usa"],
"event_count": 18,
"dominant_types": ["naval", "military"],
"trend": "heating"
}
],
"meta": { "total": 8, "days": 7 }
}
GET /v1/anomalies All
Events that don't fit established patterns. Embedding-space outliers — events whose semantic content is far from any identified cluster. Anomalies are either noise or early signals of emerging dynamics that existing analysis doesn't capture yet.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter to anomalies in this crisis |
| since | integer | No | Lookback in days (1–30). Default: 7 |
| limit | integer | No | Max results (1–25). Default: 10 |
Response
{
"anomalies": [
{
"event": {
"id": 4521,
"crisis": "iran",
"event_type": "cyber",
"label": "Unexplained communications blackout in Isfahan",
"date": "2026-03-27T08:15:00Z"
},
"deviation_score": 8.4,
"nearest_pattern": {
"id": 3,
"label": "Hormuz Naval Activity"
}
}
],
"meta": { "total": 5, "days": 7 }
}
Markets endpoints
Three market-data endpoints are available under /v1/markets/*. They proxy the dashboard's internal market views into the v1 API surface. Accept crisis as the primary filter and return minute/hour/day bar data suitable for charting.
| Endpoint | Returns |
|---|---|
GET /v1/markets/cone | Forward uncertainty cone (price fan) around a key ticker for a crisis. Response includes ticker, current_price, sigma_daily, and a series array of upper/lower bounds by horizon. |
GET /v1/markets/sensitivity | Per-scenario ticker sensitivity estimates. Response keys each scenario ID to an array of {ticker, expected_move_pct, confidence}. |
GET /v1/markets/events | Recent crisis events annotated with the market move that followed them (useful for backtesting). |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/markets/cone?crisis=iran"
import requests cone = requests.get( "https://polycrisis.world/api/v1/markets/cone", headers={"Authorization": "Bearer $POLYCRISIS_KEY"}, params={"crisis": "iran"} ).json() print(f"{cone['ticker']}: {cone['current_price']} (σ={cone['sigma_daily']:.2%})")
GET /v1/intensity All
Returns a calculated escalation intensity index for a crisis, plus a timeseries over the requested window. Derived from event frequency, type severity weighting, and cross-crisis connection activity. Useful for triggering alerts or dynamically weighting portfolio exposure when a crisis is heating up.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | Yes | Crisis theater (e.g. scs, iran). |
| window | integer | No | Number of days of history to include. Default: 30, max: 365. |
| granularity | string | No | Bucket size for the timeseries: day (default) or week. Also accepts bucket. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/intensity?crisis=scs&window=14"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/intensity", headers=headers, params={"crisis": "scs", "window": 14} ).json() current = data["current_index"] print(f"Intensity: {current['value']} ({current['band']})") print(f"7-day delta: {current['delta_7d']}")
Response
{
"crisis": "scs",
"window_days": 14,
"current_index": {
"value": 7.8,
"band": "high",
"delta_7d": +0.6,
"event_count": 38
},
"timeseries": [
{ "bucket": "2026-03-08", "index": 6.2, "event_count": 24 },
{ "bucket": "2026-03-15", "index": 7.1, "event_count": 31 },
{ "bucket": "2026-03-21", "index": 7.8, "event_count": 38 }
],
"generated_at": "2026-03-21T14:30:00Z",
"meta": { "granularity": "day" }
}
GET /v1/indicators All
Returns 8 normalized (0–1) risk indicators for a crisis, plus a composite risk score. Covers escalation probability, event intensity, signal velocity, actor concentration, confidence drift, market contagion, narrative contagion, and anomaly detection. Cached for 15 minutes.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | One of crisis or country | Crisis ID (e.g. iran, ukraine). |
| country | string | One of crisis or country | Country name (e.g. Turkey, Taiwan). Mapped to the relevant crisis. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/indicators?crisis=iran"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/indicators", headers=headers, params={"crisis": "iran"} ).json() print(f"Composite risk: {data['composite_risk']}") for name, ind in data["indicators"].items(): print(f" {name}: {ind['value']} ({ind['trend']})")
Response
{
"crisis": "iran",
"timestamp": "2026-04-20T12:00:00Z",
"composite_risk": 0.52,
"indicators": {
"escalation_probability": { "value": 0.65, "trend": "rising", "period": "30d" },
"event_intensity": { "value": 0.81, "trend": "stable", "period": "7d" },
"signal_velocity": { "value": 0.43, "trend": "falling", "period": "3d" },
"actor_concentration": { "value": 0.38, "trend": "stable", "period": "30d" },
"confidence_drift": { "value": 0.45, "trend": "falling", "period": "7d" },
"market_contagion": { "value": 0.72, "trend": "rising", "period": "30d" },
"narrative_contagion": { "value": 0.55, "trend": "stable", "period": "30d" },
"anomaly_index": { "value": 0.12, "trend": "stable", "period": "7d" }
}
}
Indicator Descriptions
| Indicator | Source | Description |
|---|---|---|
| escalation_probability | ai_scenarios | Severity-weighted average of active scenario probabilities. |
| event_intensity | events | 7-day event rate vs 30-day baseline. >0.33 = acceleration. |
| signal_velocity | events | 3-day spike detection vs 30-day rolling average. |
| actor_concentration | events | HHI of actor involvement. 1.0 = monopoly, ~0 = diffuse. |
| confidence_drift | events | Change in avg event confidence. <0.5 = increasing fog of war. |
| market_contagion | market_daily | Avg |change_pct| of crisis-linked tickers. Higher = markets reacting. |
| narrative_contagion | crisis_connections | Strength of spillover to other crisis theatres. |
| anomaly_index | events | Z-score of event volume spikes vs 30-day baseline. |
GET /v1/correlations Analyst+
Computes cross-crisis correlations between geopolitical event types and financial instruments, including statistical significance testing and average market moves. Requires the Developer plan.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis required | string | Yes | Crisis theater to analyze. |
| event_type | string | No | Source event type (e.g., naval, military). Omit for all types. |
| market | string | No | Single market symbol to test (e.g., CL=F, TSM, GLD). Omit for the crisis’s default basket. |
| window | integer | No | Lookback window in days. Default: 90. |
| windows | string | No | Comma-separated post-event horizons to test (minutes). Default: 15,60,240,1440. |
Request
curl -H "Authorization: Bearer YOUR_ANALYST_KEY" \ "https://polycrisis.world/api/v1/correlations?crisis=scs&event_type=naval&market=CL=F"
import requests headers = {"Authorization": "Bearer YOUR_ANALYST_KEY"} corr = requests.get( "https://polycrisis.world/api/v1/correlations", headers=headers, params={"crisis": "scs", "event_type": "naval", "market": "CL=F"} ).json() for c in corr["correlations"]: print(f"{c['ticker']} @ {c['window_min']}m: r={c['correlation']:.2f}")
Response
{
"crisis": "scs",
"event_type": "naval",
"window_days": 90,
"correlations": [
{
"ticker": "CL=F",
"window_min": 60,
"correlation": 0.73,
"p_value": 0.002,
"avg_move_pct": 2.1,
"sample_size": 47
}
],
"generated_at": "2026-03-21T14:30:00Z",
"meta": { "windows": [15, 60, 240, 1440] }
}
GET /v1/signals All
Multi-layer confluence detection across all active crises. Identifies which crises have multiple simultaneous risk signals — scenario confirmations, intensity spikes (from /v1/intensity), inbound cross-crisis connections (from /v1/connections), and humanitarian alerts. Higher confluence scores indicate more layers of risk converging.
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/signals"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} data = requests.get( "https://polycrisis.world/api/v1/signals", headers=headers ).json() for s in data["signals"]: print(f"{s['crisis_name']}: confluence {s['confluence_score']} ({s['layer_count']} layers)")
Response
{
"signals": [
{
"crisis": "iran",
"crisis_name": "Iran",
"confluence_score": 4,
"layers": [
{ "type": "scenarios", "count": 3 },
{ "type": "intensity", "score": 78 },
{ "type": "connections_inbound", "count": 2 },
{ "type": "humanitarian_alerts", "count": 1 }
],
"layer_count": 4,
"summary": "Iran showing confluence across all 4 risk layers..."
}
],
"generated_at": "2026-03-21T14:30:00Z",
"meta": {
"layers_checked": ["scenarios", "intensity", "connections_inbound", "humanitarian_alerts"],
"min_layers": 2
}
}
GET /v1/briefing All
Returns a cached intelligence briefing for a crisis theater. Two depth levels: light returns a 2-3 sentence summary updated every 30 minutes; deep returns a full analysis derived from the daily podcast transcript. No AI tokens consumed — briefings are pre-generated and cached.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis required | string | Yes | Crisis theater to brief on. |
| depth | string | No | light (2-3 sentences, 30-min cache) or deep (full analysis from daily briefing transcript, 1-hour cache). Default: light. |
Request
curl -H "Authorization: Bearer $POLYCRISIS_KEY" \ "https://polycrisis.world/api/v1/briefing?crisis=iran&depth=deep"
import requests headers = {"Authorization": "Bearer $POLYCRISIS_KEY"} briefing = requests.get( "https://polycrisis.world/api/v1/briefing", headers=headers, params={"crisis": "iran", "depth": "deep"} ).json() print(briefing["briefing"])
Response
{
"crisis": "iran",
"depth": "deep",
"briefing": "**Iran (Intensity: 7.2, RISING):** IAEA confirmed 83.7% enrichment at Fordow, up from 60% baseline. Israeli defense minister statement interpreted as implicit strike authorization. CL=F up 1.4% on the development. Backchannel talks via Oman continue but no breakthrough indicators detected.",
"event_count_48h": 37,
"generated_at": "2026-03-21T10:15:00Z"
}
GET /v1/stream All
Server-Sent Events (SSE) endpoint for real-time streaming. Opens a persistent connection and pushes new events as they are processed. Supports filtering by crisis, event type, and minimum confidence.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| crisis | string | No | Filter stream to a specific crisis theater. Omit for all. |
| type | string | No | Filter by event type (single value). |
| min_confidence | number | No | Minimum confidence score (0–1) for streamed events. |
Event Types
| Event | Description |
|---|---|
| new_event | A new crisis event was processed and added. |
| heartbeat | Keepalive signal sent every 15 seconds. |
Request
curl -N -H "Authorization: Bearer $POLYCRISIS_KEY" \ -H "Accept: text/event-stream" \ "https://polycrisis.world/api/v1/stream?crisis=iran&type=nuclear"
import requests, json headers = { "Authorization": "Bearer $POLYCRISIS_KEY", "Accept": "text/event-stream" } r = requests.get( "https://polycrisis.world/api/v1/stream", headers=headers, params={"crisis": "iran"}, stream=True ) for line in r.iter_lines(decode_unicode=True): if line.startswith("data: "): event = json.loads(line[6:]) print(event.get("title", event))
Response Stream
event: new_event data: {"id":7824,"crisis":"iran","event_type":"nuclear","title":"IAEA confirms 83.7% enrichment at Fordow","lat":34.708,"lng":51.984} event: heartbeat data: {"ts":"2026-03-21T10:15:30Z"}
POST /v1/webhooks All
Register a webhook to receive real-time alerts. Events matching your filters are POSTed to your callback URL as they occur. The server returns an HMAC signing_secret when you create a webhook — use it to verify the X-Polycrisis-Signature header on inbound deliveries. Also supports GET (list webhooks) and DELETE (remove webhook).
Create Webhook — Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| url required | string | Yes | Your callback URL. Must be HTTPS. |
| triggers | string[] | No | Trigger types to subscribe to: new_event, scenario_change, intensity_spike. Default: all. |
| crisis | string | No | Restrict deliveries to this crisis theater. |
| event_type | string | No | Restrict deliveries to this event type (applies to new_event). |
| min_confidence | number | No | Suppress events below this confidence (0–1). |
| intensity_threshold | number | No | Fire intensity_spike only when the index crosses this value. |
| filter | string | No | Freeform label you can use server-side for your own routing. |
| cascade_alert | boolean | No | Also fire on cross-crisis connection effects. |
| cascade_theaters | string[] | No | Restrict cascade alerts to the listed crisis theaters. |
The response includes a signing_secret field — this is the only time the server returns it in cleartext. Store it securely and use it to HMAC-verify incoming webhook payloads.
Create Request
curl -X POST -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-system.com/webhook", "triggers": ["new_event", "scenario_change"], "crisis": "iran", "event_type": "nuclear", "min_confidence": 0.6 }' \ https://polycrisis.world/api/v1/webhooks
import requests headers = { "Authorization": "Bearer YOUR_KEY", "Content-Type": "application/json" } webhook = requests.post( "https://polycrisis.world/api/v1/webhooks", headers=headers, json={ "url": "https://your-system.com/webhook", "triggers": ["new_event", "scenario_change"], "crisis": "iran", "event_type": "nuclear", "min_confidence": 0.6 } ).json() print(f"Webhook ID: {webhook['id']}") print(f"Signing secret: {webhook['signing_secret']}")
Create Response
{
"id": "wh_a9c3f1",
"status": "active",
"url": "https://your-system.com/webhook",
"triggers": ["new_event", "scenario_change"],
"crisis": "iran",
"event_type": "nuclear",
"min_confidence": 0.6,
"intensity_threshold": null,
"signing_secret": "whsec_cd3f9a...",
"created_at": "2026-03-21T10:00:00Z"
}
Manage Webhooks
# List all webhooks owned by this key curl -H "Authorization: Bearer YOUR_KEY" \ https://polycrisis.world/api/v1/webhooks # Delete a webhook — ID goes in the JSON body, not the URL path curl -X DELETE -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"id": "wh_a9c3f1"}' \ https://polycrisis.world/api/v1/webhooks
Use Cases
Practical examples for integrating POLYCRISIS data into trading systems, risk dashboards, and monitoring bots.
Geopolitical Signal for Oil Trading
Monitor Iran scenario probabilities and correlate with oil futures. Generate trading signals when Hormuz disruption probability crosses your threshold.
import requests import pandas as pd API_KEY = "pk_YOUR_KEY" headers = {"Authorization": f"Bearer {API_KEY}"} # Get Iran crisis intensity and Hormuz scenario probability scenarios = requests.get( "https://polycrisis.world/api/v1/scenarios", headers=headers, params={"crisis": "iran"} ).json() hormuz = next((s for s in scenarios["scenarios"] if "hormuz" in s["title"].lower()), None) if hormuz: prob = hormuz["probability"] # already 0-100 print(f"Hormuz disruption probability: {prob}% [{hormuz['band']}]") if prob > 80: print("HIGH RISK -- consider oil long positions") # Correlate with market data (Analyst+ plan required) correlations = requests.get( "https://polycrisis.world/api/v1/correlations", headers=headers, params={"crisis": "iran", "market": "CL=F"} ).json() print(f"Iran-Oil correlation: {correlations['correlations'][0]['correlation']}")
Crisis Event Monitoring Bot
Poll for new military events in real time. Alert your team when new high-confidence events appear in a crisis theater.
import requests import time API_KEY = "pk_YOUR_KEY" headers = {"Authorization": f"Bearer {API_KEY}"} seen_ids = set() while True: events = requests.get( "https://polycrisis.world/api/v1/events", headers=headers, params={"crisis": "iran", "type": "military", "limit": 5} ).json().get("events", []) for event in events: if event["id"] not in seen_ids: seen_ids.add(event["id"]) print(f"NEW: {event['title']} ({event.get('lat')}, {event.get('lng')})") time.sleep(300) # Poll every 5 minutes
Multi-Crisis Risk Dashboard Data
Build a portfolio risk dashboard that pulls intensity scores across all crisis theaters and flags elevated risks.
import requests API_KEY = "pk_YOUR_KEY" headers = {"Authorization": f"Bearer {API_KEY}"} crises = requests.get( "https://polycrisis.world/api/v1/crises", headers=headers ).json() for crisis in crises["crises"]: data = requests.get( "https://polycrisis.world/api/v1/intensity", headers=headers, params={"crisis": crisis["id"]} ).json() current = data.get("current_index", {}) print(f"{crisis['name']}: intensity {current.get('value')} [{current.get('band')}]")
Scenario Backtesting Signal
Track scenario probability changes over time. When a scenario crosses a threshold, generate a trading signal for backtesting or live execution.
""" Track scenario probability changes over time. When a scenario crosses a threshold, generate a trading signal. """ import requests API_KEY = "pk_YOUR_KEY" headers = {"Authorization": f"Bearer {API_KEY}"} # Get scenario history for backtesting history = requests.get( "https://polycrisis.world/api/scenario-history", params={"crisis": "iran"} ).json() for scenario_id, entries in history.get("history", {}).items(): if len(entries) < 2: continue latest = entries[-1]["prob"] previous = entries[-2]["prob"] delta = latest - previous if abs(delta) >= 10: direction = "UP" if delta > 0 else "DOWN" print(f"{direction} {scenario_id}: {previous}% -> {latest}% (delta {delta:+d})")