Docs contents
HTTP API reference
Exact request/response shapes for the AgentOS HTTP API. For when to use each, read the concepts first: Invoking hosted agents and Reporting runs.
- Base URL:
https://agentos-ai.dev - Auth:
Authorization: Bearer <key>. Ingest and invoke accept an agent key (aos_agent_…, limited to its own agent) or a workspace key (aos_ws_…). See Authentication. - Envelope: every JSON response is
{ "data": …, "error": … }, with exactly one of the two set. Streaming invokes (stream: true) returntext/event-streaminstead.
Ingest API
Report runs your own code executes (non-hosted agents). Guide: Reporting runs.
Start a run
POST /api/ingest/v1/run/start
{
"agent_id": "uuid",
"trigger_type": "sdk",
"input": { "query": "Hello" },
"external_run_id": "optional-correlation-id",
"parent_run_id": "uuid"
}
| Field | Type | Notes |
|---|---|---|
agent_id | uuid | Required. An agent key must match its own agent. |
trigger_type | "manual" | "scheduled" | "webhook" | "sdk" | Default "sdk". |
input | object | Default {}. |
external_run_id | string | Optional, up to 128 characters. Idempotent: starting again with the same id returns the existing run. |
parent_run_id | uuid | Optional. Links this run as a child of another run in the workspace. |
Paused or archived agents return 403 FORBIDDEN.
Response
{ "data": { "run_id": "uuid" }, "error": null }
Emit events
POST /api/ingest/v1/events
{
"run_id": "uuid",
"events": [
{
"type": "step.completed",
"level": "info",
"payload": { "step": "fetch-data", "rows": 42 },
"occurred_at": "2026-05-11T20:00:00.000Z"
}
]
}
Send 1 to 500 events per request. level is "debug" | "info" | "warn" | "error" (default "info"). See Events.
To make an event a node in the run's trace tree, add span fields: span_id, parent_span_id, kind, started_at, ended_at and duration_ms (derived from the timestamps when omitted). See Tracing & spans.
Response (HTTP 202)
{ "data": { "accepted": 1, "run_id": "uuid" }, "error": null }
Complete a run
POST /api/ingest/v1/run/complete
{
"run_id": "uuid",
"output": { "result": "Done" },
"input_tokens": 1200,
"output_tokens": 350,
"cache_read_tokens": 0,
"cache_creation_tokens": 0
}
Token counts are optional and feed the cost views.
Fail a run
POST /api/ingest/v1/run/fail
{
"run_id": "uuid",
"error_message": "Something went wrong",
"error_detail": { "step": "fetch" }
}
Cancel a run
POST /api/ingest/v1/run/cancel
{ "run_id": "uuid", "reason": "User aborted" }
reason is optional. Cancelling also cancels any pending human input request on the run.
Response (complete, fail and cancel)
{ "data": { "run_id": "uuid", "duration_ms": 5000 }, "error": null }
Repeating the same call on a finished run is safe and returns the same shape. Closing a run that already ended with a different status returns 409 CONFLICT.
Create / update a task
POST /api/ingest/v1/tasks
{
"run_id": "uuid",
"task": {
"id": "uuid",
"name": "parse-pdf",
"status": "running",
"input": { "file": "report.pdf" }
}
}
status: "pending" | "running" | "completed" | "failed" | "skipped". Call again with the same id and a terminal status (plus output or error_message) to update. See Tasks.
Response
{ "data": { "task_id": "uuid" }, "error": null }
Ask a human
POST /api/ingest/v1/human-input/request
{
"run_id": "uuid",
"prompt": "Approve the refund for order #1234?",
"context": { "amount": 120 },
"timeout_seconds": 3600
}
A long poll: the request waits for someone to answer in the dashboard. timeout_seconds is 30 to 86400 (default 3600).
| Status | Body | Meaning |
|---|---|---|
| 200 | { "input": …, "request_id": "uuid" } | Answered. |
| 202 | { "request_id": "uuid", "status": "pending" } | Still waiting after about 4.5 minutes. Call again with the same body plus request_id to keep waiting. |
| 408 | TIMEOUT | No answer before timeout_seconds. |
| 409 | CONFLICT | The request or run was cancelled. |
The SDKs handle the retry for you.
Send OpenTelemetry traces
POST /api/ingest/v1/traces
Accepts OTLP/JSON trace exports, up to 1000 spans per request. Each trace becomes a run. With a workspace key, set the agentos.agent_id resource attribute. Returns 202 with { "accepted": <spans>, "runs": <runs> }. See Tracing & spans.
Invoke API
Ask AgentOS to run a hosted agent and return its output. Guide: Invoking hosted agents.
Invoke a hosted agent
POST /api/v1/agents/:agentId/invoke
Requires a workspace key or an agent key for that agent. Only works on hosted agents.
{
"input": { "query": "Summarise this" },
"prompt_variables": { "SHEET_ID": "1pjdT1FADq-..." },
"session_id": "uuid",
"stream": false,
"parent_run_id": "uuid"
}
| Field | Type | Notes |
|---|---|---|
input | object | Defaults to {}. |
prompt_variables | { KEY: string } | Optional; fills {{KEY}} placeholders. Prompt variables. |
session_id / start_session | uuid / bool | Server-managed conversation memory. Memory. |
external_user_id | string | Your id for the session's end user; only with session_id or start_session. |
history | array | Client-managed history, up to 50 { role, content } turns. |
parent_run_id | uuid | Link as a child run (agent-to-agent). |
stream | boolean | Return a text/event-stream instead of JSON. |
test | boolean | Sandboxed test run: tools do not act, and the run is left out of metrics and alerts. Allowed on paused agents. |
session_id, start_session and history are mutually exclusive.
Response: completed
{ "data": { "run_id": "uuid", "output": { "summary": "…" }, "duration_ms": 4200, "session_id": "uuid" }, "error": null }
session_id is present only when the call used a session.
Response: paused (HTTP 202)
{ "data": { "run_id": "uuid", "awaiting_approval": { "approval_id": "uuid" }, "output": null, "duration_ms": 1800 }, "error": null }
{ "data": { "run_id": "uuid", "awaiting_input": { "request_id": "uuid", "question": "…", "options": ["…"] }, "output": null, "duration_ms": 1800 }, "error": null }
awaiting_input.question is always present; context and options only when the agent provided them.
Streaming
With stream: true the response is text/event-stream. Each frame is data: <json>, where the JSON has a type:
type | Fields | When |
|---|---|---|
start | run_id | The run was created. |
chunk | text | Output text. Not sent for agents with an output schema. |
tool | name, status (calling | returned | failed) | A tool call started or finished. |
done | run_id, duration_ms, session_id? | Terminal: the run finished. |
awaiting_approval | run_id, duration_ms, approval_id, session_id? | Terminal: paused for approval. |
awaiting_input | run_id, duration_ms, request_id, question, context?, options?, session_id? | Terminal: paused for human input. |
error | message, code | Terminal: the run failed. |
Answer a paused run
When an invoke returns awaiting_input, send the answer to resume the run. Both endpoints require a workspace key.
POST /api/v1/runs/:runId/reply
{ "request_id": "uuid", "response": "Yes, go ahead." }
POST /api/v1/runs/:runId/human-input
{ "response": "Yes, go ahead." }
/human-input finds the pending request for you. response is up to 10,000 characters. Both return the same shapes as invoke: 200 when the run completes, or 202 if it pauses again. /reply returns 409 CONFLICT if the request was already answered.
Control plane
POST /api/v1/rpc/:method
Every MCP tool (agents_list, runs_invoke, alerts_create, …) as plain JSON over HTTP. The body is the tool's arguments; the response is { data, error }. Requires a workspace or personal key; with a personal key, include "workspace": "<slug or id>" in the body. Unknown methods return 404 UNKNOWN_METHOD. Full catalog: Control plane.
curl -X POST https://agentos-ai.dev/api/v1/rpc/agents_list \
-H "Authorization: Bearer aos_ws_..." \
-H "Content-Type: application/json" \
-d '{ "status": "active" }'
Rate limits
Limits apply per workspace, per 60-second window. Run starts and invokes count against runs; each event or span counts against events.
| Plan | Runs / min | Events / min |
|---|---|---|
| Solo | 200 | 1,200 |
| Operations | 200 | 1,200 |
| Evolution | 400 | 2,400 |
| Enterprise | 1,000 | 6,000 |
Over the limit, the API returns 429 RATE_LIMITED with a Retry-After header (seconds). A workspace with no plan gets 402 NO_PLAN.
Error responses
{ "data": null, "error": { "code": "UNAUTHENTICATED", "message": "Invalid or revoked key." } }
| Code | HTTP | Meaning |
|---|---|---|
VALIDATION_ERROR | 400 | Bad request payload, or invoking a non-hosted agent |
UNAUTHENTICATED | 401 | Missing, invalid, revoked or expired key |
NO_PLAN | 402 | The workspace has no plan |
FORBIDDEN | 403 | Key scoped to a different agent or not allowed on this endpoint; agent archived; run started on a paused agent |
AGENT_PAUSED | 403 | Invoking a paused agent (use test: true for a test run) |
WORKSPACE_SUSPENDED | 403 | The workspace is suspended |
NOT_FOUND | 404 | Agent, run or session not found |
TIMEOUT | 408 | A human input request timed out |
CONFLICT | 409 | Run already ended with a different status, or request already answered |
RATE_LIMITED | 429 | Too many requests; see Retry-After |
INTERNAL_ERROR | 500 | Unexpected server error |
Invoke, reply and human-input return 400 with one of these codes when the hosted run itself fails:
| Code | Meaning |
|---|---|
INVALID_AGENT | The agent or run can't be run or resumed as asked (for example, no system prompt, or the request was already answered) |
LLM_ERROR | The model provider returned an error |
OUTPUT_PARSE_ERROR | The output did not match the agent's output schema |
MAX_ITERATIONS | The agent hit its iteration limit |
OUTPUT_TRUNCATED | The model hit the agent's max tokens before finishing |
CANCELLED | The run was cancelled |