Real-Time Events (SSE)
The Events endpoint streams simulation activity through SSE for live dashboards and monitoring tools. A basin loss is a collapse event. A decree is a stored intervention record. A prophecy is a stored simulation result.
Subscribe to Events
Section titled “Subscribe to Events”GET /v1/simulations/{id}/eventsOpens an authenticated SSE connection for an accessible simulation.
API keys access their own organization’s simulations. JWT callers need organization membership or ownership of a personal simulation.
Replace <api-key> and <simulation-id> in the examples with your key and simulation UUID.
Scope required (API key): simulation:read
Path Parameters
Section titled “Path Parameters”| Parameter | Type | Description |
|---|---|---|
id | uuid | Simulation ID |
Connection Details
Section titled “Connection Details”- Content-Type:
text/event-stream - Connection: Keep-alive
- Heartbeat: Every 30 s with an empty JSON object as data
- Concurrency: Limited by the identity’s applicable license tier (see Rate Limiting)
Event Types
Section titled “Event Types”| Event | Description |
|---|---|
tick | Latest simulation snapshot, which can summarize a multi-tick request |
loss | A basin loss (irreversible collapse) occurred |
warning | Warning active state changed |
paradox | A paradox was detected |
decree | A decree record was submitted |
prophecy | A new prophecy was generated |
simulation:status | Status notification: running, paused, completed, or failed |
error | A simulation error occurred |
heartbeat | Keep-alive signal with {} as data |
Event Format
Section titled “Event Format”Each frame has an event line, a JSON data line, and a blank terminator.
This shortened tick example omits state fields and agent snapshots. The loss frame shows its field names and illustrative values.
event: tickdata: {"t":42,"b":0,"lastMove":"stay","state":{...},"warning":null,"agents":[...]}
event: lossdata: {"type":"LOSS","t":247,"b":0,"magnitude":0.6133,"val":0.5}
event: heartbeatdata: {}Example: curl
Section titled “Example: curl”curl -N "https://api.anankelabs.io/v1/simulations/<simulation-id>/events" \ -H "X-Api-Key: <api-key>"Example: JavaScript
Section titled “Example: JavaScript”The browser EventSource constructor does not accept an API key header. Use fetch to read this authenticated stream.
const response = await fetch( "https://api.anankelabs.io/v1/simulations/<simulation-id>/events", { headers: { "X-Api-Key": "<api-key>" } });if (!response.ok) throw new Error(`HTTP ${response.status}`);if (!response.body) throw new Error("No response stream");
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();let buffer = "";try { while (true) { const { value, done } = await reader.read(); if (done) break; buffer += value; const frames = buffer.split("\n\n"); buffer = frames.pop(); for (const frame of frames) { const lines = frame.split("\n"); const type = lines.find((line) => line.startsWith("event: "))?.slice(7); const data = lines.find((line) => line.startsWith("data: "))?.slice(6); if (data === undefined) continue; const event = JSON.parse(data); if (type === "tick") console.log(`Tick ${event.t}`); if (type === "loss") console.log(`Basin loss at tick ${event.t}`); if (type === "error") console.error("Simulation error:", event); } }} finally { await reader.cancel();}Example: Python
Section titled “Example: Python”import jsonimport httpx
url = "https://api.anankelabs.io/v1/simulations/<simulation-id>/events"headers = {"X-Api-Key": "<api-key>"}
with httpx.stream("GET", url, headers=headers) as response: response.raise_for_status() for line in response.iter_lines(): if line.startswith("data:"): payload = line.removeprefix("data:").strip() if payload: event = json.loads(payload) print(event)- The SSE connection counts against the applicable license tier’s concurrent SSE limit, rather than the per-minute request limit.
- API keys use their organization’s license tier. JWT calls to this simulation-ID route use community limits without an explicit organization context.
- If you exceed the concurrent SSE limit, the server returns
429 Too Many Requests. - The
fetchexample ends when the server closes the stream. We recommend explicit reconnection handling. - The server sends no SSE event IDs and offers no replay of missed events.
- Before streaming starts, errors can return
401,403,404,429, or500. See HTTP Status Codes.