Using the API
Pagination and streaming
Walk long lists with opaque cursors, and follow runs, sessions and tasks live over Server-Sent Events.
Two things grow without bound on a platform where agents work all day: lists of things, and the events of work in progress. Lists come back a page at a time behind a cursor. Work in progress is streamed as Server-Sent Events (SSE), which you can resume after a dropped connection without missing anything.
Cursor pagination
Most lists take limit and cursor and answer in this shape:
{
"items": [ ],
"cursor": "<opaque>",
"has_more": true
}
To read the next page, send the cursor you were given:
curl "https://api.snaga.ai/api/v1/runs?limit=50&cursor=<cursor>" \
-H "Authorization: Bearer $SNAGA_API_KEY"
Rules worth knowing:
- The cursor is opaque. Do not build or edit one; pass back exactly what
you received. It cannot be used to jump to the far end of a list. A cursor
the API did not issue is refused with 422,
code: INVALID_CURSOR. has_moredecides when to stop. On the last page it isfalseandcursorisnull.limitis clamped, not refused. Each list has its own default and maximum — for example agents default to 20 and sessions to 50, both capped at 100. A value out of range is pulled into range.- Order is part of the contract. Runs come newest first. If you want the
oldest, ask for
order=ascinstead of paging to the end.
A few lists are small enough to return whole, with a total and no cursor —
GET /api/v1/integrations is one. Each operation in the
API reference says which form it uses.
The SDKs walk cursors for you; see Streaming and pagination.
Server-Sent Events
Event streams are long-lived GET requests answered as text/event-stream.
Each event has an id, an event name and JSON data. The main streams:
| Stream | What it carries |
|---|---|
GET /api/v1/runs/{runId}/events | One run: lifecycle, model output, tool calls. |
GET /api/v1/sessions/{sessionId}/events | Every run in one conversation. |
GET /api/v1/notifications/stream | Your notifications. |
GET /api/v1/missions/{missionId}/events | One mission. |
GET /api/v1/initiatives/{initiativeId}/events | One initiative. |
GET /api/v1/a2a/tasks/{taskId}/events | One A2A task's status. |
Following a run
curl -N https://api.snaga.ai/api/v1/runs/<run_id>/events \
-H "Authorization: Bearer $SNAGA_API_KEY"
Every run event arrives under its own name — event: llm.chunk,
event: tool.call and so on — and its data carries stream_type
(lifecycle, assistant, tool or other) so you can filter. The stream
ends when the run reaches a final status:
- an
event: doneframe with the run'sstatus,output,metricsandcost_usd— close on this, not onrun.completed; - then a bare
data: [DONE]line for readers written for OpenAI-style streams.
Two other frames are worth handling. gap means the server dropped some
non-essential events (chiefly llm.chunk) under backpressure; tool, approval,
input and document events are never dropped. error means the buffer
saturated and the server closed the stream — reconnect.
Resuming after a drop
Send the id of the last event you saw as Last-Event-ID; the server replays
everything strictly after it. A browser's EventSource does this for you on
reconnect.
On the session stream, event ids look like <runId>:<seq>. New event names
can appear over time; ignore the ones you do not know.
Streams in the browser
EventSource cannot send an Authorization header. Rather than put a full
API key in a URL, mint a short-lived token:
curl -X POST https://api.snaga.ai/api/v1/auth/sse-tokens \
-H "Authorization: Bearer $SNAGA_API_KEY"
The answer has a token and its expires_at — it lives 60 seconds. Pass
it as ?token=:
const source = new EventSource(
`https://api.snaga.ai/api/v1/runs/${runId}/events?token=${token}`,
);
source.addEventListener("done", () => source.close());
The token carries only the read scopes you already hold for streams
(sessions:read, runs:read, agents:read, notifications:read) and works
only for GET on event streams. Any other request presenting it is refused.
Because it is short-lived, mint a fresh one each time you open a stream.
Related
- Runs — what the events of a run mean.
- Requests and errors — rate limits and retries.
- API reference — each list's limits and each stream's events.