Platform concepts
Runs
A run is one piece of work an agent does — how to start one, follow it live, answer it when it stops for you, and pick it up again.
Every time an agent works, the platform records a run: the input, each step, the tools called, the cost and the result. Chat messages, schedules, missions and inbound webhooks all start runs, and so can you, through the API. Runs are asynchronous: creating one queues it and answers at once, and you follow the work by streaming its events, waiting on it, or reading it back.
The life of a run
A run's status tells you where it is.
| Status | What it means |
|---|---|
queued | Accepted and waiting to execute. |
running | The agent is working. |
paused | Stopped at a step boundary until someone resumes it. |
awaiting_approval | A tool call needs a person's decision before it goes ahead. |
awaiting_input | The agent asked a question and is waiting for the answer. |
completed | Finished; output holds the result. |
failed, cancelled, timeout, guardrail_blocked | Ended without a normal result; error_code says why. |
Start a run
Send the agent's id and an input. message is the conventional field;
file_ids attaches up to 20 files you uploaded earlier.
curl -X POST https://api.snaga.ai/api/v1/runs \
-H "Authorization: Bearer $SNAGA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"agent_id": "<agent_id>",
"input": { "message": "Summarise this week's support tickets" },
"resource_limits": { "max_steps": 20, "max_cost_usd": 1.5 }
}'
The answer is 202 with the run and its run_id. The Idempotency-Key
makes a retried request return the same run instead of a second one.
version pins a specific agent version instead of the current one.
resource_limits tightens this run's limits — max_duration_ms,
max_steps, max_tool_calls, max_tokens_per_run, max_cost_usd — and any
other key is refused with 422. A run that crosses max_cost_usd fails with
error_code: BUDGET_EXCEEDED.
To see what a run is likely to cost before starting it, call
POST /api/v1/runs/estimate. It looks at the agent's recent runs and stores
nothing. When it answers pricing: "unknown", the 0 it returns means "no
known rate", not "free".
Follow it live
GET /api/v1/runs/{runId}/events is a server-sent event stream. Each frame's
event name is the event type (run.started, llm.chunk, tool.call,
run.completed …), its id is the event's sequence number, and its data
carries a stream_type you can filter on: lifecycle, assistant (the
streamed text), tool or other.
curl -N https://api.snaga.ai/api/v1/runs/<run_id>/events \
-H "Authorization: Bearer $SNAGA_API_KEY"
If the connection drops, reconnect with the Last-Event-ID header and
the stream continues from there. When the run ends the
server sends a final done event and closes the stream.
A browser EventSource cannot set an Authorization header. Mint a
short-lived token with POST /api/v1/auth/sse-tokens (valid for 60 seconds)
and pass it as ?token=.
Prefer not to stream?
GET /api/v1/runs/{runId}/wait?timeout_sec=60returns the run as soon as it ends. If time runs out first it answers202withstatus: still_running— call it again.GET /api/v1/runs/{runId}returns the run at any moment.
When a run stops for you
Some tools need a person's approval, and an agent can ask a question. In both
cases the run waits, and GET /api/v1/runs/{runId} tells you what it is
waiting for, so a client can rebuild the prompt even if its stream dropped.
awaiting_approval — the run carries pending_approvals: each blocked
tool call with its name and args. You have three answers:
| Call | Effect |
|---|---|
POST /api/v1/runs/{runId}/approve | The action goes ahead. The body is optional; response passes a note to the agent. |
POST /api/v1/runs/{runId}/revise | The action is not carried out; feedback (required) tells the agent what to change, and the run continues. |
POST /api/v1/runs/{runId}/reject | The action is refused and the run ends as failed with error_code: approval_rejected. |
Each decision is recorded in the run's approvals; see Approvals.
awaiting_input — the run carries pending_input with the question,
any options and context. Answer it:
curl -X POST https://api.snaga.ai/api/v1/runs/<run_id>/respond \
-H "Authorization: Bearer $SNAGA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "response": "Use the EU price list" }'
The run goes back to the queue and continues.
Pause, resume, cancel
POST /api/v1/runs/{runId}/pausestops arunningrun at its next step boundary. A step already in flight finishes first.POST /api/v1/runs/{runId}/resumeputs it back in the queue. The body is optional;input.notereaches the agent as a message from you.POST /api/v1/runs/{runId}/cancelstops it for good. It always answers200—cancelled: falsemeans there was nothing to stop — so repeating it is safe.
Continuing a run that ran out of steps
A run that hits its step budget finishes with output.truncated: true. When
the platform can sign one, output also carries a continuation_token; pass
it back to pick up where the run stopped:
curl -X POST https://api.snaga.ai/api/v1/runs/<run_id>/continue \
-H "Authorization: Bearer $SNAGA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "continuation_token": "<token>" }'
This is different from output.output_truncated, which means the model ran
out of output tokens mid-answer.
POST /api/v1/runs/{runId}/checkpoint marks a checkpoint on a running run
without disturbing it; GET /api/v1/runs/{runId}/checkpoints lists them.
Looking back at a run
| Call | What you get |
|---|---|
GET /api/v1/runs | Runs in your company, newest first; filter by agent_id, session_id, status. |
GET /api/v1/runs/{runId}/steps | Each step with its tokens, cost and tool calls. |
GET /api/v1/runs/{runId}/sources | The links the agent read or found, which ones the answer cites, and unsourced_links to check first. |
GET /api/v1/runs/{runId}/artifacts | Files the run produced. |
GET /api/v1/runs/{runId}/events/export | The whole event log as JSON lines. |
See also Pagination and streaming and the API reference.