Чаты
Шесть запросов, которые личный ключ может сделать с чатами: создать, читать, писать, останавливать и удалять.
Личный ключ действует от имени сотрудника, который его создал. Внешняя система по этому ключу создаёт чаты сотрудника, читает и отправляет в них сообщения, останавливает ход и удаляет чат. Здесь — шесть запросов, которые ключ открывает. Как получить ключ, описано на странице «Личный ключ».
Все запросы идут на адрес портала, по которому вы работаете в браузере. В примерах
он обозначен как https://portal.example.com. Ключ передаётся в заголовке
Authorization:
Authorization: Bearer sk_forge_...Заголовок обязателен в каждом запросе.
Типичный сценарий
Бот заводит чат по типу задачи, задаёт вопрос и дожидается ответа:
- Создайте чат запросом
POST /api/chat-sessions, передавtaskTypeId. Портал вернётidнового чата. - Отправьте сообщение запросом
POST /api/chat-sessions/<id>/messagesс текстом вtextи своимclientMessageId. - Держите соединение с потоком открытым, пока портал не завершит ход: поток закроется, когда ответ готов. Подробности — в разделе «Ожидание ответа».
- Прочитайте ответ. Это последнее сообщение с
role: "assistant"вdata.messages. - Если ход пошёл не так, остановите его запросом
POST /api/chat-sessions/<id>/stop. - Когда чат больше не нужен, удалите его запросом
DELETE /api/chat-sessions/<id>.
Ожидание ответа
Запрос POST /api/chat-sessions/<id>/messages открывает поток
text/event-stream. Поток сам говорит, когда ответ готов: он закрывается после
события message_complete (ход завершился), queued (чат был занят, ход
выполнится позже) или error (ход завершился ошибкой). Разбирать другие
события не нужно.
Держите соединение открытым, пока портал не завершит ход: если закрыть его
раньше, ход остановится, и последнее сообщение будет со статусом stopped.
Когда поток закрылся после message_complete, прочитайте ответ запросом
GET /api/chat-sessions/<id>: это последнее сообщение с role: "assistant" в
data.messages. Если поток закрылся после queued, опрашивайте
GET /api/chat-sessions/<id> с интервалом около трёх секунд, пока последнее
сообщение не станет ответом ассистента с финальным статусом.
Частичный текст ответа виден только в потоке (события text_delta); в ответе
GET /:id сообщение ассистента пустое, пока ход не завершён. Если хотите
видеть ответ по мере написания, читайте поток и держите его открытым.
Если ход остановили, последнее сообщение ассистента будет со статусом
stopped. Если он завершился ошибкой, со статусом failed и кодом в
errorCode.
Лимиты
На каждый запрос по ключу действуют два счётчика. Первый общий для всех шести запросов, 300 в минуту на пользователя. Второй отдельный для каждого запроса, считается по адресу и общий с браузером, который ходит в портал с того же адреса.
| Запрос | Лимит по адресу |
|---|---|
POST /api/chat-sessions | 20 в час |
GET /api/chat-sessions | 600 в час |
POST /api/chat-sessions/<id>/messages | 60 в час |
Остальные три запроса (GET /:id, POST /:id/stop, DELETE /:id) ограничены
только общим счётчиком 300 в минуту на пользователя.
Превышение отвечает кодом 429:
{ "error": { "code": "RATE_LIMITED", "message": "Слишком много попыток. Повторите через 1 минут." } }В примерах ответов показаны не все поля, а те, что нужны для работы. Реальный ответ может содержать и другие поля, опирайтесь на те, что описаны в таблицах.
Создать чат
Создаёт чат по типу задачи. Чат можно привязать к конкретной задаче, тогда ассистент отвечает с учётом её файлов и результата.
POST /api/chat-sessionsПоля запроса
Тело запроса — JSON.
| Поле | Тип | Обязательно | Значение | Допустимые значения |
|---|---|---|---|---|
taskTypeId | строка (uuid) | да | Тип задачи, по которому ведётся чат | uuid типа задачи |
taskId | строка (uuid) | нет | Задача, о которой идёт чат | uuid задачи или null |
sourceFileId | строка (uuid) | нет | Файл задачи, с которого начался чат | uuid файла или null |
userFolderIds | массив строк (uuid) | нет | Папки личной библиотеки, приложенные к чату | до 10, без повторов; по умолчанию пусто |
Пример
curl -X POST "https://portal.example.com/api/chat-sessions" \
-H "Authorization: Bearer sk_forge_..." \
-H "Content-Type: application/json" \
-d '{"taskTypeId": "7f2c9a1e-4b3d-4e5f-8a6b-1c2d3e4f5a6b"}'Ответ
Код 201.
{
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"taskTypeId": "7f2c9a1e-4b3d-4e5f-8a6b-1c2d3e4f5a6b",
"taskId": null,
"title": null,
"status": "active",
"visibility": "private",
"messageCount": 0,
"lastMessageAt": null,
"createdAt": "2026-09-28T09:15:00.000Z",
"updatedAt": "2026-09-28T09:15:00.000Z"
}
}Поля ответа
| Поле | Значение |
|---|---|
id | Идентификатор чата. Подставляется во все остальные запросы |
status | Состояние чата. У нового — active |
title | Название чата. У нового — null, появится после первого сообщения |
messageCount | Число сообщений. У нового — 0 |
lastMessageAt | Время последнего сообщения. У нового — null |
Ошибки
| Код | Когда |
|---|---|
400 | taskTypeId или taskId не uuid; либо у типа задачи не настроен чат; либо чат настроен на выведенную из обращения конфигурацию. Текст ошибки назовёт причину; выберите другой тип задачи или обратитесь к администратору |
404 | Типа задачи нет, он скрыт или доступен не всем, либо задача не найдена |
403 | Чат у типа задачи отключён, тип задачи системный, чат настроен на недоступную для типа конфигурацию, или чат открывается только после выполнения задачи |
429 | Превышен лимит 20 созданий в час с одного адреса или 300 запросов в минуту на пользователя |
Список чатов
Отдаёт список чатов. По умолчанию — чаты владельца ключа, которые он ещё не удалил.
GET /api/chat-sessionsПараметры запроса
Передаются в строке запроса.
| Параметр | Тип | Значение | Допустимые значения |
|---|---|---|---|
scope | строка | Чей список: свои, общие со мной или открытые | my (по умолчанию), shared-with-me, shared |
status | строка | Отбор по состоянию чата | active, closed, archived |
taskTypeId | строка (uuid) | Только чаты этого типа задачи | uuid типа задачи |
taskId | строка (uuid) | Только чаты этой задачи | uuid задачи |
taskQuery | строка | Подстрока в названии задачи или типа задачи | 1–200 символов |
q | строка | Полнотекстовый поиск по чатам и сообщениям владельца | 2–200 символов |
cursor | строка (uuid) | Продолжить список с этого чата | id чата из meta.nextCursor |
limit | число | Размер страницы | 1–50, по умолчанию 20 |
Пример
curl "https://portal.example.com/api/chat-sessions?limit=20" \
-H "Authorization: Bearer sk_forge_..."Ответ
Код 200.
{
"data": [
{
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"title": "Сколько продаж за сентябрь",
"status": "active",
"messageCount": 2,
"lastMessageAt": "2026-09-28T09:16:04.000Z",
"createdAt": "2026-09-28T09:15:00.000Z",
"taskType": {
"id": "7f2c9a1e-4b3d-4e5f-8a6b-1c2d3e4f5a6b",
"slug": "sales-summary",
"name": "Сводка по продажам",
"icon": "clipboard-list",
"browserControlEnabled": false
},
"task": {
"id": "3d4e5f6a-0000-0000-0000-000000000001",
"title": "Продажи за сентябрь 2026",
"status": "done"
},
"browserControlEnabled": false
}
],
"meta": { "nextCursor": null }
}Поля ответа
| Поле | Значение |
|---|---|
data[].id | Идентификатор чата |
data[].title | Название чата |
data[].status | Состояние чата |
data[].messageCount | Число сообщений |
data[].lastMessageAt | Время последнего сообщения |
data[].taskType.name | Название типа задачи |
data[].task.title | Название связанной задачи, если чат привязан к задаче |
meta.nextCursor | id последнего чата страницы. Передайте его в cursor, чтобы получить следующую страницу. null, если страниц больше нет |
С параметром q ответ другой: список совпадений с фрагментом текста.
{
"data": [
{
"sessionId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"source": "message",
"snippet": "…за сентябрь 2026 было <em>148 продаж</em>…",
"sortTs": "2026-09-28T09:16:04.000Z"
}
]
}source — откуда совпадение, meta или message. snippet — фрагмент текста
вокруг совпадения.
Ошибки
| Код | Когда |
|---|---|
400 | Неверный cursor, taskTypeId или taskId (не uuid), limit больше 50, q короче двух символов |
429 | Превышен лимит 600 запросов в час с одного адреса или 300 запросов в минуту на пользователя |
Чат и его сообщения
Отдаёт чат и его сообщения. Это запрос, по которому клиент дожидается ответа.
GET /api/chat-sessions/<id>Параметры запроса
Передаются в строке запроса.
| Параметр | Тип | Значение | Допустимые значения |
|---|---|---|---|
id | строка (uuid) | Идентификатор чата | uuid чата |
before | строка (uuid) | Показать сообщения раньше этого | id сообщения |
limit | число | Число сообщений | по умолчанию 50, потолок 100 |
Пример
curl "https://portal.example.com/api/chat-sessions/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d" \
-H "Authorization: Bearer sk_forge_..."Ответ
Код 200.
{
"data": {
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"title": "Сколько продаж за сентябрь",
"status": "active",
"canWrite": true,
"isStreaming": false,
"messages": [
{
"id": "1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e",
"role": "user",
"content": "Сколько продаж за сентябрь и сколько из них закрыто?",
"status": "completed",
"isError": false,
"authorName": "Анна Смирнова",
"createdAt": "2026-09-28T09:16:00.000Z"
},
{
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"role": "assistant",
"content": "За сентябрь 2026 было 148 продаж, 121 закрыто, 27 в работе.",
"status": "completed",
"isError": false,
"authorName": null,
"createdAt": "2026-09-28T09:16:04.000Z"
}
]
},
"meta": { "hasMore": false }
}Поля ответа
| Поле | Значение |
|---|---|
data.isStreaming | true, пока ассистент составляет ответ; false, когда ответ готов |
data.canWrite | Может ли владелец писать в этот чат |
data.messages | Сообщения чата, от старых к новым |
data.messages[].role | user — сообщение владельца, assistant — ответ |
data.messages[].content | Текст сообщения |
data.messages[].status | completed, stopped или failed |
data.messages[].isError | true, если ход завершился ошибкой |
data.messages[].errorCode | Код ошибки, если isError — true |
data.messages[].authorName | Имя автора сообщения. У ответа ассистента — null |
meta.hasMore | Есть ли ещё более старые сообщения. Если true, передайте id первого сообщения в before |
Ошибки
| Код | Когда |
|---|---|
400 | id не uuid |
404 | Чата с таким id нет или владелец его удалил |
403 | Чат не принадлежит владельцу ключа, не открыт и не общий с ним |
429 | Превышен лимит 300 запросов в минуту на пользователя |
Отправить сообщение
Отправляет сообщение в чат и запускает ход. Ответ на запрос — поток
text/event-stream, который закрывается, когда ход завершён. Держите
соединение открытым, пока портал не завершит ход (если закрыть его раньше, ход
остановится). Что делать после закрытия потока — в разделе «Ожидание ответа».
POST /api/chat-sessions/<id>/messagesПоля запроса
Тело запроса — JSON.
| Поле | Тип | Обязательно | Значение | Допустимые значения |
|---|---|---|---|---|
id | строка (uuid) | да | Идентификатор чата | uuid чата |
text | строка | да | Текст сообщения | 1–32000 символов; не может начинаться со слеш-команды |
clientMessageId | строка (uuid) | да | Свой идентификатор сообщения | uuid, который генерирует клиент |
attachedFileIds | массив строк (uuid) | нет | Файлы чата, приложенные к сообщению | до 20; по умолчанию пусто |
clientMessageId нужен для повторной отправки. Если запрос оборвался и вы
отправили то же сообщение с тем же clientMessageId, портал не создаст дубль,
а повторит ход по уже сохранённому сообщению.
Личный ключ файлы чата не загружает и не перечисляет — эти запросы доступны
только в портале. Поле attachedFileIds принимает идентификаторы файлов,
которые уже загружены в чат в портале.
Пример
curl -sN --max-time 600 -X POST "https://portal.example.com/api/chat-sessions/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d/messages" \
-H "Authorization: Bearer sk_forge_..." \
-H "Content-Type: application/json" \
-d '{"text": "Сколько продаж за сентябрь и сколько из них закрыто?", "clientMessageId": "c0ffee00-0000-0000-0000-000000000001"}' \
> /dev/nullОтвет
Код 200, тип text/event-stream. Поток несёт события, из которых клиенту по
ключу нужно одно — message_complete, он означает, что ход завершился:
event: message_start
data: {"role":"assistant"}
event: text_delta
data: {"content":"За сентябрь "}
event: message_complete
data: {"messageId":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","totalDurationMs":4180,"generatedFiles":[]}Если ход уже выполняется в этом чате, поток закроется событием queued
({"reason":"busy"}) без message_complete. Сообщение сохранится, ход
выполнится позже, и ответ появится при следующем опросе.
Поля ответа
| Поле | Значение |
|---|---|
messageId | Идентификатор сообщения ассистента. Его можно найти в data.messages при опросе |
totalDurationMs | Сколько миллисекунд занял ход |
generatedFiles | Файлы, которые ассистент создал в ходе ответа |
Ошибки
До начала потока запрос может ответить обычной ошибкой.
| Код | Когда |
|---|---|
400 | text пустой или длиннее 32000 символов, clientMessageId не uuid, текст начинается со слеш-команды |
404 | Чата с таким id нет или владелец его удалил |
403 | В чат нельзя писать: он архивный, файл не из этого чата, или у владельца нет права на запись |
409 | Чат закрыт. Личный ключ чат не возобновляет — создайте новый чат запросом POST /api/chat-sessions; закрытый остаётся в списке |
429 | Превышен лимит 60 сообщений в час с одного адреса или 300 запросов в минуту на пользователя |
Остановить ход
Останавливает ход, который выполняется прямо сейчас. Запрос идемпотентен: если
активного хода нет, портал ответит stopped: false и ничего не сломает.
POST /api/chat-sessions/<id>/stopПоля запроса
Тело запроса не нужно.
| Поле | Тип | Обязательно | Значение | Допустимые значения |
|---|---|---|---|---|
id | строка (uuid) | да | Идентификатор чата | uuid чата |
Пример
curl -X POST "https://portal.example.com/api/chat-sessions/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d/stop" \
-H "Authorization: Bearer sk_forge_..."Ответ
Код 200.
{ "data": { "stopped": true } }Поля ответа
| Поле | Значение |
|---|---|
stopped | true, если ход был остановлен; false, если активного хода не было |
Ошибки
| Код | Когда |
|---|---|
400 | id не uuid |
404 | Чата с таким id нет или владелец его удалил |
403 | У владельца нет права на запись в этот чат |
429 | Превышен лимит 300 запросов в минуту на пользователя |
Удалить чат
Удаляет чат. На портале это та же операция, что кнопка «Удалить чат» в
интерфейсе. После удаления чат исчезает из списка, а запрос
GET /api/chat-sessions/<id> отвечает 404.
DELETE /api/chat-sessions/<id>Поля запроса
Тело запроса не нужно.
| Поле | Тип | Обязательно | Значение | Допустимые значения |
|---|---|---|---|---|
id | строка (uuid) | да | Идентификатор чата | uuid чата |
Пример
curl -X DELETE "https://portal.example.com/api/chat-sessions/9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d" \
-H "Authorization: Bearer sk_forge_..."Ответ
Код 204, тело ответа пустое.
Поля ответа
Полей нет. Успех означает код 204.
Ошибки
| Код | Когда |
|---|---|
400 | id не uuid |
404 | Чата с таким id нет или он принадлежит другому сотруднику |
429 | Превышен лимит 300 запросов в минуту на пользователя |