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.
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; base URL, authentication and error conventions are in the HTTP API overview.
| Operation | Endpoint |
|---|---|
| Check whether Halo is still working on a reply in one conversation | GET /api/agent/generating/:conversationId |
| Start a new Halo turn in a conversation | POST /api/agent/message |
| List conversations Halo is currently working on | GET /api/agent/sessions |
| Stop whatever Halo is currently doing in a conversation | POST /api/agent/stop |
| List the on-demand toolsets available to a conversation | POST /api/agent/toolsets/list |
| List conversations in a space | GET /api/spaces/:spaceId/conversations |
| Create an empty conversation | POST /api/spaces/:spaceId/conversations |
| Read a conversation with its messages | GET /api/spaces/:spaceId/conversations/:conversationId |
| Update a conversation title or metadata | PUT /api/spaces/:spaceId/conversations/:conversationId |
| Delete a conversation 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 |
| Star or unstar a conversation | POST /api/spaces/:spaceId/conversations/:conversationId/star |
Check whether Halo is still working on a reply in one conversation
GET /api/agent/generating/:conversationId Assistant
- Pairs with
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. |
Response
{success:true,data:boolean}Example
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 Assistant
- Starts Halo working in the conversation and returns as soon as the turn is accepted:
success: truemeans 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/:conversationIdwith 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,xhighormax; overridesthinkingEnabled, 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, 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
{
"spaceId": "<spaceId>",
"conversationId": "<conversationId>",
"message": "Summarize the activity log"
}Response
{success:true} // no data — the turn runs after the call returnsExample
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 Assistant
Response
{success:true,data:string[]} // array of conversationId, each one currently generating a replyExample
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 Assistant
conversationIdis optional. Leave it out (or send{}) to stop everything Halo is doing.
Request body
{
"conversationId": "<conversationId>"
}Response
{success:true}Example
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 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
{
"spaceId": "<spaceId>",
"conversationId": "<conversationId>"
}Response
{success:true,data:[{id:string,displayName:string,summary:string,open:boolean}]}Example
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 Assistant
Path parameters
| Name | Description |
|---|---|
spaceId | Workspace id, from GET /api/spaces. The Halo Workspace is always halo-temp. |
Response
{
"success": true,
"data": [
{
"id": "<uuid>",
"title": "…",
"starred": false
}
]
}Example
curl -s "$HALO_URL/api/spaces/<spaceId>/conversations" \
-H "Authorization: Bearer $HALO_TOKEN"Create an empty conversation
POST /api/spaces/:spaceId/conversations Assistant
- Creates an empty conversation. To make Halo work in it, call
POST /api/agent/messagewith its id. - Optional body field
reasoningEffort:off,minimal,low,medium,high,xhighormax— 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. The Halo Workspace is always halo-temp. |
Request body
{
"title": "Weekly report"
}Response
{
"success": true,
"data": {
"id": "<uuid>",
"title": "Weekly report"
}
}Example
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 Assistant
- Long conversations return a lot of text. To read only what is new, pass
?from=<messageId>: messages start at that message (inclusive) and the response carriesmessagesFrom. An unknown id returns the whole conversation. - Each message has its own
id; it is themessageIdthatGET /api/spaces/:spaceId/conversations/:conversationId/messages/:messageId/thoughtstakes.
Path parameters
| Name | Description |
|---|---|
spaceId | Workspace id, from GET /api/spaces. The Halo Workspace is always halo-temp. |
conversationId | Conversation id, from GET /api/spaces/:spaceId/conversations. |
Query parameters: from
Response
{
"success": true,
"data": {
"id": "<uuid>",
"messages": [
{
"id": "<uuid>",
"role": "user",
"content": "…"
}
]
}
}Example
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 Reversible Assistant
- modelSourceId + modelId (always both; sourceId is a uuid from
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. The Halo Workspace is always halo-temp. |
conversationId | Conversation id, from GET /api/spaces/:spaceId/conversations. |
Request body
{
"title": "Renamed conversation"
}Response
{"success":true,"data":{...updated conversation}}Example
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 Irreversible Assistant
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. The Halo Workspace is always halo-temp. |
conversationId | Conversation id, from GET /api/spaces/:spaceId/conversations. |
Response
{
"success": true
}Example
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 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. The Halo Workspace is always halo-temp. |
conversationId | Conversation id, from GET /api/spaces/:spaceId/conversations. |
messageId | Message id, from the messages returned by GET /api/spaces/:spaceId/conversations/:conversationId. |
Response
{
"success": true,
"data": [
{
"id": "…",
"type": "…",
"content": "…",
"timestamp": "…",
"toolName": "…",
"toolInput": {},
"toolOutput": "…"
}
]
}Example
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 Reversible Assistant
Path parameters
| Name | Description |
|---|---|
spaceId | Workspace id, from GET /api/spaces. The Halo Workspace is always halo-temp. |
conversationId | Conversation id, from GET /api/spaces/:spaceId/conversations. |
Request body
{
"starred": true
}Response
{
"success": true
}Example
curl -sX POST "$HALO_URL/api/spaces/<spaceId>/conversations/<conversationId>/star" \
-H "Authorization: Bearer $HALO_TOKEN" \
-H "Content-Type: application/json" \
-d '{"starred":true}'