> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upsonic.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# API overview

> Authentication, environments, roles, errors, pagination and streaming for the AgentOS HTTP API.

Everything you can do in the AgentOS panel — deploy agents, start runs, decide approvals, run evals, read memory and the audit log — is also an HTTP API under `/v0`. This section is the reference for callers: your backend, scripts and CI.

> [!NOTE]
>
> Agents themselves talk to a different set of routes with their **run token** (`x-agentos-run-token`): holds, state, memory, files, events, child runs and results. Those are described with the agent contract in [Build](https://docs.upsonic.ai/agentos/build/agent-contract.md).

## Base URL

Every route lives under your installation's address plus `/v0`:

```bash theme={null}
export AGENTOS=https://agentos.example.com
export AGENTOS_API_KEY=aos_...

curl -sS -H "Authorization: Bearer $AGENTOS_API_KEY" $AGENTOS/v0/envs/default/agents
```

Most routes name an **environment** in the path: `/v0/envs/{env}/…`, where `{env}` is the environment's name (`default`, `staging`, `prod`…). An object of another environment is a `404` there, even when you can see it elsewhere. A few routes are addressed by an id that already belongs to one environment, such as `/v0/deploys/{deploy_id}`.

The OpenAPI description is at `/v0/openapi.json`, browsable at `/v0/docs`. Both need you to be signed in to the panel.

## Authentication

Every request carries an API key. Scripts and other systems use a **service account**: a tenant admin creates one on the **Users** page, gives it a role in each environment it calls, and issues an API key. The key is shown once.

```bash theme={null}
curl -sS -H "Authorization: Bearer aos_..." $AGENTOS/v0/envs/default/agents
```

Revoking the key or deactivating the service account takes effect at once. See [Users and API keys](https://docs.upsonic.ai/agentos/platform/users-and-api-keys.md).

A request without a valid key answers `401 unauthorized`.

## Roles

Access is decided per environment. Without any role there, every route of that environment answers `403 forbidden`.

| You need | To |
| - | - |
| **Any role** (member or admin) | Read agents, versions, deploys, runs, holds, sessions, files, datasets, evals, experiments and memory. |
| **Member or admin** | Start and cancel runs, create sessions, upload files, edit datasets, evaluators and evals, start and cancel experiments. |
| **Admin** | Deploy and promote versions, make a candidate from an experiment, set a dataset's collect rule, delete and erase memory, read the audit log. |
| **An approver role of the capability** | Decide a hold. A capability's `approvers` in [agentos.yaml](https://docs.upsonic.ai/agentos/build/agentos-yaml.md) say which roles may, `[admin, member]` by default. |

## Errors

Every error under `/v0` has the same JSON shape:

```json theme={null}
{"code": "not_found", "message": "No such agent."}
```

A `422` also lists every problem it found, one per field:

```json theme={null}
{"code": "invalid_request", "message": "The request is invalid.",
 "errors": [{"field": "input.message", "message": "required"},
            {"field": "limit", "message": "unknown query parameter"}]}
```

Some errors carry more keys, such as `deploy_id` on a refused upload or `keys` on a `config_mismatch`; each page lists them. Branch on `code`, not on `message`: messages are written for people and may change.

| Status | Common codes |
| - | - |
| `400` | A decision that doesn't match its hold (`unknown_item`, `missing_item`…) |
| `401` | `unauthorized`: no session or API key, or a revoked one |
| `403` | `forbidden`: no role in the environment, or not the role this action needs |
| `404` | `not_found`: no such environment, agent, run, hold… (also an unknown route) |
| `405` | `method_not_allowed` |
| `409` | A conflict with the current state: `deploy_busy`, `session_busy`, `already_decided`, `run_finished`… |
| `413` | `too_large`: a body over the route's limit |
| `415` | `unsupported_media_type` |
| `422` | `invalid_request` (with `errors`), and route-specific codes such as `invalid_bundle` or `blocked_by_guardrail` |
| `503` | `unavailable` / `storage_unavailable`: try again later |

A body that isn't valid JSON, contains `NaN` or `Infinity`, has a number too large to represent, or has a NUL character (`\u0000`) in a string is a `422 invalid_request`.

## Unknown query parameters

Query parameters a route doesn't know are refused with `422`, naming each one, so a misspelt filter never silently returns everything:

```json theme={null}
{"code": "invalid_request", "message": "The request is invalid.",
 "errors": [{"field": "stauts", "message": "unknown query parameter"}]}
```

## Pagination

Lists are newest first and take `limit` and `before`. Pass the id of the last item you received as `before` to get the next page:

```bash theme={null}
curl -sS -H "Authorization: Bearer $AGENTOS_API_KEY" "$AGENTOS/v0/envs/default/agents/hello-agent/runs?limit=50"
curl -sS -H "Authorization: Bearer $AGENTOS_API_KEY" "$AGENTOS/v0/envs/default/agents/hello-agent/runs?limit=50&before=r_812"
```

A page shorter than `limit` is the last one. Memory and the audit log page with a `next` value in the answer instead; their pages say how.

## Idempotency

Starting a run takes an optional `Idempotency-Key` header (up to 200 characters). The same key from the same caller with the same body returns the same run instead of starting a second one, so a retry after a network error is safe. Reusing a key with a different body is a `409 idempotency_key_reused`. See [Runs](https://docs.upsonic.ai/agentos/api/runs.md#idempotency).

## Server-sent events

Deploys and runs can be followed live as [server-sent events](https://html.spec.whatwg.org/multipage/server-sent-events.html):

```bash theme={null}
curl -sS -N -H "Authorization: Bearer $AGENTOS_API_KEY" $AGENTOS/v0/envs/default/runs/r_13/events
```

```text theme={null}
id: 1
event: run.queued
data: {"seq": 1, "type": "run.queued", "at": "2026-10-27T09:00:00.120Z", "data": {}}

id: 2
event: run.started
data: {"seq": 2, "type": "run.started", "at": "2026-10-27T09:00:00.310Z", "data": {...}}
```

Each event has an `id` (its sequence number), an `event` (its type) and `data` (`{seq, type, at, data}`). The stream ends after the final event (`deploy.finished`, or `run.completed` / `run.failed` / `run.cancelled`). To resume after a dropped connection, reconnect with the header `Last-Event-ID: <the last id you saw>`; the stream replays what came after it. Once you have seen the final event, the route answers `204`, so a browser `EventSource` stops reconnecting.

## Endpoints

| Area | Method and path | |
| - | - | - |
| **Deploys** | `GET /v0/envs/{env}/agents` | [List agents](https://docs.upsonic.ai/agentos/api/deploys.md#list-agents) |
| | `GET /v0/envs/{env}/agents/{agent}` | [Get an agent](https://docs.upsonic.ai/agentos/api/deploys.md#get-an-agent) |
| | `POST /v0/envs/{env}/agents/{agent}/versions` | [Upload a version](https://docs.upsonic.ai/agentos/api/deploys.md#upload-a-version) |
| | `POST /v0/envs/{env}/agents/{agent}/versions/{version}/promote` | [Promote a version](https://docs.upsonic.ai/agentos/api/deploys.md#promote-a-version) |
| | `GET /v0/envs/{env}/agents/{agent}/deploys` | [List deploys](https://docs.upsonic.ai/agentos/api/deploys.md#list-deploys) |
| | `GET /v0/deploys/{deploy_id}` | [Get a deploy](https://docs.upsonic.ai/agentos/api/deploys.md#get-a-deploy) |
| | `GET /v0/deploys/{deploy_id}/events` | [Follow a deploy](https://docs.upsonic.ai/agentos/api/deploys.md#follow-a-deploy) |
| **Runs** | `POST /v0/envs/{env}/agents/{agent}/capabilities/{capability}/runs` | [Start a run](https://docs.upsonic.ai/agentos/api/runs.md#start-a-run) |
| | `GET /v0/envs/{env}/runs/{run_id}` | [Get a run](https://docs.upsonic.ai/agentos/api/runs.md#get-a-run) |
| | `GET /v0/envs/{env}/agents/{agent}/runs` | [List runs](https://docs.upsonic.ai/agentos/api/runs.md#list-runs) |
| | `GET /v0/envs/{env}/runs/{run_id}/events` | [Follow a run](https://docs.upsonic.ai/agentos/api/runs.md#follow-a-run) |
| | `POST /v0/envs/{env}/runs/{run_id}/cancel` | [Cancel a run](https://docs.upsonic.ai/agentos/api/runs.md#cancel-a-run) |
| **Holds** | `GET /v0/envs/{env}/holds` | [List holds](https://docs.upsonic.ai/agentos/api/holds.md#list-holds) |
| | `GET /v0/envs/{env}/holds/{hold_id}` | [Get a hold](https://docs.upsonic.ai/agentos/api/holds.md#get-a-hold) |
| | `POST /v0/envs/{env}/holds/{hold_id}/decision` | [Decide a hold](https://docs.upsonic.ai/agentos/api/holds.md#decide-a-hold) |
| **Sessions** | `POST /v0/envs/{env}/sessions` | [Create a session](https://docs.upsonic.ai/agentos/api/sessions.md#create-a-session) |
| | `GET /v0/envs/{env}/sessions/{session_id}` | [Get a session](https://docs.upsonic.ai/agentos/api/sessions.md#get-a-session) |
| **Memory** | `GET /v0/envs/{env}/agents/{agent}/memory/facts` | [List or search facts](https://docs.upsonic.ai/agentos/api/memory.md#list-or-search-facts) |
| | `GET /v0/envs/{env}/agents/{agent}/memory/facts/{fact_id}` | [Get a fact](https://docs.upsonic.ai/agentos/api/memory.md#get-a-fact) |
| | `GET /v0/envs/{env}/agents/{agent}/memory/facts/{fact_id}/versions` | [Get a fact's versions](https://docs.upsonic.ai/agentos/api/memory.md#get-a-facts-versions) |
| | `DELETE /v0/envs/{env}/agents/{agent}/memory/facts/{fact_id}` | [Delete a fact](https://docs.upsonic.ai/agentos/api/memory.md#delete-a-fact) |
| | `POST /v0/envs/{env}/agents/{agent}/memory/erase` | [Erase a path](https://docs.upsonic.ai/agentos/api/memory.md#erase-a-path) |
| | `POST /v0/envs/{env}/memory/erase-user` | [Erase an end user](https://docs.upsonic.ai/agentos/api/memory.md#erase-an-end-user) |
| **Files** | `POST /v0/envs/{env}/files` | [Upload a file](https://docs.upsonic.ai/agentos/api/files.md#upload-a-file) |
| | `GET /v0/envs/{env}/files/{file_id}` | [Download a file](https://docs.upsonic.ai/agentos/api/files.md#download-a-file) |
| **Evals** | `/v0/envs/{env}/datasets…` | [Datasets and items](https://docs.upsonic.ai/agentos/api/evals.md#datasets) |
| | `/v0/envs/{env}/evaluators…` | [Evaluators](https://docs.upsonic.ai/agentos/api/evals.md#evaluators) |
| | `/v0/envs/{env}/evals…` | [Evals](https://docs.upsonic.ai/agentos/api/evals.md#evals) |
| | `/v0/envs/{env}/experiments…` | [Experiments](https://docs.upsonic.ai/agentos/api/evals.md#experiments) |
| **Audit** | `GET /v0/envs/{env}/audit` | [Read the audit log](https://docs.upsonic.ai/agentos/api/audit.md#read-the-audit-log) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.