Skip to documentation

Ports

Run agents

Agents are the platform's reasoning layer: a durable harness that plans, calls KB and data tools, respects budgets and guardrails, and pauses for human approval on sensitive actions. The /api/v1/agents surface drives the exact same harness the UI uses. This guide queues a run, reattaches to its stream, reads the trace, resolves an approval, and records feedback.

Prerequisites

  • A key with agents:run (start/cancel/approve/feedback) and runs:read (inspect).
  • An agent published in the workspace, identified by its slug.
  • An enabled chat model — an unconfigured slot returns 409 no-model-configured.

Concepts first, if you want them: Agents & the harness and Tools, MCP & HITL.

Start a run

Runs are addressed by the agent's slug. The normal start returns HTTP 202 as soon as the queued run is the durable handoff record. Save both the id and the returned stream URL. The initial pg-boss send uses a stable identity; worker boot/minute reconciliation reconstructs the same pinned start if the request process or broker failed between row commit and queue acceptance.

POST/api/v1/agents/{slug}/runsBearer · agents:run

Persist and queue a durable run of the named agent.

Request body

inputrequiredstringThe task or question (min length 1).
conversationIdstringContinue an existing conversation for multi-turn context.
Example requestbash
curl -X POST https://your-host/api/v1/agents/budget-analyst/runs \
  -H "Authorization: Bearer $ELI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":"What changed in the FY26 budget?"}'
Responsejson
// HTTP 202
{ "runId": "01J…", "status": "queued", "stream": "/api/v1/runs/01J…/stream" }

Reattach with GET /api/v1/runs/{id}/stream and the runs:read scope. The stream replays persisted steps and then tails the database, so a disconnect or another web replica does not lose execution state.

GET /api/v1/runs/{id}/streamtext
data: {"type":"model_call","runId":"01J…","textLength":0,"toolCalls":1}
data: {"type":"tool_call","runId":"01J…","name":"kb_search","ok":true}
data: {"type":"final","runId":"01J…","status":"succeeded","text":"…","citations":[{"docId":"01J…","chunkId":"01J…"}]}

# terminal event is one of:
#   {"type":"final","runId","status","text","citations"}
#   {"type":"suspended","runId","approvalId","toolName"}
#   {"type":"error","message":"…"}   e.g. "no-model-configured"

Legacy inline SSE

Add ?stream=inline to the start URL only when an older client requires one in-request stream. It is an explicit compatibility path, not the durable default.

Terminal statuses

queued · running · succeeded · failed · budget_exceeded (graceful stop; text holds the partial answer) · interrupted · suspended (awaiting a human decision — resolve with /approve). Budget exhaustion is not an error: the run ends cleanly with what it has.

Inspect a run

Every run persists a full, ordered step trace — model calls, tool calls, guardrails, approvals, retries — with token and cost accounting. Read it to debug, to audit, or to show a user how the answer was reached.

GET/api/v1/runs/{id}Bearer · runs:read

Fetch a run and its ordered step trace. A run in another workspace is invisible under RLS → 404.

Example requestbash
curl -s https://your-host/api/v1/runs/$RUN_ID \
  -H "Authorization: Bearer $ELI_KEY"
Responsejson
{
  "run": {
    "id": "01J…",
    "status": "succeeded",
    "trigger": "api",
    "input": "What changed in the FY26 budget?",
    "output": { "text": "…", "citations": [  ] },
    "tokensIn": 4210, "tokensOut": 380,
    "costUsd": "0.021840",
    "apiKeyId": "01J…",
    "startedAt": "2026-07-21T14:03:11.204Z",
    "finishedAt": "2026-07-21T14:03:18.902Z"
  },
  "steps": [ { "idx": 0, "kind": "model_call", "status": "ok", "latencyMs": 1420 }, { "idx": 1, "kind": "tool_call", "name": "kb_search", "status": "ok" } ]
}

For just the steps, GET /api/v1/runs/{id}/steps. To stop a run in flight, POST /api/v1/runs/{id}/cancel — worker runs poll a cancel flag between steps and stop cooperatively.

Resolve an approval

When a run calls a tool marked requires approval, it suspends with an approvalId and waits — the human-in-the-loop gate. Record the decision; the server atomically queues a worker continuation and returns 202. Keep following the original run stream.

POST/api/v1/runs/{id}/approveBearer · agents:run

Resolve a suspended HITL approval and queue a durable continuation.

Request body

approvalIdrequiredstringThe approval to resolve (from the suspended event/result).
decisionrequired"allow" | "deny"Allow executes the tool; deny returns an error result to the model.
notestringOptional reviewer note, stored on the approval.
Example requestbash
curl -s -X POST https://your-host/api/v1/runs/$RUN_ID/approve \
  -H "Authorization: Bearer $ELI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"approvalId":"01J…","decision":"allow"}'
Responsejson
// HTTP 202
{ "runId": "01J…", "approvalId": "01J…", "status": "queued" }

Attach feedback

Close the loop by recording how a run did. Feedback is durable, attributed, and feeds evals and quality tracking.

POST/api/v1/runs/{id}/feedbackBearer · agents:run

Attach human feedback to a completed run. Returns 201 with the feedback id.

Request body

kindrequired"thumb" | "rating" | "correction" | "edit" | "citation_flag"The feedback kind.
valuejsonKind-specific payload, e.g. { "rating": 4 } or { "thumb": "up" }.
notestringOptional free-text note.
Example requestbash
curl -s -X POST https://your-host/api/v1/runs/$RUN_ID/feedback \
  -H "Authorization: Bearer $ELI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"thumb","value":{"thumb":"up"}}'
Responsejson
{ "id": "01J…" }   // HTTP 201

Reference & error handling

This guide is the task-oriented tour; the endpoint-by-endpoint reference with every field lives in Agents & runs (v1). All endpoints share the conventions in Errors & rate limits: 401 bad key, 403 missing scope/capability, 404 unknown/other-workspace run, 400 invalid body, 402 monthly spend admission, and 429 active-run admission.

The leverage

You are not calling a chat completion — you are triggering a governed, auditable worker that reasons over your knowledge graph and live data, stops for a human before it does anything risky, and leaves a complete trace behind. Wire it to a webhook, a queue, or a schedule and every automated decision comes with its own receipt. Every keyed run is attributed to its API key and counts against the workspace budgets, so automation never runs away with your spend.