# Migrate from the Tasks API to the Chats API

<Callout type="warn" title="Warning">
  Coder Tasks was deprecated in Coder v2.34 and has been removed, including the Tasks API (`/api/v2/tasks`).
  To read about Coder Tasks, use a previous version of the Coder documentation, from a release before v2.36.
</Callout>

The Tasks API (`/api/v2/tasks`) and the [Chats API](/beta-docs/@main/reference/api/chats/) (`/api/v2/chats`) serve similar goals (programmatic access to AI-powered coding agents) but they differ significantly in architecture, capabilities, and usage patterns.

This guide walks you through updating your integrations from the Tasks API to the Chats API.

## When to migrate [#when-to-migrate]

Migrate now.
Coder Tasks has been removed, so requests to the Tasks API fail.

If your integrations still call the Tasks API, migrate to the Chats API and [Coder Agents](/beta-docs/@main/ai-coder/agents/).
Coder Agents runs the agent loop in the Coder control plane rather than inside the workspace, and is the supported path going forward.

The two systems are not interchangeable.
Tasks and Chats are separate resources with separate APIs, so plan to update your integrations rather than expecting a drop-in replacement.

## Key architectural differences [#key-architectural-differences]

Before mapping individual endpoints, understand the structural changes:

| Aspect                 | Tasks API                                                                        | Chats API                                                  |
| ---------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| Agent execution        | Agent runs **inside the workspace** (via AgentAPI)                               | Agent loop runs **in the control plane**                   |
| LLM credentials        | Injected into workspace environment                                              | Stored in control plane only; never enters the workspace   |
| Workspace provisioning | You specify a `template_version_id` at creation                                  | The agent auto-selects a template and provisions on demand |
| Template requirements  | Requires `coder_ai_task` resource, `coder_task` data source, and an agent module | Any template with a clear description works                |
| Chat state             | Stored in the workspace (AgentAPI state file)                                    | Persisted in the Coder database                            |
| Conversation model     | Single prompt with optional follow-up input                                      | Multi-turn chat with message history, queuing, and editing |
| Real-time updates      | HTTP polling (`GET .../logs`)                                                    | WebSocket streaming (`GET .../stream`)                     |
| Sub-agents             | Not supported                                                                    | Built-in sub-agent delegation                              |

## Endpoint mapping [#endpoint-mapping]

The table below maps each Tasks API endpoint to its Chats API equivalent.

| Operation         | Tasks API                                 | Chats API                                                 |
| ----------------- | ----------------------------------------- | --------------------------------------------------------- |
| List              | `GET /api/v2/tasks`                       | `GET /api/v2/chats`                                       |
| Create            | `POST /api/v2/tasks/{user}`               | `POST /api/v2/chats`                                      |
| Get by ID         | `GET /api/v2/tasks/{user}/{task}`         | `GET /api/v2/chats/{chat}`                                |
| Delete            | `DELETE /api/v2/tasks/{user}/{task}`      | `PATCH /api/v2/chats/{chat}` with `{"archived": true}`    |
| Send follow-up    | `POST /api/v2/tasks/{user}/{task}/send`   | `POST /api/v2/chats/{chat}/messages`                      |
| Update input      | `PATCH /api/v2/tasks/{user}/{task}/input` | `PATCH /api/v2/chats/{chat}/messages/{message}`           |
| Get logs / stream | `GET /api/v2/tasks/{user}/{task}/logs`    | `GET /api/v2/chats/{chat}/stream` (WebSocket)             |
| Pause             | `POST /api/v2/tasks/{user}/{task}/pause`  | `POST /api/v2/chats/{chat}/interrupt`                     |
| Resume            | `POST /api/v2/tasks/{user}/{task}/resume` | `POST /api/v2/chats/{chat}/messages` (send a new message) |
| Watch all         | n/a                                       | `GET /api/v2/chats/watch` (WebSocket)                     |
| Get messages      | n/a                                       | `GET /api/v2/chats/{chat}/messages`                       |
| List models       | n/a                                       | `GET /api/v2/organizations/{organization}/chats/models`   |
| Upload file       | n/a                                       | `POST /api/v2/chats/files`                                |

## Migration steps [#migration-steps]

<div className="fd-steps">
  <div className="fd-step">
    ### Configure an LLM provider [#configure-an-llm-provider]

    With Tasks, LLM credentials are injected into the workspace as environment variables (e.g. `ANTHROPIC_API_KEY`).
    With Coder Agents, credentials are configured once in the control plane:

    1. Navigate to **Admin settings** > **AI** and select **Providers**.
    2. Add or update a provider with its credentials and upstream endpoint, then save it.
    3. Navigate to **Admin settings** > **AI** > **Models**.
    4. Select the correct organization.
    5. Add at least one model, and set it as the default.

    You no longer pass API keys in template variables or workspace environment.
    See [https://coder.com/docs/ai-coder/agents/getting-started](https://coder.com/docs/ai-coder/agents/getting-started) for more information.
  </div>

  <div className="fd-step">
    ### Update task creation calls [#update-task-creation-calls]

    **Tasks API**.
    You specify the user, template version, and a prompt string:

    ```sh
    # Tasks API: create a task
    curl -X POST https://coder.example.com/api/v2/tasks/me \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "template_version_id": "<template-version-uuid>",
        "input": "Fix the failing tests in the auth service"
      }'
    ```

    **Chats API**.
    You send structured content parts.
    No template or user path segment is required:

    ```sh
    # Chats API: create a chat
    curl -X POST https://coder.example.com/api/v2/chats \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "organization_id": "<your-org-id>",
        "content": [
          {"type": "text", "text": "Fix the failing tests in the auth service"}
        ]
      }'
    ```

    Key differences:

    * The `{user}` path parameter is removed.
      The authenticated user is inferred from the session token.
    * `organization_id` is required in the request body.
      The caller must be a member of that organization.
    * The prompt is now an array of `ChatInputPart` objects (supporting `text`, `file`, and `file-reference` types) instead of a plain string.
    * `template_version_id` and `template_version_preset_id` are removed.
      The agent selects a template automatically based on the prompt and available template descriptions.
      To pin to a specific workspace, pass `workspace_id` instead.
    * Optionally pass `model_config_id` to override the default model, or `mcp_server_ids` to attach MCP servers.
    * Optionally pass `title` to set the chat's title.
      A title you set is kept; automatic title generation runs only when `title` is omitted.
  </div>

  <div className="fd-step">
    ### Update follow-up message calls [#update-follow-up-message-calls]

    **Tasks API**.
    Follow-ups use the send endpoint with a plain string:

    ```sh
    # Tasks API: send input
    curl -X POST https://coder.example.com/api/v2/tasks/me/my-task/send \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"input": "Now also update the integration tests"}'
    ```

    **Chats API**.
    Follow-ups use the messages endpoint with content parts:

    ```sh
    # Chats API: send a message
    curl -X POST \
      https://coder.example.com/api/v2/chats/$CHAT_ID/messages \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "content": [
          {"type": "text", "text": "Now also update the integration tests"}
        ]
      }'
    ```

    The Chats API supports message queuing.
    If the agent is busy, the message is queued automatically and delivered when the agent finishes its current step.
    The response includes a `queued` field indicating whether the message was delivered immediately or queued.
  </div>

  <div className="fd-step">
    ### Switch from log polling to WebSocket streaming [#switch-from-log-polling-to-websocket-streaming]

    **Tasks API**.
    You poll for logs:

    ```sh
    # Tasks API: get logs
    curl https://coder.example.com/api/v2/tasks/me/my-task/logs \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN"
    ```

    **Chats API**.
    You open a one-way WebSocket connection:

    ```txt
    GET wss://coder.example.com/api/v2/chats/{chat}/stream
    ```

    The WebSocket sends JSON envelopes with a `type` field (`"ping"`, `"data"`, or `"error"`).
    Data envelopes contain batches of events:

    | Event 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 control plane is retrying a failed LLM call         |
    | `queue_update` | The queued message list changed                         |

    Use `after_id` as a query parameter when reconnecting to skip messages the client already has.
  </div>

  <div className="fd-step">
    ### Update status handling [#update-status-handling]

    Task and chat statuses use different values.
    The Chats API status set is defined in `codersdk.ChatStatus`:

    | Tasks API status | Chats API status  | Notes                                                                                                               |
    | ---------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------- |
    | `pending`        | `running`         | Chats have no separate queued state; a chat that hasn't been picked up yet reports `running`.                       |
    | `running`        | `running`         | Agent is actively working.                                                                                          |
    | `complete`       | `waiting`         | Idle. Newly created, finished successfully, or interrupted. This is the default idle state.                         |
    | `paused`         | n/a               | The Tasks API pause stops the workspace; the Chats API equivalent is `interrupt` plus separate workspace lifecycle. |
    | `failed`         | `error`           | Agent encountered an error.                                                                                         |
    | n/a              | `requires_action` | Agent invoked a client-provided tool and is waiting for the result before continuing.                               |
    | n/a              | `interrupting`    | An interrupt was requested and the agent is winding down the current run.                                           |

    The Chats API uses `waiting` as the default idle state (not `complete`).
    A chat enters `waiting` when it is first created (before any message is queued) and again whenever a run finishes or is interrupted, so treat `waiting` as "the agent is not currently working" rather than only "the agent just finished."
  </div>

  <div className="fd-step">
    ### Replace delete with archive [#replace-delete-with-archive]

    The Tasks API uses `DELETE` to remove a task.
    The Chats API uses archiving:

    ```diff
    - curl -X DELETE https://coder.example.com/api/v2/tasks/me/my-task \
    -   -H "Coder-Session-Token: $CODER_SESSION_TOKEN"

    + curl -X PATCH https://coder.example.com/api/v2/chats/$CHAT_ID \
    +   -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
    +   -H "Content-Type: application/json" \
    +   -d '{"archived": true}'
    ```

    Archived chats can be restored by setting `archived` to `false`.
  </div>

  <div className="fd-step">
    ### Replace pause/resume with interrupt and messaging [#replace-pauseresume-with-interrupt-and-messaging]

    **Tasks API**.
    Pause and resume stop and start the workspace:

    ```sh
    # Tasks API
    curl -X POST \
      https://coder.example.com/api/v2/tasks/me/my-task/pause \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN"

    curl -X POST \
      https://coder.example.com/api/v2/tasks/me/my-task/resume \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN"
    ```

    **Chats API**.
    Interrupt stops the current agent loop.
    Sending a new message resumes processing:

    ```sh
    # Chats API: interrupt
    curl -X POST \
      https://coder.example.com/api/v2/chats/$CHAT_ID/interrupt \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN"

    # Chats API: resume by sending a new message
    curl -X POST \
      https://coder.example.com/api/v2/chats/$CHAT_ID/messages \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "content": [
          {"type": "text", "text": "Continue where you left off"}
        ]
      }'
    ```

    In the Tasks API, pausing stops the workspace and frees compute.
    In the Chats API, interrupt stops the agent loop in the control plane; the workspace may remain running.
    The workspace lifecycle is managed independently.
  </div>

  <div className="fd-step">
    ### Update GitHub Actions integrations [#update-github-actions-integrations]

    If you use the [Create Task Action](https://github.com/coder/create-task-action) GitHub Action, replace it with the dedicated [`coder/create-agent-chat-action`](https://github.com/coder/create-agent-chat-action).
    It handles the API call, the GitHub user lookup, and the optional issue comment, so most existing workflows can swap one `uses:` line and rename a few inputs.

    We are actively shipping new features for `create-agent-chat-action`, so pin to a major version (for example `@v0`) and watch the [releases](https://github.com/coder/create-agent-chat-action/releases) for updates.

    ```diff
    # .github/workflows/triage-bug.yaml
    jobs:
      coder-create-task:
        runs-on: ubuntu-latest
        if: github.event.label.name == 'coder'
        steps:
    -     - name: Coder Create Task
    -       uses: coder/create-task-action@v0
    -       with:
    -         coder-url: ${{ secrets.CODER_URL }}
    -         coder-token: ${{ secrets.CODER_TOKEN }}
    -         coder-organization: "default"
    -         coder-template-name: "my-template"
    -         coder-task-name-prefix: "gh-task"
    -         coder-task-prompt: >-
    -           Use the gh CLI to read
    -           ${{ github.event.issue.html_url }},
    -           fix the issue, and create a PR.
    -         github-user-id: ${{ github.event.sender.id }}
    -         github-issue-url: ${{ github.event.issue.html_url }}
    -         github-token: ${{ github.token }}
    -         comment-on-issue: true
    +     - name: Coder Create Agent Chat
    +       uses: coder/create-agent-chat-action@v0
    +       with:
    +         coder-url: ${{ secrets.CODER_URL }}
    +         coder-token: ${{ secrets.CODER_TOKEN }}
    +         chat-prompt: >-
    +           Use the gh CLI to read
    +           ${{ github.event.issue.html_url }},
    +           fix the issue, and create a PR.
    +         github-url: ${{ github.event.issue.html_url }}
    +         github-token: ${{ github.token }}
    +         comment-on-issue: true
    ```

    Key differences from the Tasks GHA:

    * No `coder-template-name` or `coder-task-name-prefix`.
      The agent auto-provisions a workspace; pass `workspace-id` if you want to pin to an existing workspace instead.
    * The prompt input is renamed from `coder-task-prompt` to `chat-prompt`.
    * LLM credentials are no longer passed through the template.
      They are configured in the Coder control plane.
    * No user mapping: the Tasks GHA's `github-user-id` input has no equivalent, because the chat is always owned by the user the `coder-token` belongs to and the Chats API has no owner override.

    See the [action README](https://github.com/coder/create-agent-chat-action#inputs) for the full input and output reference, including the `existing-chat-id` input for sending follow-up messages on a previous chat.
  </div>
</div>

## Template recommendations [#template-recommendations]

<Callout type="info" title="Note">
  This section contains recommendations that may evolve as Coder Agents matures.
  Review these against your deployment requirements.
</Callout>

With Coder Tasks, every task-capable template requires specific Terraform resources (`coder_ai_task`, `coder_task`, agent modules, and LLM API keys).
With Coder Agents, templates no longer need any of these.
The agent runs in the control plane and treats the workspace as plain compute.

However, **we still recommend creating dedicated templates for agent workloads** rather than reusing your standard developer templates unchanged.
The reasons are different from Tasks, but the principle holds:

### Why dedicated agent templates still matter [#why-dedicated-agent-templates-still-matter]

* **Network boundaries.**
  Agent workspaces inherit whatever network access the template allows.
  Because the agent does not need outbound access to LLM providers (that happens in the control plane), you can lock down agent templates to only reach the Coder control plane and your git provider.
  Standard developer templates typically allow broader access.
* **No IDE tooling overhead.**
  The agent connects via the workspace daemon's HTTP API, not through VS Code or JetBrains.
  Removing IDE extensions, desktop environments, and similar tooling from agent templates reduces image size and startup time.
* **Scoped credentials.**
  Agent workloads may warrant more restrictive credentials than interactive developer sessions.
  A dedicated template lets you provide a separate, narrower-scoped git token or service account without affecting your developers' workflow.
* **Cost control.**
  Agent workspaces can often use smaller compute resources than developer workspaces since they don't need to run IDEs, language servers, or other interactive tooling.
  A dedicated template lets you right-size the infrastructure.

### What to include in agent templates [#what-to-include-in-agent-templates]

* **Clear descriptions.*&#x2A;
  The agent selects templates by reading names and descriptions.
  Include the target language, framework, repository, and type of work.
  For example: &#x2A;"Python backend services for the payments repo.
  Includes Poetry, Python 3.12, and PostgreSQL."*
* **Pre-installed dependencies.**
  Language runtimes, build tools, `git`, and project-specific dependencies should be baked into the image.
  Time the agent spends installing tools is time not spent on the task.
* **Git configuration.**
  Ensure `git` is configured with credentials and author information so the agent can commit and push without additional setup.
* **Minimal parameters.**
  Use sensible defaults so the agent can provision workspaces without guessing.
  Avoid required parameters with opaque identifiers.

### What to remove from migrated task templates [#what-to-remove-from-migrated-task-templates]

If you are converting an existing task template for use with Coder Agents, you can safely remove the Tasks-specific Terraform resources.
They are unused when the chat is driven by the Chats API:

```diff
  terraform {
    required_providers {
      coder = {
        source  = "coder/coder"
-       version = ">= 2.13"
+       version = ">= 2.13"
      }
    }
  }

- data "coder_task" "me" {}
-
- resource "coder_ai_task" "task" {
-   app_id = module.claude-code.task_app_id
- }
-
- module "claude-code" {
-   source         = "registry.coder.com/coder/claude-code/coder"
-   version        = "4.0.0"
-   agent_id       = coder_agent.main.id
-   ai_prompt      = data.coder_task.me.prompt
-   claude_api_key = var.anthropic_api_key
- }
-
- variable "anthropic_api_key" {
-   type        = string
-   description = "Anthropic API key"
-   sensitive   = true
- }

  resource "coder_agent" "main" {
    os   = "linux"
    arch = "amd64"
+   # No agent modules, no AgentAPI, no LLM keys needed.
+   # The Coder Agents control plane handles the agent loop.
  }
```

<Callout type="idea" title="Important">
  Remove the Tasks-specific Terraform when you upgrade.
  Tasks and Chats can no longer run side by side: Coder no longer injects `CODER_TASK_ID` or `CODER_TASK_PROMPT`, so builds of a template that keeps the `coder_task` data source can no longer populate it.
</Callout>

See [Template Optimization](/beta-docs/@main/ai-coder/agents/platform-controls/template-optimization/) for the full guide on writing discoverable descriptions, configuring network boundaries, scoping credentials, and pre-installing dependencies.

### Pre-creating a workspace for deterministic results [#pre-creating-a-workspace-for-deterministic-results]

Letting the agent pick a template and provision a workspace works well for exploratory chats.
If your workflow requires deterministic results like:

* Automations
* Recurring processes
* Generally any case that needs a known reproducible environment

pre-create the workspace yourself and attach it when you create the chat.

The pattern is two API calls:

1. Create a workspace from a specific template via [`POST /api/v2/users/{user}/workspaces`](/beta-docs/@main/reference/api/workspaces/#create-user-workspace).
   You control the template, the version, and any rich parameters.
2. Create the chat with `workspace_id` set to the workspace you just created.
   The agent runs against that workspace instead of selecting one heuristically.

```sh
# 1. Provision the workspace from the exact template you want.
WORKSPACE_ID=$(curl -s -X POST \
  https://coder.example.com/api/v2/users/me/workspaces \
  -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "<your-agent-template-uuid>",
    "name": "agent-run-${GITHUB_RUN_ID}"
  }' | jq -r '.id')

# 2. Create the chat bound to that workspace.
curl -s -X POST https://coder.example.com/api/v2/chats \
  -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"organization_id\": \"<your-org-id>\",
    \"workspace_id\": \"$WORKSPACE_ID\",
    \"content\": [
      {\"type\": \"text\", \"text\": \"Fix the failing tests in the auth service\"}
    ]
  }"
```

This pattern is the closest analogue to the Tasks API behavior of `template_version_id` plus `coder-template-name`: you decide which template runs, the agent decides what to do inside it.
The same approach works from the [`coder/create-agent-chat-action`](https://github.com/coder/create-agent-chat-action) GHA, which exposes the same pin via its `workspace-id` input.

## How to test your migration [#how-to-test-your-migration]

After completing the migration steps above, walk through these checks to confirm the Chats API integration is working end-to-end.

<div className="fd-steps">
  <div className="fd-step">
    ### Confirm LLM provider connectivity [#confirm-llm-provider-connectivity]

    List the available models in an organization to verify at least one provider is configured and reachable:

    ```sh
    curl -s https://coder.example.com/api/v2/organizations/$CODER_ORGANIZATION/chats/models \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" | jq '.models[].display_name'
    ```

    If this returns an empty list or an error, revisit [Step 1: Configure an LLM provider](#1-configure-an-llm-provider).
  </div>

  <div className="fd-step">
    ### Create a chat and confirm the response [#create-a-chat-and-confirm-the-response]

    Create a simple chat that does not require a workspace:

    ```sh
    curl -s -X POST https://coder.example.com/api/v2/chats \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "content": [{"type": "text", "text": "What is 2 + 2?"}]
      }' | jq '{id, status, title}'
    ```

    You should receive a `Chat` object with `status` set to `"running"`, since new chats begin processing immediately.
    Save the `id` for subsequent steps.
  </div>

  <div className="fd-step">
    ### Stream the response [#stream-the-response]

    Open a WebSocket connection to verify the agent processes the prompt and returns a response.
    Using [websocat](https://github.com/vi/websocat):

    ```sh
    websocat -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      "wss://coder.example.com/api/v2/chats/$CHAT_ID/stream"
    ```

    You should see JSON envelopes with `"type": "data"` containing `message_part` and `status` events.
    The chat should eventually reach `"waiting"` status, indicating the agent completed its response.
  </div>

  <div className="fd-step">
    ### Send a follow-up message [#send-a-follow-up-message]

    Verify multi-turn conversation works:

    ```sh
    curl -s -X POST \
      "https://coder.example.com/api/v2/chats/$CHAT_ID/messages" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "content": [{"type": "text", "text": "Now multiply that by 10"}]
      }' | jq '{queued}'
    ```

    The response should include `"queued": false` (delivered immediately) or `"queued": true` (agent was busy.
    The message is queued and will be processed next).
  </div>

  <div className="fd-step">
    ### Test workspace provisioning [#test-workspace-provisioning]

    Create a workspace from your converted agent template through the standard Coder UI, then attach it to a new chat from the chat composer:

    1. In the Coder dashboard, create a workspace from the agent template you migrated.
    2. Open **Agents** and start a new chat.
    3. In the composer, use the workspace picker to attach the workspace you just created.
    4. Send a prompt that exercises the workspace, for example: &#x2A;"List the files in the root directory of this workspace."*

    The response stream should show the agent invoking workspace tools (such as `execute`) against the attached workspace.
    After the chat finishes, verify the chat is bound to the workspace via the API:

    ```sh
    curl -s "https://coder.example.com/api/v2/chats/$CHAT_ID" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" | jq '{workspace_id, status}'
    ```

    A `workspace_id` matching the workspace you attached confirms the chat is driving that workspace end-to-end.
    Auto-provisioning from the chat flow is also supported but is easier to verify once the manual-attach path is working.
  </div>

  <div className="fd-step">
    ### Verify interrupt works [#verify-interrupt-works]

    Start a long-running chat and interrupt it:

    ```sh
    curl -s -X POST \
      "https://coder.example.com/api/v2/chats/$CHAT_ID/interrupt" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN"
    ```

    Then confirm the chat status returns to `"waiting"`:

    ```sh
    curl -s "https://coder.example.com/api/v2/chats/$CHAT_ID" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" | jq '.status'
    ```
  </div>

  <div className="fd-step">
    ### Validate archive and restore [#validate-archive-and-restore]

    ```sh
    # Archive
    curl -s -X PATCH \
      "https://coder.example.com/api/v2/chats/$CHAT_ID" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"archived": true}'

    # Confirm it no longer appears in the default list
    curl -s "https://coder.example.com/api/v2/chats" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      | jq --arg id "$CHAT_ID" '[.[] | select(.id == $id)] | length'
    # Should return 0

    # Restore
    curl -s -X PATCH \
      "https://coder.example.com/api/v2/chats/$CHAT_ID" \
      -H "Coder-Session-Token: $CODER_SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"archived": false}'
    ```
  </div>
</div>

### Quick checklist [#quick-checklist]

Use this list to confirm each part of your integration:

* At least one LLM model is configured in the organization and returned by `/organizations/{organization}/chats/models`
* `POST /chats` creates a chat and returns a valid `Chat` object
* WebSocket stream at `/chats/{chat}/stream` delivers events
* Follow-up messages via `/chats/{chat}/messages` are accepted
* Chat attached to a workspace from the converted template runs tools against that workspace
* `POST /chats/{chat}/interrupt` stops the agent and returns to `waiting`
* Archive and restore via `PATCH /chats/{chat}` works
* (If applicable) GitHub Actions workflow creates chats successfully

## Features available only in the Chats API [#features-available-only-in-the-chats-api]

The Chats API includes capabilities that have no equivalent in the Tasks API:

| Feature                              | Description                                                                                           |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------- |
| **WebSocket streaming**              | Real-time event stream via `GET /chats/{chat}/stream` instead of HTTP polling                         |
| **Watch all chats**                  | `GET /chats/watch` pushes events for all chats owned by the user                                      |
| **Message editing**                  | `PATCH /chats/{chat}/messages/{message}` to edit a sent message and re-process                        |
| **Message queuing**                  | Follow-up messages are automatically queued when the agent is busy                                    |
| **File uploads**                     | Attach images via `POST /chats/files` and reference them in messages                                  |
| **Model selection**                  | `GET /organizations/{organization}/chats/models` to discover models; override per-chat or per-message |
| **MCP server attachment**            | Attach MCP servers to a chat for tool augmentation                                                    |
| **Labels**                           | Key-value metadata on chats for filtering (`label` query parameter)                                   |
| **Sub-agents**                       | Agent can spawn child agents for parallel work                                                        |
| **Diff/PR tracking**                 | `GET /chats/{chat}/diff` returns change tracking and PR metadata                                      |
| **Title generation**                 | `POST /chats/{chat}/title/propose` returns a suggested title                                          |
| **Pinning**                          | Pin and reorder chats via the `pin_order` field                                                       |
| **Automatic workspace provisioning** | Created for workspace access or to obtain missing tools, skills, MCP integrations, or context         |

## Response schema changes [#response-schema-changes]

The Tasks API returns a `Task` object with workspace-centric fields.
The Chats API returns a `Chat` object with conversation-centric fields:

| Tasks API field    | Chats API equivalent                          | Notes                                                            |
| ------------------ | --------------------------------------------- | ---------------------------------------------------------------- |
| `id`               | `id`                                          | Both are UUIDs                                                   |
| `initial_prompt`   | First message in `GET /chats/{chat}/messages` | Prompt is a message, not a top-level field                       |
| `display_name`     | `title`                                       | Auto-generated or set via `PATCH`                                |
| `status`           | `status`                                      | Different enum values (see status table above)                   |
| `current_state`    | Latest `status` event from the stream         | No equivalent top-level field                                    |
| `workspace_id`     | `workspace_id`                                | Nullable in Chats. May be `null` if no workspace was provisioned |
| `workspace_status` | n/a                                           | Manage workspace lifecycle separately                            |
| `template_id`      | n/a                                           | Not exposed; the agent selects templates internally              |
| `owner_id`         | `owner_id`                                    | Same concept                                                     |
| `name`             | n/a                                           | Chats use `id` for identification, not human-readable names      |

## CLI changes [#cli-changes]

The Tasks CLI (`coder task`) was removed, and Coder does not ship an interactive Coder Agents TUI.
Use the web UI for interactive chat and direct API calls for automation.
The table below maps the removed commands to their Chats API equivalents.

| Removed Tasks CLI   | Chats equivalent                       |
| ------------------- | -------------------------------------- |
| `coder task create` | Web UI or `POST /chats`                |
| `coder task list`   | Web UI or `GET /chats`                 |
| `coder task logs`   | `GET /chats/{chat}/stream` (WebSocket) |
| `coder task pause`  | `POST /chats/{chat}/interrupt`         |
| `coder task resume` | Send a follow-up message to the chat   |
