> Documentation index: [/llms.txt](/llms.txt). Every page as one file: [/llms-full.txt](/llms-full.txt).

# Run an agent and stream its events

Run an agent and stream its events [#run-an-agent-and-stream-its-events]

Send an AG-UI `RunAgentInput` body to a run route and read the AG-UI events it streams back.

Endpoints [#endpoints]

All paths start with `/api/v1/agents-v2` and need `X-Space-Slug`.

| Method           | URL                                                        | Does                                                                                                                  | Auth          |
| ---------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------- |
| `POST`           | `/agents/{agent_id}/run-stream/`                           | Run that agent; the response is the event stream                                                                      | Key or bearer |
| `POST`           | `/agents/run-stream/`                                      | Run the workspace's default agent                                                                                     | Key or bearer |
| `POST`           | `/agents/run-stream/?default=false`                        | Run the inline config in `forwardedProps.runtimeConfig`, with no agent row                                            | Key or bearer |
| `POST`           | `/runs/`                                                   | Start a background run of `?agent_id=` (omitted: the default agent); returns `{run_id, thread_id, chat_id, agent_id}` | Key or bearer |
| `GET`            | `/runs/{run_id}/events/?last_id=`                          | Stream a background run's events from after `last_id` (default `0`, the start)                                        | Key or bearer |
| `POST`           | `/runs/{run_id}/cancel/`                                   | Cancel a background run; `204`                                                                                        | Key or bearer |
| `GET`            | `/runs/{run_id}/history/`                                  | The events so far: `{events, last_event_id, status}`                                                                  | Key or bearer |
| `GET`            | `/runs/by-thread/{thread_id}/`                             | The thread's latest background run: `{run_id, status}`                                                                | Key or bearer |
| `GET`            | `/runs/by-thread/{thread_id}/history/`                     | `{run_id, events, last_event_id, status}` for that run                                                                | Key or bearer |
| `POST`           | `/files/upload/`                                           | Upload an attachment                                                                                                  | Key or bearer |
| `GET`            | `/agents/{agent_id}/sandbox/files/presigned-url/`          | Download link for a generated file                                                                                    | Key or bearer |
| `POST`           | `/agents/{agent_id}/sandbox/skills/resync/`                | Copy the agent's current skills into its sandbox; `204`                                                               | Key or bearer |
| `GET`            | `/agents/default/`                                         | The workspace's default agent, the one `/agents/run-stream/` runs                                                     | Key or bearer |
| `GET` · `DELETE` | `/agents/{agent_id}/sandbox/files/?thread_id=` · `…&path=` | List a chat's sandbox files · delete one                                                                              | Bearer only   |
| `DELETE`         | `/agents/{agent_id}/sandbox/files/clean/`                  | Empty `/home/user/` in the caller's sandbox for this agent                                                            | Bearer only   |

* The `/runs/` routes need background runs enabled on the server; otherwise they return `404 Background agent runs are disabled.`
* Background run events are kept for a limited time after the run ends.

Chat history [#chat-history]

| Route                                      | History                                         |
| ------------------------------------------ | ----------------------------------------------- |
| `/agents/{agent_id}/run-stream/`, `/runs/` | Saved to a chat; `?save_history=false` skips it |
| `/agents/run-stream/`                      | Always saved                                    |
| `/agents/run-stream/?default=false`        | Never saved                                     |

* Saved history is a chat; the chat routes are bearer only ([Read and share chats](chats)). With an API key, read a background run's events through `/runs/{run_id}/history/`, or an agent's chats through [Lab](../lab/overview) with the `lab` scope.
* To continue a conversation, reuse its `threadId`. With saved history the server replays the stored conversation and uses only the last user message from `messages`.
* With `?save_history=false` or an inline config nothing is stored: send the whole conversation in `messages` on every run.

Request fields [#request-fields]

Every top-level key is required: `threadId`, `runId`, `state`, `messages`, `tools`, `context` and `forwardedProps`.

| Field                                        | Rule                                                                                                                                                                                                      |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `forwardedProps.mode`                        | `"act"` (default) or `"plan"`                                                                                                                                                                             |
| `forwardedProps.files`                       | Attachments, `[{"id": "<upload id>"}]`                                                                                                                                                                    |
| `forwardedProps.chatSource`, `chatSourceRef` | Set the saved chat's `source` and `source_ref`. Default: none. Used only with a workspace key, on the run that creates the chat through `run-stream`; `"app"` hides the chat from the web app's chat list |
| `forwardedProps.runtimeConfig`               | Per-run overrides, below                                                                                                                                                                                  |

| `runtimeConfig` field                  | Effect on the agent's configuration           |
| -------------------------------------- | --------------------------------------------- |
| `system_prompt`                        | Replaces the prompt                           |
| `model_config_id` or `model_slug`      | Replaces the model                            |
| `tool_names`                           | Replaces the tool list                        |
| `skill_slugs`, `skill_set_slugs`       | Add skills                                    |
| `connection_ids`, `mcp_connection_ids` | Add connections; never remove the agent's own |
| `file_scope`                           | Replaces the Files scope                      |

Stream a run [#stream-a-run]

1. Pick a `threadId`, or reuse one to continue a conversation.

2. Send the body with `Accept: text/event-stream`:

   ```bash
   curl -N -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/run-stream/" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -H "Accept: text/event-stream" \
     -H "Content-Type: application/json" \
     -d '{
       "threadId": "contract-demo-1",
       "runId": "run-1",
       "state": null,
       "messages": [{"id": "m1", "role": "user", "content": "Summarize the renewal terms."}],
       "tools": [],
       "context": [],
       "forwardedProps": {}
     }'
   ```

3. Read events until `RUN_FINISHED` or `RUN_ERROR`; either one ends the run.

Run in the background [#run-in-the-background]

1. Start the run with the same body; the response holds its `run_id` (`chat_id` is `null` when history is not saved):

   ```bash
   curl -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/runs/?agent_id=42" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -H "Content-Type: application/json" \
     -d '{"threadId": "contract-demo-2", "runId": "run-1", "state": null, "messages": [{"id": "m1", "role": "user", "content": "Summarize the renewal terms."}], "tools": [], "context": [], "forwardedProps": {}}'
   ```

2. Stream its events from `GET /api/v1/agents-v2/runs/{run_id}/events/?last_id=0`. Each chunk starts with an `id:` line; after a disconnect, reconnect with `last_id` set to the last `id` you received. The stream closes with a `: done` comment.

3. To stop the run, send `POST /api/v1/agents-v2/runs/{run_id}/cancel/`.

Override settings for one run [#override-settings-for-one-run]

1. Put the overrides in `forwardedProps.runtimeConfig`; connections you list are added to the agent's own:

   ```bash
   curl -N -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/run-stream/" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -H "Accept: text/event-stream" \
     -H "Content-Type: application/json" \
     -d '{
       "threadId": "contract-demo-1",
       "runId": "run-2",
       "state": null,
       "messages": [{"id": "m2", "role": "user", "content": "Compare it with last year."}],
       "tools": [],
       "context": [],
       "forwardedProps": {
         "mode": "act",
         "runtimeConfig": {
           "connection_ids": [17],
           "mcp_connection_ids": [7],
           "model_config_id": 12
         }
       }
     }'
   ```

Attach files [#attach-files]

1. Upload the file; the response is `201` with `{id, name, mime_type, size, gc_url, file_metadata, presigned_url}`:

   ```bash
   curl -X POST "$CENTRAL_HUB_URL/api/v1/agents-v2/files/upload/" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG" \
     -F "file=@contract.pdf;type=application/pdf"
   ```

2. Add `{"id": "<id>"}` to `forwardedProps.files`. The file is copied into the agent's sandbox at `/home/user/uploads/<id>-<name>` and the agent is told its path. Only your own uploads are resolved.

3. Optional: to let the model read the file directly, add a content part to the last user message; use `"type": "image"` for images. Files the model cannot take directly are left to the sandbox copy.

   ```json
   {"type": "document", "source": {"type": "url", "id": "<id>", "name": "contract.pdf", "mimeType": "application/pdf", "value": "<presigned_url>"}}
   ```

Download a generated file [#download-a-generated-file]

1. Take `path` and `fileId` from the run's `FILE_GENERATED` event, `{type, toolCallId, path, name, mimeType, size}` plus `fileId` once the file is stored.

2. Request a link with the run's `agent_id` and `thread_id`:

   ```bash
   curl "$CENTRAL_HUB_URL/api/v1/agents-v2/agents/42/sandbox/files/presigned-url/?path=/home/user/report.xlsx&thread_id=contract-demo-1&file_id=<fileId>&expires_in_seconds=600" \
     -H "X-API-Key: $ALO_API_KEY" \
     -H "X-Space-Slug: $WORKSPACE_SLUG"
   ```

3. Download from `url` in the response, `{url, expires_in_seconds}`.

| Parameter            | Rule                                                                                                       |
| -------------------- | ---------------------------------------------------------------------------------------------------------- |
| `path`               | Required; must start with `/home/user/`                                                                    |
| `thread_id`          | Required                                                                                                   |
| `file_id`            | Optional, recommended: one path can hold several versions of a file, and without it the newest is returned |
| `expires_in_seconds` | 30–3600, default 600                                                                                       |

Troubleshooting [#troubleshooting]

| Response                                                                                                                           | Cause                                                                                                        | Fix                                                                                |
| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `409` `{"detail": {"code": "SANDBOX_BUSY", "message": "This chat is still working on an earlier message.", "run_id": "<run id>"}}` | Another run still holds this chat's sandbox                                                                  | Wait for that run to end, or cancel it if it is a background run                   |
| `429`                                                                                                                              | Too many runs; the run routes share one limit per caller                                                     | See [Rate limits](../api-basics/rate-limits)                                       |
| `402` `SUBSCRIPTION_INACTIVE`                                                                                                      | A signed-in user's subscription is not active                                                                | Renew the subscription                                                             |
| `RUN_ERROR` with `errorSurface.layer` `quota`                                                                                      | The caller is over a credit quota; the event also carries `code`, `quota_type`, `metric`, `limit` and `used` | Wait for the quota period to reset, or upgrade the plan                            |
| `RUN_ERROR` `agent request failed (status=422): …`                                                                                 | A required top-level key is missing from the body                                                            | Send every key listed in [Request fields](#request-fields)                         |
| `PER_USER_AUTH_REQUIRED` event, `{"connections": [{"connectionId", "connectorKey", "name"}]}`                                      | The caller has not authorized a per-user OAuth connection                                                    | The run continues without it; the user connects it in the web app, then runs again |
| `403` `You do not have access to this run`                                                                                         | The run belongs to another user or workspace                                                                 | Use the credential that started it                                                 |
| `404` `Background agent runs are disabled.`                                                                                        | The server has background runs off                                                                           | Use a `run-stream` route                                                           |
| `400` `Only /home/user files can be downloaded`                                                                                    | `path` is outside `/home/user/`                                                                              | Use the `path` from `FILE_GENERATED`                                               |
| `404` `This file is no longer available`                                                                                           | The generated file was not kept                                                                              | Run the agent again                                                                |
