Run API
The Run API is the canonical HTTP surface for run/task management.
Unlike protocol adapters (ag-ui, ai-sdk, a2a), this API exposes a stable transport-neutral run model.
Prerequisites
- Server must include
http::run_routes().
Endpoints
GET /v1/runsGET /v1/runs/:idPOST /v1/runsPOST /v1/runs/:id/inputsPOST /v1/runs/:id/cancel
Run Record Model
GET /v1/runs/:id returns RunRecord:
{
"run_id": "run-1",
"thread_id": "thread-1",
"agent_id": "assistant",
"parent_run_id": "run-0",
"parent_thread_id": "thread-0",
"origin": "ag_ui",
"status": "done",
"termination_code": "input_required",
"termination_detail": "approval needed",
"created_at": 1760000000000,
"updated_at": 1760000005000,
"metadata": null
}
origin:
usersubagentag_uiai_sdka2ainternal
status:
runningwaitingdone
List Runs
GET /v1/runs query params:
offset(default0)limit(clamped1..=200, default50)thread_idparent_run_idstatusorigintermination_codecreated_at_from,created_at_to(unix millis, inclusive)updated_at_from,updated_at_to(unix millis, inclusive)
Example:
curl 'http://127.0.0.1:8080/v1/runs?thread_id=t1&status=done&origin=ag_ui&limit=20'
Start Run
POST /v1/runs starts a run and streams canonical SSE events.
Minimal payload:
{
"agentId": "assistant",
"messages": [{ "role": "user", "content": "hello" }]
}
All accepted fields:
agentId/agent_id(required)threadId/thread_id/contextId/context_id(optional — generated if absent)runId/run_id/taskId/task_id(optional — generated if absent)parentRunId/parent_run_id(optional — links this run to a parent run for lineage tracking)parentThreadId/parent_thread_id/parentContextId/parent_context_id(optional — links to a parent thread)resourceId/resource_id(optional — associates the run with a resource identifier)state(optional JSON object — initial state to merge into the thread before the run starts)messages(optional array — user messages to start the run with)initialDecisions/initial_decisions/decisions(optional array — pre-resolved tool call decisions)
Example:
curl -N \
-H 'content-type: application/json' \
-d '{"agentId":"assistant","threadId":"thread-1","messages":[{"role":"user","content":"hello"}]}' \
http://127.0.0.1:8080/v1/runs
Push Inputs
POST /v1/runs/:id/inputs has two modes.
- Decision forwarding (active run):
{
"decisions": [
{
"target_id": "fc_perm_1",
"decision_id": "d1",
"action": "resume",
"result": { "approved": true },
"updated_at": 1760000000000
}
]
}
Response (202):
{
"status": "decision_forwarded",
"run_id": "run-1",
"thread_id": "thread-1"
}
- Continuation run (messages provided):
{
"agentId": "assistant",
"messages": [{ "role": "user", "content": "continue" }],
"decisions": []
}
Response (202):
{
"status": "continuation_started",
"parent_run_id": "run-1",
"thread_id": "thread-1"
}
Rules:
messagesanddecisionscannot both be empty.- If
messagesis present,agentIdis required. - Decision-only forwarding requires the target run to be active.
Cancel Run
POST /v1/runs/:id/cancel
Response (202):
{
"status": "cancel_requested",
"run_id": "run-1"
}
If run exists but is not active: 400 (run is not active).
Errors
Common API errors:
404:run not found: <id>404:agent not found: <id>400: input validation failures500: internal errors (including uninitialized run service)
Error body shape:
{ "error": "bad request: messages and decisions cannot both be empty" }