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

# Threads

> Persist conversation history across multiple completions

Threads are the durable conversation context behind multi-turn agent runs. Each thread is scoped to a single computer and stores the full message history so the AI can build on what it has already done. Pass a thread's ID into [Create chat completion](/api-reference/chat/completions) to continue a session.

<Info>
  Threads are created implicitly. Every call to `POST /v1/chat/completions` with a `computer_id` either continues an existing thread (when `thread_id` is passed) or creates a new one and returns its ID. Use these endpoints to list, inspect, rename, archive, or delete threads - you rarely need to create them by hand.
</Info>

## Endpoints

| Method   | Path                               | Purpose                                                |
| -------- | ---------------------------------- | ------------------------------------------------------ |
| `GET`    | `/api/chat/threads?desktopId={id}` | List threads for a computer.                           |
| `POST`   | `/api/chat/threads`                | Create an empty thread.                                |
| `GET`    | `/api/chat/threads/{id}`           | Get a thread with full message history.                |
| `PATCH`  | `/api/chat/threads/{id}`           | Update title, replace messages, archive, or unarchive. |
| `DELETE` | `/api/chat/threads/{id}`           | Delete a thread.                                       |
| `POST`   | `/api/chat/threads/{id}/title`     | Auto-generate a title with Claude Haiku.               |

**Base URL:** `https://www.orgo.ai`
**Auth:** `Authorization: Bearer sk_live_...` on every request.

***

## List threads

```
GET /api/chat/threads?desktopId={desktop_uuid}
```

Returns every thread the authenticated user owns for the given computer, including full message history.

### Query parameters

<ParamField query="desktopId" type="string" required>
  UUID of the computer (the `id` field from [Create computer](/api-reference/computers/create)). Threads are scoped per-computer; to list across computers, call this endpoint once per computer.
</ParamField>

### Response

<ResponseField name="threads" type="array">
  Array of thread objects, most recent first.

  <Expandable title="thread">
    <ResponseField name="id" type="string">Thread UUID.</ResponseField>
    <ResponseField name="remoteId" type="string">Same as `id`. Kept for compatibility with assistant-ui clients.</ResponseField>
    <ResponseField name="status" type="string">`active` or `archived`.</ResponseField>
    <ResponseField name="title" type="string">Human-readable title. Omitted if no title has been generated yet.</ResponseField>
    <ResponseField name="messages" type="array">Full message history - `[{ role, content }, ...]`. May be empty for brand-new threads.</ResponseField>
    <ResponseField name="updated_at" type="string">ISO 8601 timestamp of the last modification.</ResponseField>
  </Expandable>
</ResponseField>

### Example

<CodeGroup>
  ```python Python theme={null}
  import requests

  r = requests.get(
      "https://www.orgo.ai/api/chat/threads",
      params={"desktopId": "a3bb189e-8bf9-3888-9912-ace4e6543002"},
      headers={"Authorization": "Bearer sk_live_a3bb189e8bf93888"},
  )
  for t in r.json()["threads"]:
      print(t["id"], t.get("title", "(untitled)"))
  ```

  ```typescript TypeScript theme={null}
  const r = await fetch(
    "https://www.orgo.ai/api/chat/threads?desktopId=a3bb189e-8bf9-3888-9912-ace4e6543002",
    { headers: { Authorization: "Bearer sk_live_a3bb189e8bf93888" } },
  );
  const { threads } = await r.json();
  ```

  ```bash cURL theme={null}
  curl "https://www.orgo.ai/api/chat/threads?desktopId=a3bb189e-8bf9-3888-9912-ace4e6543002" \
    -H "Authorization: Bearer sk_live_a3bb189e8bf93888"
  ```
</CodeGroup>

```json theme={null}
{
  "threads": [
    {
      "id": "thr_01HX8W3Z6PN2Q1MRT7YV9K4BFA",
      "remoteId": "thr_01HX8W3Z6PN2Q1MRT7YV9K4BFA",
      "status": "active",
      "title": "GitHub search",
      "messages": [
        { "role": "user", "content": "Open github.com" },
        { "role": "assistant", "content": "Done - GitHub is open." }
      ],
      "updated_at": "2026-04-20T14:22:05.123Z"
    }
  ]
}
```

***

## Create thread

```
POST /api/chat/threads
```

Creates an empty thread bound to a computer. Only needed when you want a thread ID before making the first completion - otherwise, omit this call and let `POST /v1/chat/completions` create one for you.

### Request

<ParamField body="desktopId" type="string" required>
  UUID of the computer to attach the thread to.
</ParamField>

<ParamField body="localId" type="string">
  Optional client-side identifier. Echoed back as `externalId` in the response so clients can reconcile local and remote threads.
</ParamField>

### Response

Returns `201 Created`.

<ResponseField name="remoteId" type="string">The new thread's UUID. Use this as `thread_id` in subsequent chat completions.</ResponseField>
<ResponseField name="externalId" type="string">Mirror of `localId` from the request. Omitted if not supplied.</ResponseField>

### Example

<CodeGroup>
  ```python Python theme={null}
  import requests

  r = requests.post(
      "https://www.orgo.ai/api/chat/threads",
      headers={"Authorization": "Bearer sk_live_a3bb189e8bf93888"},
      json={"desktopId": "a3bb189e-8bf9-3888-9912-ace4e6543002"},
  )
  thread_id = r.json()["remoteId"]
  ```

  ```typescript TypeScript theme={null}
  const r = await fetch("https://www.orgo.ai/api/chat/threads", {
    method: "POST",
    headers: {
      Authorization: "Bearer sk_live_a3bb189e8bf93888",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ desktopId: "a3bb189e-8bf9-3888-9912-ace4e6543002" }),
  });
  const { remoteId } = await r.json();
  ```

  ```bash cURL theme={null}
  curl -X POST https://www.orgo.ai/api/chat/threads \
    -H "Authorization: Bearer sk_live_a3bb189e8bf93888" \
    -H "Content-Type: application/json" \
    -d '{"desktopId": "a3bb189e-8bf9-3888-9912-ace4e6543002"}'
  ```
</CodeGroup>

***

## Get thread

```
GET /api/chat/threads/{id}
```

Fetches a single thread with its full message history. 403 if the thread belongs to another user; 404 if it does not exist.

### Response

<ResponseField name="remoteId" type="string">Thread UUID.</ResponseField>
<ResponseField name="status" type="string">`active` or `archived`.</ResponseField>
<ResponseField name="title" type="string">Title if set, otherwise omitted.</ResponseField>
<ResponseField name="messages" type="array">Full message history in chronological order.</ResponseField>

***

## Update thread

```
PATCH /api/chat/threads/{id}
```

Updates title, replaces messages, or toggles archive state. Archive takes precedence over other fields when both are present.

### Request

<ParamField body="title" type="string">
  New human-readable title.
</ParamField>

<ParamField body="messages" type="array">
  Replaces the entire stored message history with this array. Use with care - this is a full overwrite, not an append.
</ParamField>

<ParamField body="archive" type="boolean">
  Set to `true` to archive. Archived threads are hidden from default list views but remain fetchable by ID.
</ParamField>

<ParamField body="unarchive" type="boolean">
  Set to `true` to restore an archived thread.
</ParamField>

### Response

<ResponseField name="remoteId" type="string">Thread UUID.</ResponseField>
<ResponseField name="status" type="string">Updated status (`active` or `archived`).</ResponseField>
<ResponseField name="title" type="string">Updated title if set.</ResponseField>

### Example

```bash theme={null}
curl -X PATCH https://www.orgo.ai/api/chat/threads/thr_01HX8W3Z6PN2Q1MRT7YV9K4BFA \
  -H "Authorization: Bearer sk_live_a3bb189e8bf93888" \
  -H "Content-Type: application/json" \
  -d '{"title": "GitHub research session"}'
```

***

## Delete thread

```
DELETE /api/chat/threads/{id}
```

Permanently deletes the thread and its message history. Prefer `PATCH` with `archive: true` if you might need the conversation back.

### Response

```json theme={null}
{ "success": true }
```

***

## Generate title

```
POST /api/chat/threads/{id}/title
```

Generates a short (3–6 word) title from the first few messages using Claude Haiku and saves it to the thread. Returns an assistant-ui-compatible text stream rather than JSON.

### Request

<ParamField body="messages" type="array" required>
  The messages to summarize. Only the first three are considered. Each message is `{ role, content }` where `content` may be a string or an array of `{ type: "text", text }` blocks.
</ParamField>

### Response

`text/plain` stream in the assistant-ui format:

```
0:"GitHub search session"
```

The generated title is also persisted to the thread, so a subsequent `GET` will include it in the `title` field.

***

## Using threads with completions

Threads compose with [chat completions](/api-reference/chat/completions) - you almost never manage them directly in production code:

```python theme={null}
# First turn - server creates the thread, returns its ID
first = client.chat.completions.create(
    model="claude-sonnet-4.6",
    messages=[{"role": "user", "content": "Open Chrome and go to github.com"}],
    extra_body={"computer_id": computer_id},
)
thread_id = first.orgo["thread_id"]

# Later turn - agent picks up where it left off
client.chat.completions.create(
    model="claude-sonnet-4.6",
    messages=[{"role": "user", "content": "Search for 'orgo'"}],
    extra_body={"computer_id": computer_id, "thread_id": thread_id},
)
```

## Errors

| Status | Meaning                                                  |
| ------ | -------------------------------------------------------- |
| 400    | `desktopId` or `messages` missing from the request body. |
| 401    | Missing or invalid `Authorization` header.               |
| 403    | The thread exists but belongs to a different user.       |
| 404    | Thread does not exist.                                   |
| 500    | Unexpected server error. Retry with backoff.             |

Error responses are JSON with a single `error` field:

```json theme={null}
{ "error": "desktopId is required" }
```
