# Conversations

A conversation holds a chat and everything it refers to: the messages, and the documents, files, and web resources attached to them. CKEditor AI answers from that content, or proposes edits to it. The API is used by the editor’s [AI Chat](../../../../ckeditor5/latest/features/ai/ckeditor-ai-chat.md) feature. The endpoints are documented in the [Conversations](https://ai.cke-cs.com/v1/docs#tag/Conversations), [Conversation Documents](https://ai.cke-cs.com/v1/docs#tag/Conversation-Documents), [Conversation Files](https://ai.cke-cs.com/v1/docs#tag/Conversation-Files), and [Conversation Messages](https://ai.cke-cs.com/v1/docs#tag/Conversation-Messages) sections of the API reference.

<a id="request-and-response">

## Request and response

The flow is three calls: create the conversation, upload what the message refers to, and send the message.

<a id="create-a-conversation">

### Create a conversation

```http
POST /v1/conversations
Content-Type: application/json
Authorization: Bearer <your-token>

{
  "id": "my-conversation-123",
  "group": "research"
}
```

<a id="upload-a-document-or-a-file">

### Upload a document or a file

Upload an HTML document before a message references it:

```http
POST /v1/conversations/my-conversation-123/documents
Content-Type: application/json
Authorization: Bearer <your-token>

{
  "content": "<h1>Hello, world!</h1>"
}
```

Response:

```json
{
  "id": "doc-123"
}
```

A file goes to a different endpoint. Send `POST /v1/conversations/{conversationId}/files` as `multipart/form-data` with the file in a `file` field:

```http
POST /v1/conversations/my-conversation-123/files
Content-Type: multipart/form-data; boundary=----boundary
Authorization: Bearer <your-token>

------boundary
Content-Disposition: form-data; name="file"; filename="report.pdf"
Content-Type: application/pdf

<binary content>
------boundary--
```

The format comes from the content type of the `file` part, and from the file extension when that content type is `application/octet-stream`. An unsupported format is rejected with `415` and an `unsupported-file-type` code. To have the service download the file instead, post a JSON body with a `url` to the same endpoint.

See the [Conversation Documents](https://ai.cke-cs.com/v1/docs#tag/Conversation-Documents) and [Conversation Files](https://ai.cke-cs.com/v1/docs#tag/Conversation-Files) references for the full schemas.

<a id="send-a-message">

### Send a message

```http
POST /v1/conversations/my-conversation-123/messages
Content-Type: application/json
Authorization: Bearer <your-token>

{
  "prompt": "Analyze the attached document and provide a summary of the key points",
  "model": "agent-1",
  "content": [
	{
	  "type": "document",
	  "id": "doc-123"
	}
  ],
  "capabilities": {
	"webSearch": {},
	"reasoning": {}
  }
}
```

`content` takes as many entries as the message needs, so a request can put a document and a web resource in front of the model at once:

```json
"content": [
  { "type": "document", "id": "doc-123" },
  { "type": "web-resource", "id": "web-123" }
]
```

The reply arrives as a stream. The first event carries the id of the reply, and the text follows in chunks:

```
event: message-metadata
data: {"messageId":"mesg-id-0000000000006"}

event: text-delta
data: {"textDelta":"The attached document "}

event: text-delta
data: {"textDelta":"has 10 words."}
```

[Streaming events](#streaming-events) lists every event a conversation stream can carry.

To be able to replay the reply after a dropped connection, send the message to the `/v1.1` endpoint instead. See [Resuming a dropped reply](#resuming-a-dropped-reply).

<a id="attachments-and-capabilities">

## Attachments and capabilities

* **Attachments:** a message references documents, files, and web resources uploaded to the conversation. Files can be PDF, DOCX, HTML, Markdown, plain text, PNG, or JPEG. [Conversation context permissions](permissions.md#conversation-context-permissions) set the formats a user may attach, and [File and content limits](rest-api.md#file-and-content-limits) set the sizes.
* **Web search:** `"webSearch": {}` in the `capabilities` object makes CKEditor AI search the web and read the results, so the reply can use current information. Each page it used arrives as a `source` event. The token needs `ai:conversations:websearch`.
* **Reasoning:** `"reasoning": {}` in the same object lets the model work through the request before it answers. The reasoning text is not returned. The stream sends a `reasoning` event for each step, so your interface can show that the reply is in progress. The token needs `ai:conversations:reasoning`, and [Reasoning](models.md#reasoning) lists which models support it.

<a id="streaming-events">

## Streaming events

`POST /v1/conversations/{conversationId}/messages` returns the reply over Server-Sent Events (SSE). A reply can search the web, reason, call tools, and set the conversation title. Each of those steps has its own event, so a conversation stream has more event types than the other endpoints:

* `message-metadata` arrives first and carries the `messageId` of the reply. Store it, because cancelling and resuming both use that id.
* `text-delta` carries the reply text, and `modification-delta` carries the document edits it proposes.
* `reasoning`, `web-search`, `document-read`, and `source` report work in progress, so your interface can show something while no text arrives.
* `mcp-tool-result`, `mcp-tool-notification`, and `hook-progress` arrive when a reply calls a tool on one of your [MCP servers](extensions/mcp-tools.md) or a [hook](extensions/hooks.md) you configured. A tool call needs no confirmation from the user, and the event arrives after the call ran.
* `conversation-title` arrives at the end, for a conversation created without a title. Store it with the conversation.
* `error` ends the stream, and a cancelled reply ends the same way.

See [Streaming protocol](streaming-protocol.md) for the payload of each event, the order they arrive in, and how to join the chunks of one modification.

<a id="resuming-a-dropped-reply">

### Resuming a dropped reply

If the connection drops during a reply, the part already generated is not lost. Send the message to `POST /v1.1/conversations/{conversationId}/messages` instead of the `/v1` endpoint. That version buffers the reply, so you can reconnect and replay the events you missed. The request and the response are otherwise the same as on `/v1`.

To reconnect, send a GET request to `/v1.1/conversations/{conversationId}/messages/{messageId}/stream` with the id of the last SSE event you received as the `lastEventId` query parameter. Without it, the whole reply is replayed. The same call recovers a message left in the `streaming` status. A DELETE request to the same URL cancels a reply in progress. See the [resume stream endpoint](https://ai.cke-cs.com/v1/docs#tag/Conversation-Messages-V1.1/operation/resumeStream) reference.

<a id="stored-conversations">

## Stored conversations

CKEditor AI stores the conversations and their messages, so you do not have to store them yourself.

> **Note**
>
> CKEditor AI deletes conversations after a retention period. See [Storage and retention](security-and-compliance.md#storage-and-retention).

The editor’s chat reads them back after a reload through these endpoints:

* `GET /v1/conversations` lists the user’s conversations with their titles and timestamps. The response is one page. Pass `nextCursor` back as the `cursor` parameter to get the next one, and stop when it arrives `null`.
* `GET /v1/conversations/{conversationId}/messages` returns the messages of one conversation. A `user` message carries what the user typed in `prompt` and its attachments in `content`. An `assistant` message carries the reply in `content`, and a `status` that is `completed`, `cancelled`, `error`, or `streaming`. A reply still `streaming` can be resumed, as [Resuming a dropped reply](#resuming-a-dropped-reply) describes.
* `PATCH /v1/conversations/{conversationId}` renames a conversation, and sets `pinned`, `group`, and `attributes`. A conversation created without a title gets one generated from its first message.

See the [Conversations](https://ai.cke-cs.com/v1/docs#tag/Conversations) and [Conversation Messages](https://ai.cke-cs.com/v1/docs#tag/Conversation-Messages) sections of the API reference for the query parameters and the full response schemas.

<a id="rating-a-reply">

### Rating a reply

Rate a reply by how many of its suggestions the user accepted. Send a PUT request to `/v1/conversations/{conversationId}/messages/{messageId}/ratings` with `positiveCount`, the number the user accepted, and `totalCount`, the number they received. If you send the request again for the same message, the new rating replaces the old one. Ratings work on messages sent through `/v1` and through `/v1.1`. See the [API reference](https://ai.cke-cs.com/v1/docs#tag/Conversation-Messages/operation/addConversationMessageRating) for the schema.

<a id="permissions">

## Permissions

Access is set per token. `ai:conversations:read` covers listing conversations and reading their messages, and `ai:conversations:write` covers creating conversations and sending messages. Web search and reasoning need `ai:conversations:websearch` and `ai:conversations:reasoning`. See [Conversation permissions](permissions.md#conversation-permissions) for the full list, including the file formats a user may attach.

<a id="next-steps">

## Next steps

* **[REST API](rest-api.md)** lists every endpoint family and the mechanics they share.
* **[Streaming protocol](streaming-protocol.md)** defines the SSE events for every endpoint family.
* **[Permissions](permissions.md)** lists the scopes a token can carry.
* **[Context library](extensions/context-library.md)** stores prompts and reference files in your environment, and a message references them by id.

---

Full index of the Cloud Services documentation: [llms.txt](../../../llms.txt)
