---
title: "Conversations API: start and manage conversations"
description: "Halo HTTP API for conversations: start a turn of work, stop it, see what is running, and list, read, rename, star and delete conversations."
type: "reference"
audience: ["developer"]
lang: "en"
canonical: "https://hello-halo.cc/docs/en/developers/api/conversation.html"
last_updated: "2026-10-19T00:11:17+08:00"
source: "Halo 3.0.4 docs"
---
# API: Conversations

Halo HTTP API for conversations: start a turn of work, stop it, see what is running, and list, read, rename, star and delete conversations.

Conversations are the threads between a user and Halo's assistant inside a workspace (`space` in the API paths). Use these operations to start work in a conversation, follow and stop it, and manage the conversation list. Chats with a Digital Human are on [API: Digital Humans](https://hello-halo.cc/docs/en/developers/api/digital-human.html).

Paths are relative to your Halo base URL, and every request carries the access password. Set `$HALO_URL` and `$HALO_TOKEN` as in the [quickstart](https://hello-halo.cc/docs/en/developers/quickstart.html); base URL, authentication and error conventions are in the [HTTP API overview](https://hello-halo.cc/docs/en/developers/api/).

| Operation | Endpoint |
| --- | --- |
| [Check whether Halo is still working on a reply in one conversation](#get-api-agent-generating-conversationid) | `GET /api/agent/generating/:conversationId` |
| [Start a new Halo turn in a conversation](#post-api-agent-message) | `POST /api/agent/message` |
| [List conversations Halo is currently working on](#get-api-agent-sessions) | `GET /api/agent/sessions` |
| [Stop whatever Halo is currently doing in a conversation](#post-api-agent-stop) | `POST /api/agent/stop` |
| [List the on-demand toolsets available to a conversation](#post-api-agent-toolsets-list) | `POST /api/agent/toolsets/list` |
| [List conversations in a space](#get-api-spaces-spaceid-conversations) | `GET /api/spaces/:spaceId/conversations` |
| [Create an empty conversation](#post-api-spaces-spaceid-conversations) | `POST /api/spaces/:spaceId/conversations` |
| [Read a conversation with its messages](#get-api-spaces-spaceid-conversations-conversationid) | `GET /api/spaces/:spaceId/conversations/:conversationId` |
| [Update a conversation title or metadata](#put-api-spaces-spaceid-conversations-conversationid) | `PUT /api/spaces/:spaceId/conversations/:conversationId` |
| [Delete a conversation](#delete-api-spaces-spaceid-conversations-conversationid)  (Irreversible) | `DELETE /api/spaces/:spaceId/conversations/:conversationId` |
| [Read the reasoning and tool calls behind one message](#get-api-spaces-spaceid-conversations-conversationid-messages-messageid-thoughts) | `GET /api/spaces/:spaceId/conversations/:conversationId/messages/:messageId/thoughts` |
| [Star or unstar a conversation](#post-api-spaces-spaceid-conversations-conversationid-star) | `POST /api/spaces/:spaceId/conversations/:conversationId/star` |

## Check whether Halo is still working on a reply in one conversation {#get-api-agent-generating-conversationid}

`GET /api/agent/generating/:conversationId`  (Assistant)

- Pairs with [`POST /api/agent/stop`](#post-api-agent-stop) — check this before deciding whether there is anything to stop

**Path parameters**

| Name | Description |
| --- | --- |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |

**Response**

```ts
{success:true,data:boolean}
```

**Example**

```bash
curl -s "$HALO_URL/api/agent/generating/<conversationId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Start a new Halo turn in a conversation {#post-api-agent-message}

`POST /api/agent/message`  (Assistant)

- Starts Halo working in the conversation and returns as soon as the turn is accepted: `success: true` means accepted, not answered. The reply is written afterwards.
- Follow the reply over the WebSocket after subscribing to the conversation, or poll [`GET /api/agent/generating/:conversationId`](#get-api-agent-generating-conversationid) with a growing interval (2 s, then double) and read the conversation when it is done.
- Optional body fields: `resumeSessionId`, `thinkingEnabled` (boolean), `reasoningEffort` (`off`, `minimal`, `low`, `medium`, `high`, `xhigh` or `max`; overrides `thinkingEnabled`, but a level the user chose for this conversation wins), `knowledgeBaseId`, `images` (base64 attachments; the whole JSON body must stay under 100 KB).
- Start work in a conversation you created with [`POST /api/spaces/:spaceId/conversations`](#post-api-spaces-spaceid-conversations), so your turn never interrupts one the user is having.
- A turn can stop to ask the user a question. The user answers it in the Halo app, and the turn waits until then.

**Request body**

```json
{
  "spaceId": "<spaceId>",
  "conversationId": "<conversationId>",
  "message": "Summarize the activity log"
}
```

**Response**

```ts
{success:true}  // no data — the turn runs after the call returns
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/agent/message" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spaceId":"<spaceId>","conversationId":"<conversationId>","message":"Summarize the activity log"}'
```

## List conversations Halo is currently working on {#get-api-agent-sessions}

`GET /api/agent/sessions`  (Assistant)

**Response**

```ts
{success:true,data:string[]}  // array of conversationId, each one currently generating a reply
```

**Example**

```bash
curl -s "$HALO_URL/api/agent/sessions" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Stop whatever Halo is currently doing in a conversation {#post-api-agent-stop}

`POST /api/agent/stop`  (Assistant)

- `conversationId` is optional. Leave it out (or send `{}`) to stop everything Halo is doing.

**Request body**

```json
{
  "conversationId": "<conversationId>"
}
```

**Response**

```ts
{success:true}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/agent/stop" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"conversationId":"<conversationId>"}'
```

## List the on-demand toolsets available to a conversation {#post-api-agent-toolsets-list}

`POST /api/agent/toolsets/list`  (Assistant)

- Read-only: lists the on-demand capabilities (toolsets in the API) a conversation can use and whether each is open. The user opens and closes them in the composer under **＋ › Capabilities**.

**Request body**

```json
{
  "spaceId": "<spaceId>",
  "conversationId": "<conversationId>"
}
```

**Response**

```ts
{success:true,data:[{id:string,displayName:string,summary:string,open:boolean}]}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/agent/toolsets/list" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"spaceId":"<spaceId>","conversationId":"<conversationId>"}'
```

## List conversations in a space {#get-api-spaces-spaceid-conversations}

`GET /api/spaces/:spaceId/conversations`  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |

**Response**

```json
{
  "success": true,
  "data": [
    {
      "id": "<uuid>",
      "title": "…",
      "starred": false
    }
  ]
}
```

**Example**

```bash
curl -s "$HALO_URL/api/spaces/<spaceId>/conversations" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Create an empty conversation {#post-api-spaces-spaceid-conversations}

`POST /api/spaces/:spaceId/conversations`  (Assistant)

- Creates an empty conversation. To make Halo work in it, call [`POST /api/agent/message`](#post-api-agent-message) with its id.
- Optional body field `reasoningEffort`: `off`, `minimal`, `low`, `medium`, `high`, `xhigh` or `max` — how hard the model thinks. Leave it out to follow the model's configured effort.
- Optional body field `ephemeral` (boolean): for a view that shows the transcript itself. The conversation is left out of every list and search, and deleted at the next start of Halo unless deleted before. Leave it out for a conversation the user should see.

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |

**Request body**

```json
{
  "title": "Weekly report"
}
```

**Response**

```json
{
  "success": true,
  "data": {
    "id": "<uuid>",
    "title": "Weekly report"
  }
}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/spaces/<spaceId>/conversations" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Weekly report"}'
```

## Read a conversation with its messages {#get-api-spaces-spaceid-conversations-conversationid}

`GET /api/spaces/:spaceId/conversations/:conversationId`  (Assistant)

- Long conversations return a lot of text. To read only what is new, pass `?from=&lt;messageId&gt;`: messages start at that message (inclusive) and the response carries `messagesFrom`. An unknown id returns the whole conversation.
- Each message has its own `id`; it is the `messageId` that [`GET /api/spaces/:spaceId/conversations/:conversationId/messages/:messageId/thoughts`](#get-api-spaces-spaceid-conversations-conversationid-messages-messageid-thoughts) takes.

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |

**Query parameters**: `from`

**Response**

```json
{
  "success": true,
  "data": {
    "id": "<uuid>",
    "messages": [
      {
        "id": "<uuid>",
        "role": "user",
        "content": "…"
      }
    ]
  }
}
```

**Example**

```bash
curl -s "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Update a conversation title or metadata {#put-api-spaces-spaceid-conversations-conversationid}

`PUT /api/spaces/:spaceId/conversations/:conversationId`  (Reversible)  (Assistant)

- modelSourceId + modelId (always both; sourceId is a uuid from [`GET /api/config`](https://hello-halo.cc/docs/en/developers/api/settings.html#get-api-config)) pin the account and model the conversation runs on. A pin naming an account that no longer exists is not rejected: the conversation runs on the current global account until it is pinned again.

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |

**Request body**

```json
{
  "title": "Renamed conversation"
}
```

**Response**

```ts
{"success":true,"data":{...updated conversation}}
```

**Example**

```bash
curl -sX PUT "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"Renamed conversation"}'
```

## Delete a conversation {#delete-api-spaces-spaceid-conversations-conversationid}

`DELETE /api/spaces/:spaceId/conversations/:conversationId`  (Irreversible)  (Assistant)

::: danger Irreversible
This cannot be undone, and nothing goes to a trash folder. Make sure it is what the user wants before you call it.
:::

- Removes the conversation file and its reasoning history from disk. There is no backup.

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |

**Response**

```json
{
  "success": true
}
```

**Example**

```bash
curl -sX DELETE "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Read the reasoning and tool calls behind one message {#get-api-spaces-spaceid-conversations-conversationid-messages-messageid-thoughts}

`GET /api/spaces/:spaceId/conversations/:conversationId/messages/:messageId/thoughts`  (Assistant)

- Wrong ids return an empty array, not a 404 — an empty result does not prove the message had no thoughts.
- toolInput and toolOutput are the raw arguments and results of that turn, so this gets long fast. Read it to diagnose what Halo actually did, not as a way to read a conversation.

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |
| `messageId` | Message id, from the messages returned by [`GET /api/spaces/:spaceId/conversations/:conversationId`](#get-api-spaces-spaceid-conversations-conversationid). |

**Response**

```json
{
  "success": true,
  "data": [
    {
      "id": "…",
      "type": "…",
      "content": "…",
      "timestamp": "…",
      "toolName": "…",
      "toolInput": {},
      "toolOutput": "…"
    }
  ]
}
```

**Example**

```bash
curl -s "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>/messages/<messageId>/thoughts" \
  -H "Authorization: Bearer $HALO_TOKEN"
```

## Star or unstar a conversation {#post-api-spaces-spaceid-conversations-conversationid-star}

`POST /api/spaces/:spaceId/conversations/:conversationId/star`  (Reversible)  (Assistant)

**Path parameters**

| Name | Description |
| --- | --- |
| `spaceId` | Workspace id, from [`GET /api/spaces`](https://hello-halo.cc/docs/en/developers/api/workspace.html#get-api-spaces). The Halo Workspace is always `halo-temp`. |
| `conversationId` | Conversation id, from [`GET /api/spaces/:spaceId/conversations`](#get-api-spaces-spaceid-conversations). |

**Request body**

```json
{
  "starred": true
}
```

**Response**

```json
{
  "success": true
}
```

**Example**

```bash
curl -sX POST "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>/star" \
  -H "Authorization: Bearer $HALO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"starred":true}'
```
