Files
coder/docs/ai-coder/agents/chats-api.md
T
Matt Vollmer 115011bd70 docs: rename Chat API to Chats API (#23121)
Renames the page title and manifest label from "Chat API" to "Chats API"
to match the plural endpoint path (`/api/experimental/chats`).
2026-03-16 11:31:43 -04:00

220 lines
7.1 KiB
Markdown

# Chats API
> [!NOTE]
> The Chats API is experimental and gated behind the `agents` experiment flag.
> Endpoints live under `/api/experimental/chats` and may change without notice.
The Chats API lets you create and interact with Coder Agents
programmatically. You can start a chat, send follow-up messages, and stream
the agent's response — all without using the Coder dashboard.
## Authentication
All endpoints require a valid session token:
```sh
curl -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
https://coder.example.com/api/experimental/chats
```
## Quick start
Create a chat with a single text prompt:
```sh
curl -X POST https://coder.example.com/api/experimental/chats \
-H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": [
{"type": "text", "text": "hello world"}
]
}'
```
The response is the newly created `Chat` object:
```json
{
"id": "a1b2c3d4-...",
"owner_id": "...",
"workspace_id": null,
"last_model_config_id": "...",
"title": "hello world",
"status": "waiting",
"last_error": null,
"created_at": "2025-07-17T00:00:00Z",
"updated_at": "2025-07-17T00:00:00Z",
"archived": false
}
```
The agent begins processing the prompt asynchronously. Use the
[stream endpoint](#stream-updates) to follow its progress.
## Core workflow
A typical integration follows three steps:
1. **Create a chat**`POST /api/experimental/chats` with your prompt.
2. **Stream updates** — Open a WebSocket to
`GET /api/experimental/chats/{chat}/stream` to receive real-time events
as the agent works.
3. **Send follow-ups**`POST /api/experimental/chats/{chat}/messages` to
add messages to the conversation. Messages are queued if the agent is
busy.
## Endpoints
### Create a chat
`POST /api/experimental/chats`
| Field | Type | Required | Description |
|-------------------|-------------------|----------|-------------------------------------------------|
| `content` | `ChatInputPart[]` | yes | The user's prompt as one or more content parts. |
| `workspace_id` | `uuid` | no | Pin the chat to a specific workspace. |
| `model_config_id` | `uuid` | no | Override the default model configuration. |
Each `ChatInputPart` has a `type` field. The simplest form is a text part:
```json
{"type": "text", "text": "Fix the failing tests in the auth service"}
```
Other part types include `file` (an uploaded image referenced by its
`file_id`) and `file-reference` (a pointer to a file with optional line
range).
**Response**: `201 Created` with a `Chat` object.
### Send a message
`POST /api/experimental/chats/{chat}/messages`
| Field | Type | Required | Description |
|-------------------|-------------------|----------|-----------------------------------|
| `content` | `ChatInputPart[]` | yes | The follow-up message content. |
| `model_config_id` | `uuid` | no | Override the model for this turn. |
If the agent is currently processing, the message is queued automatically.
The response indicates whether the message was delivered immediately or
queued:
```json
{
"queued": false,
"message": { "id": 42, "chat_id": "...", "role": "user", "created_at": "...", "content": [...] }
}
```
When `queued` is `true`, `message` is absent and `queued_message` is
returned instead.
### Stream updates
`GET /api/experimental/chats/{chat}/stream`
Opens a **one-way WebSocket** connection. The server sends events; clients
must not write to the socket (doing so closes the connection).
| Query parameter | Type | Required | Description |
|-----------------|---------|----------|-------------------------------------------|
| `after_id` | `int64` | no | Only return events after this message ID. |
Each WebSocket message is a JSON envelope with an outer `type`
(`"ping"`, `"data"`, or `"error"`) and an optional `data` field. For
`"data"` envelopes the payload is a **JSON array** of event objects:
```json
{
"type": "data",
"data": [
{"type": "status", "chat_id": "...", "status": {"status": "running"}},
{"type": "message_part", "chat_id": "...", "message_part": {"...":"..."}}
]
}
```
Ignore `"ping"` envelopes (keepalives sent every ~15 s). On first
connect the server sends an initial snapshot of the chat state before
switching to live events. Use `after_id` when reconnecting to skip
messages the client already has.
Event types inside each batch:
| Type | Description |
|----------------|--------------------------------------------------------------|
| `message_part` | A chunk of the agent's response (text, tool call, etc.). |
| `message` | A complete message has been persisted. |
| `status` | The chat status changed (e.g. `running`, `waiting`). |
| `error` | An error occurred during processing. |
| `retry` | The server is retrying a failed LLM call (includes backoff). |
| `queue_update` | The queued message list changed. |
### List chats
`GET /api/experimental/chats`
Returns all chats owned by the authenticated user.
### Get a chat
`GET /api/experimental/chats/{chat}`
Returns the `Chat` object (metadata only, no messages).
### Get chat messages
`GET /api/experimental/chats/{chat}/messages`
Returns the messages and queued messages for a chat.
### List models
`GET /api/experimental/chats/models`
Returns available models. Use this to discover valid values for
`model_config_id`.
### Archive / unarchive
`POST /api/experimental/chats/{chat}/archive`
`POST /api/experimental/chats/{chat}/unarchive`
Archive hides a chat from the default list without deleting it.
### Interrupt
`POST /api/experimental/chats/{chat}/interrupt`
Stops the agent's current processing loop and returns the chat to
`waiting` status.
## File uploads
Attach images to a chat by uploading them first:
```sh
curl -X POST "https://coder.example.com/api/experimental/chats/files?organization=$ORG_ID" \
-H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
-H "Content-Type: image/png" \
--data-binary @screenshot.png
```
The response contains an `id` you can reference as `file_id` in a
`ChatInputPart` with `"type": "file"`. To retrieve a previously uploaded
file, use `GET /api/experimental/chats/files/{file}`.
Supported formats: PNG, JPEG, GIF, WebP (up to 10 MB). The server
validates actual file content regardless of the declared `Content-Type`.
## Chat statuses
| Status | Meaning |
|-----------|--------------------------------------------------------------|
| `waiting` | Idle — newly created, finished successfully, or interrupted. |
| `pending` | Queued for processing. |
| `running` | Agent is actively working. |
| `error` | Agent encountered an error. |