Reference: Bot REST API
REST API, которым бот отправляет сообщения в каналы/DM, загружает файлы, ведёт Agent Runs и создаёт Execution Tasks.
Base URL
https://api.partyflow.ruАдрес вашей инсталляции PartyFlow. Во всех примерах ниже используется $BASE как переменная.
Authentication
Все запросы требуют Bearer token:
Authorization: Bearer fri_bot_<token>Токен имеет формат fri_bot_<base64url>, генерируется при создании бота в UI (Integrations → Bots → Create) и показывается один раз. Сохраните сразу.
При утечке — Regenerate token в UI. Старый перестаёт работать мгновенно.
Карта endpoint'ов
| Сценарий | Endpoint | Что делает |
|---|---|---|
| Сообщения | POST /api/v1/bot/messages |
Отправляет сообщение; top-level attachments принимает файлы из Bot Files API. |
| Сообщения | PATCH /api/v1/bot/messages/{message_id} |
Редактирует только content и metadata_json сообщения этого бота. Файлы через этот endpoint не меняются. |
| Файлы | POST /api/v1/bot/files/upload_sessions |
Создаёт short-lived upload URL и возвращает file_id. |
| Файлы | POST /api/v1/bot/files/{file_id}/confirm |
Подтверждает успешную загрузку и переводит файл в ready. |
| Файлы | GET /api/v1/bot/files/{file_id}/download_url?conversation_id={uuid} |
Возвращает short-lived URL для скачивания файла, доступного этому боту. |
| Execution Tasks | POST /api/v1/bot/execution_tasks |
Создаёт task widget и одноразовый runtime_capability.token для сценариев, где runtime агента не хранит bot token. |
| Execution Tasks | GET /api/v1/bot/execution_tasks/{widget_id} |
Возвращает public snapshot task. |
| Execution Tasks | PATCH /api/v1/bot/execution_tasks/{widget_id} |
Обновляет task по sequence. |
| Execution Tasks | POST /api/v1/bot/execution_tasks/{widget_id}/cancel |
Отменяет task. |
| Agent Runs | POST /api/v1/bot/agent_runs |
Создаёт long-running ответ и placeholder-сообщение. |
| Agent Runs | PATCH /api/v1/bot/agent_runs/{run_id} |
Обновляет статус; terminal completed может принять final attachments. |
| Agent Runs | GET /api/v1/bot/agent_runs/{run_id} |
Возвращает текущее состояние run. |
| Agent Runs | POST /api/v1/bot/agent_runs/{run_id}/cancel |
Отменяет run. |
| Бот и каналы | GET /api/v1/bot/me |
Проверяет token и текущую конфигурацию бота. |
| Бот и каналы | POST /api/v1/bot/conversations/{id}/join |
Добавляет бота в групповой канал. |
| Бот и каналы | POST /api/v1/bot/dm |
Создаёт или возвращает DM с пользователем. |
| События | POST /api/v1/bot/interactions/{interaction_id}/respond |
Отвечает на interactive event из Poll API. |
| События | GET /api/v1/channels/{conversation_id}/messages |
Читает историю канала для контекста. |
| События | GET /api/v1/bot/stream |
SSE stream сообщений из DM. |
Endpoints
POST /api/v1/bot/messages
Отправить сообщение в канал, тред или уже созданный DM с ботом.
Request body:
{
"conversation_id": "<uuid>",
"content": "Hello from bot!",
"display_name": "Standup Bot",
"display_avatar_url": "https://cdn.example.com/bot-avatar.png",
"parent_message_id": "<uuid>",
"metadata_json": "{\"version\":1,\"blocks\":[...]}",
"attachments": [{"file_id": "<uuid>"}]
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
conversation_id |
string (uuid) | Да | ID канала, треда или DM, куда слать сообщение. DM можно получить через POST /api/v1/bot/dm или пользовательский direct-чат с ботом. |
content |
string | Да, если нет attachments |
Markdown-текст сообщения. До 4000 символов. Для отправки используйте именно content; поле text в этом endpoint'е не принимается. |
display_name |
string | Нет | Переопределяет имя бота для этого сообщения. |
display_avatar_url |
string | Нет | Переопределяет аватар бота для этого сообщения. HTTPS only. |
parent_message_id |
string (uuid) | Нет | ID родительского/root-сообщения — ответ приходит в тред. thread_id временно принимается как legacy alias. |
metadata_json |
string | Нет | JSON-строка с attachments/blocks/buttons — см. reference/message-format.md и reference/interactive-components.md. До 32 KiB. Для интерактивных блоков нужен callback URL или event_delivery_mode="poll". |
attachments |
array | Нет | Файлы [{ "file_id": "..." }], загруженные и подтверждённые через Bot Files API, максимум 15. Нужен хотя бы content или один attachment. Это не Slack metadata_json.attachments. |
Response (200):
{
"ok": true,
"message_id": "<uuid>",
"attachment_status": "attached"
}attachment_status появляется только для сообщений с файловыми attachments:
attached означает, что PartyFlow уже связал файлы с сообщением; pending —
сообщение создано, платформа продолжит best-effort attach retry; failed —
файлы не удалось связать из-за постоянной ошибки.
Ошибки:
| Status | Причина |
|---|---|
| 400 | Невалидный JSON, отсутствует conversation_id, нет ни content ни attachments, content > 4000 символов, невалидный display_avatar_url, файл ещё не ready. |
| 401 | Невалидный или отозванный token. |
| 403 | Бот не состоит в канале или файл относится к другой conversation/space. Сначала вызовите /api/v1/bot/conversations/{id}/join. |
| 404 | Файл не найден для текущего bot token. |
| 503 | Платформа временно недоступна. Ретраить с backoff. |
| 500 | Внутренняя ошибка. Ретраить с backoff. |
Rate limit: 10 msg/sec на канал.
Async slash response: если запрос содержит заголовок
X-PartyFlow-Trigger-Id, PartyFlow считает его финальным ответом на custom
slash command. В этом режиме body поддерживает content и optional
metadata_json; conversation_id, parent_message_id, thread_id и bot_id
нельзя переопределить body-полями, routing берётся из сохранённого trigger
context. Trigger одноразовый и живёт 5 минут.
Файловые attachments в async slash response не поддерживаются.
PATCH /api/v1/bot/messages/{message_id}
Полностью заменить текст и metadata_json у сообщения, автором которого является
этот же бот.
Request body:
{
"content": "Updated text",
"metadata_json": "{\"version\":1,\"blocks\":[...]}"
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
content |
string | Да | Новый Markdown-текст, до 4000 символов. |
metadata_json |
string | Нет | Новая metadata JSON-строка. Если поле не передано, metadata очищается. |
Response (200):
{"ok": true, "message_id": "<uuid>"}PATCH использует bot token и не позволяет редактировать чужие сообщения:
платформа проверяет, что сообщение создано этим же ботом.
PATCH /api/v1/bot/messages/{message_id} не принимает файловые
attachments. Чтобы добавить или заменить файлы, загрузите их через
Bot Files API и отправьте новое POST /api/v1/bot/messages;
для долгих AI-ответов final files передаются через terminal
PATCH /api/v1/bot/agent_runs/{run_id}.
Bot Files API
Файлы Bot REST загружаются через short-lived upload URL, без проксирования байтов через Bot REST API. Используется то же приватное хранилище, что и для обычных chat attachments.
Файл привязан к текущему bot token, space и conversation. Его можно прикрепить только к сообщению этого же бота в той же conversation.
Как загрузить файл и прикрепить к сообщению
- Создайте upload session через
POST /api/v1/bot/files/upload_sessions. - Загрузите байты напрямую по
upload.upload_urlметодом изupload.methodи с заголовками изupload.headers. - Подтвердите загрузку через
POST /api/v1/bot/files/{file_id}/confirm. - Передайте
attachments: [{"file_id":"..."}]вPOST /api/v1/bot/messagesили в terminalPATCH /api/v1/bot/agent_runs/{run_id}приstatus="completed".
Минимальная последовательность:
curl -X POST "$BASE/api/v1/bot/files/upload_sessions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"conversation_id\":\"$CHANNEL_ID\",\"file_name\":\"report.pdf\",\"file_size\":1048576,\"mime_type\":\"application/pdf\"}"
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary @report.pdf
curl -X POST "$BASE/api/v1/bot/files/$FILE_ID/confirm" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"conversation_id\":\"$CHANNEL_ID\"}"
curl -X POST "$BASE/api/v1/bot/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"conversation_id\":\"$CHANNEL_ID\",\"content\":\"Отчёт готов\",\"attachments\":[{\"file_id\":\"$FILE_ID\"}]}"$FILE_ID, $UPLOAD_URL, HTTP method и upload headers берите из ответа
upload_sessions. До confirm файл имеет статус uploading и не может быть
прикреплён к сообщению.
POST /api/v1/bot/files/upload_sessions
Создать upload session.
{
"conversation_id": "<uuid>",
"file_name": "report.pdf",
"file_size": 1048576,
"mime_type": "application/pdf"
}Response (200):
{
"ok": true,
"upload": {
"file_id": "<uuid>",
"upload_url": "https://storage.example/...",
"method": "PUT",
"headers": {"Content-Type": "application/pdf"},
"expires_at": 1779523200
},
"file": {
"file_id": "<uuid>",
"conversation_id": "<uuid>",
"message_id": "",
"file_type": "document",
"file_name": "report.pdf",
"mime_type": "application/pdf",
"file_size": 1048576,
"status": "uploading",
"created_at_unix": 1779522900,
"width": 0,
"height": 0
}
}Загрузите файл напрямую:
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary @report.pdfОтвет не содержит постоянных идентификаторов приватного хранилища или постоянный download URL.
POST /api/v1/bot/files/{file_id}/confirm
Подтвердить upload после успешного PUT.
{"conversation_id": "<uuid>"}PartyFlow проверит, что файл появился в приватном хранилище, сверит фактический
размер с лимитами и для generic application/octet-stream может уточнить file
type по magic bytes. После подтверждения файл получает status="ready" и
может быть передан в POST /api/v1/bot/messages.attachments или terminal
PATCH /api/v1/bot/agent_runs/{run_id}.
Response (200):
{"ok": true, "file": {"file_id": "<uuid>", "status": "ready"}}GET /api/v1/bot/files/{file_id}/download_url?conversation_id={uuid}
Вернуть short-lived URL для скачивания файла, доступного текущему боту.
Response (200):
{
"ok": true,
"file_id": "<uuid>",
"download_url": "https://storage.example/...",
"expires_at": 1779523500,
"file": {"file_id": "<uuid>", "status": "ready"}
}Ошибки: 400 — невалидный body/размер/MIME или файл ещё не ready; 401 —
невалидный token; 403 — бот не состоит в conversation или файл из другого
space/conversation; 404 — файл не найден для текущего token; 503 —
платформа временно недоступна. Тело ошибки сейчас имеет форму
{"error":"..."} без стабильного machine-readable code.
Rate limit: Bot Files endpoints используют тот же per-bot×conversation
fixed-window лимит, что и Bot REST writes. При превышении PartyFlow отвечает
429 + Retry-After.
Execution Tasks: widget-backed task UI
Execution Task — это управляемый task widget в чате. Бот создаёт task, обновляет публичный status/title/description и может связать task с Agent Run. Когда связанный Agent Run переходит в terminal status, PartyFlow обновляет task и прикрепляет только проверенные финальные файлы.
space_id, bot_id и actor нельзя передать в body: они всегда выводятся из
Bearer bot token.
Типовой flow для AI agent
- Получите пользовательский запрос через outgoing webhook, Poll API или SSE Stream для DM.
- Если работа должна быть видимой как отдельная задача, создайте
execution_taskчерезPOST /api/v1/bot/execution_tasks. Сохранитеwidget_idиexecution_task.sequence. - Создайте Agent Run через
POST /api/v1/bot/agent_runsи передайте этотwidget_id. Виджет должен быть создан тем же bot actor в той же conversation; произвольный чужойwidget_idбудет отклонён. - Пока агент работает, обновляйте Agent Run статусами
gathering_context,using_tool,finalizingи т.п. Если нужно отдельно поменять task UI, вызывайтеPATCH /api/v1/bot/execution_tasks/{widget_id}с текущимexecution_task.sequence. - Финальные файлы сначала загрузите через Bot Files API, затем передайте их в
terminal
PATCH /api/v1/bot/agent_runs/{run_id}. PartyFlow перенесёт только проверенные ссылки на финальные файлы в task widget. - Человеческий reviewer принимает или отклоняет результат в widget UI. Bot REST v1 не подменяет reviewer и не должен отправлять prompts, raw reasoning, tool payloads, stack traces или секреты в public fields.
agent_run.sequence и execution_task.sequence — разные версии. Для Agent Run
увеличивайте run sequence монотонно. Для task PATCH используйте последний
execution_task.sequence, полученный из create/get/patch ответа.
POST /api/v1/bot/execution_tasks
Создать execution task. Запрос идемпотентен по Idempotency-Key header или
body-полю idempotency_key.
{
"idempotency_key": "build-124:<message_uuid>",
"conversation_id": "<uuid>",
"parent_message_id": "<uuid>",
"agent_run_id": "<uuid>",
"title": "Проверить failed build",
"description": "CI вернул ошибку на main",
"allowed_actions": ["update", "cancel"]
}Для source по parent_message_id поле conversation_id обязательно: root
message должен существовать в этой беседе. Можно передать thread_id вместо
parent_message_id. Если передан только conversation_id, PartyFlow создаст
silent bot-сообщение-якорь в этой беседе и привяжет widget к thread от этого
сообщения.
Response (200):
{
"ok": true,
"execution_task": {
"widget_id": "<uuid>",
"conversation_id": "<uuid>",
"agent_run_id": "<uuid>",
"status": "open",
"title": "Проверить failed build",
"description": "CI вернул ошибку на main",
"public_text": "",
"error_code": "",
"sequence": 1,
"artifacts": [],
"created_at": "2026-05-24T10:00:00Z",
"updated_at": "2026-05-24T10:00:00Z",
"closed_at": null
},
"runtime_capability": {
"token": "fri_exec_...",
"token_prefix": "fri_exec_abcd1234",
"allowed_actions": ["update", "cancel"],
"expires_at": "2026-05-24T11:00:00Z"
}
}runtime_capability.token показывается один раз. Он scoped к текущему
space_id, widget_id, optional agent_run_id, allowed actions и expiry.
В текущем Bot REST v1 все endpoints выше аутентифицируются Bearer bot token:
не передавайте fri_exec_ token вместо fri_bot_. Capability возвращается для
сценариев, где runtime агента не хранит bot token, и будет использоваться только в
endpoints, которые явно документируют auth через fri_exec_.
GET /api/v1/bot/execution_tasks/{widget_id}
Вернуть safe public snapshot task. Bot token видит только task'и своего
space/bot. В ответе могут прийти статусы open, in_progress, blocked,
completed, accepted, rejected, cancelled или closed.
PATCH /api/v1/bot/execution_tasks/{widget_id}
Применить действие к task. sequence обязателен и должен равняться текущему
execution_task.sequence.
{
"action": "update",
"status": "in_progress",
"sequence": 2,
"title": "Проверить failed build",
"description": "Checks passed",
"public_text": "Deploy started",
"idempotency_key": "build-124:<message_uuid>:2"
}Поддерживаемые v1 actions: update, complete, fail, cancel. Для
update используйте task statuses open, in_progress, blocked или
completed. Action complete переводит task в completed, fail — в
blocked, cancel — в cancelled.
POST /api/v1/bot/execution_tasks/{widget_id}/cancel
Закрыть task как cancelled. Endpoint не принимает body; если вам нужен
optimistic-lock через sequence, используйте PATCH с action cancel.
Ошибки: 400 — невалидный JSON/UUID/title/idempotency/action/status; 401 —
невалидный token; 403 — bot не имеет доступа к task/conversation; 404 —
task не найден; 409 — stale sequence или terminal state; 429 — rate
limit; 503 — нужные возможности временно недоступны на инстансе.
Agent Runs: responsive AI replies
Agent Run помогает долгим AI-ботам не оставлять пользователя в тишине. Бот
создаёт placeholder-сообщение, а затем обновляет его безопасными статусами.
Пользователи видят обычные события сообщения: сначала message.new, затем
message.edited. Отдельного stream/API agent.run.* нет.
POST /api/v1/bot/agent_runs
Создать run и placeholder-сообщение.
Headers:
Idempotency-Key: <stable-key-per-user-request>Idempotency-Key обязателен. Повтор POST с тем же ключом вернёт уже
созданный run и не создаст второй placeholder. Ключ уникален в рамках текущего
bot token; допустимы A-Z a-z 0-9 . _ : -, максимум 128 символов. Если header
неудобен, можно передать тот же ключ в body-поле idempotency_key; если
указаны оба источника, значения должны совпадать.
Request body:
{
"idempotency_key": "user-message-<uuid>",
"conversation_id": "<uuid>",
"trigger_message_id": "<uuid>",
"widget_id": "<uuid>",
"parent_message_id": "<uuid>",
"content": "Запрос принят"
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
idempotency_key |
string | Нет, если есть header | Body fallback для обязательного Idempotency-Key. |
conversation_id |
string (uuid) | Да | Канал, тред или DM, куда отправить placeholder. |
trigger_message_id |
string (uuid) | Да | Сообщение пользователя, на которое отвечает агент. Должно существовать в том же space и conversation. |
widget_id |
string (uuid) | Нет | Existing Execution Task widget, созданный тем же bot actor в этой conversation. Он получит terminal update этого run. |
parent_message_id |
string (uuid) | Нет | Root-сообщение для thread reply. Должно существовать в том же space и conversation. thread_id временно принимается как legacy alias. |
content |
string | Нет | Видимый fallback-текст placeholder, до 4000 символов. Если не передан, PartyFlow покажет текст статуса. |
space_id, bot_id, status_text и bot_metadata_json нельзя передать в
body. Они выводятся из bot token и разрешённого сервером списка.
Response (200):
{
"ok": true,
"agent_run": {
"id": "<uuid>",
"idempotency_key": "user-message-<uuid>",
"conversation_id": "<uuid>",
"trigger_message_id": "<uuid>",
"message_id": "<uuid>",
"widget_id": "<uuid>",
"status": "accepted",
"status_text": "Запрос принят",
"sequence": 1,
"is_terminal": false,
"public_text": "Запрос принят",
"error_code": "",
"bot_metadata_json": "{\"version\":1,\"kind\":\"agent_run\",\"agent_run\":{\"run_id\":\"<uuid>\",\"status\":\"accepted\",\"status_text\":\"Запрос принят\",\"sequence\":1,\"is_terminal\":false,\"trigger_message_id\":\"<uuid>\",\"widget_id\":\"<uuid>\",\"updated_at\":\"2026-05-20T10:00:00Z\",\"completed_at\":null,\"error_code\":\"\"}}",
"attachments": [],
"attachment_status": "none",
"started_at": "2026-05-20T10:00:00Z",
"updated_at": "2026-05-20T10:00:00Z",
"completed_at": null
}
}PATCH /api/v1/bot/agent_runs/{run_id}
Обновить статус. Non-terminal статусы могут доставляться с короткой задержкой,
terminal статусы приоритизируются. Клиентам следует считать источником истины
последнее message.edited.
{
"status": "completed",
"sequence": 8,
"public_text": "Готово, отчёт во вложении.",
"error_code": "",
"attachments": [{"file_id": "<uuid>"}]
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
status |
string | Да | Один из публичных статусов ниже. |
sequence |
int64 | Да | Монотонная версия от бота. Повтор того же sequence идемпотентен только с тем же payload; меньший или конфликтующий sequence вернёт 409. |
public_text |
string | Нет | Видимый текст сообщения, до 4000 символов. Для completed обязателен. content принимается как alias. |
error_code |
string | Нет | Безопасный код ошибки для failed: только буквы, цифры и _, до 64 символов. |
attachments |
array | Нет | Финальные файлы [{ "file_id": "..." }], максимум 15. Разрешены только при status="completed"; файлы должны быть загружены через Bot Files API, иметь status="ready" и принадлежать тому же боту/conversation. |
Response (200): тот же объект agent_run, что и в POST.
Идемпотентность для одинакового sequence работает только если нормализованные
status / public_text / error_code полностью совпадают с уже сохранённым
состоянием. Такой повтор вернёт текущий объект. Тот же sequence с другим
payload считается stale update и вернёт 409.
Нельзя отправлять raw reasoning, prompt, token, tool payload, stack trace или
секреты. В публичном UI показываются только public_text, server-side
status_text и безопасный error_code.
| Status | status_text |
Terminal |
|---|---|---|
accepted |
Запрос принят |
no |
queued |
В очереди |
no |
gathering_context |
Ищу контекст |
no |
using_tool |
Использую инструмент |
no |
waiting_tool |
Жду ответ инструмента |
no |
waiting_user |
Жду ответа пользователя |
no |
finalizing |
Готовлю финальный ответ |
no |
completed |
Готово |
yes |
failed |
Не удалось выполнить |
yes |
cancelled |
Остановлено |
yes |
expired |
Остановлено по тайм-ауту |
yes |
GET /api/v1/bot/agent_runs/{run_id}
Вернуть текущее состояние run. Bot token видит только свои run'ы.
Response (200): тот же объект agent_run, что и в POST.
POST /api/v1/bot/agent_runs/{run_id}/cancel
Отменить run от имени bot runtime. Это не пользовательский cancel UI; он может
быть добавлен позже поверх того же статуса cancelled.
Response (200): тот же объект agent_run, что и в POST.
Поля объекта agent_run:
| Поле | Null/omitted | Описание |
|---|---|---|
idempotency_key |
всегда присутствует | Ключ create-запроса. Нужен bot runtime'у для диагностики retry. |
parent_message_id |
отсутствует, если run не является reply/thread reply | Root-сообщение, к которому привязан placeholder. |
trigger_message_id |
присутствует после успешного create | Сообщение пользователя, запустившее run. |
message_id |
присутствует после успешного create | Placeholder bot message, который будет редактироваться статусами. |
widget_id |
отсутствует, если run не связан с execution task | Task widget, который получает terminal update с проверенными финальными файлами. |
attachments |
всегда массив | Финальные file_id, переданные при status="completed". |
attachment_status |
всегда присутствует | none, pending, attached или failed. |
completed_at |
null до terminal статуса |
Время перехода в completed / failed / cancelled / expired. |
Rate limits: create ограничен per bot + conversation, update/cancel — per
bot + run, дополнительно есть global per-bot write cap. При превышении PartyFlow
вернёт 429 и Retry-After.
Ошибки: 400 — невалидный body/UUID/status/sequence/content/idempotency
key; 401 — невалидный token; 403 — бот не состоит в conversation; 404 —
run не найден для этого бота; 409 — terminal run, stale sequence или
повторное использование Idempotency-Key для другого conversation/trigger;
429 — rate limit; 503 — временная недоступность платформы или rate
limiter.
GET /api/v1/bot/me
Информация о текущем боте. Полезно для проверки, что токен жив, и для отображения имени/аватара в вашей UI.
Response (200):
{
"ok": true,
"bot": {
"id": "<uuid>",
"space_id": "<uuid>",
"display_name": "Standup Bot",
"avatar_url": "https://cdn.example.com/bot-avatar.png",
"is_active": true,
"event_types": ["MESSAGE_CREATED", "REACTION_ADDED"],
"channel_ids": ["<uuid>"],
"event_delivery_mode": "poll",
"webhook_url": ""
}
}| Поле | Тип | Описание |
|---|---|---|
id |
string (uuid) | ID бота. |
space_id |
string (uuid) | Space, которому принадлежит бот. |
display_name |
string | Имя бота для отображения. |
avatar_url |
string | URL аватара; может быть пустой строкой. |
is_active |
bool | Активен ли бот. |
event_types |
string[] | События, на которые подписан бот (MESSAGE_CREATED, REACTION_ADDED, ...). |
channel_ids |
string[] | Каналы, где бот получает события. Пустой массив означает все каналы space'а. |
event_delivery_mode |
string | "none", "poll" или "webhook". |
webhook_url |
string | URL push webhook'а при event_delivery_mode="webhook"; пустая строка иначе. webhook_signing_secret здесь не возвращается. |
Если бот отключён админом или token revoked, Bot REST запросы обычно возвращают HTTP 401. Поле is_active в успешном ответе помогает явно проверить статус текущего бота.
POST /api/v1/bot/conversations/{id}/join
Добавить бота как участника канала. Бот появится в списке участников, сможет отправлять сообщения.
Идемпотентно: повторный вызов для уже добавленного бота — no-op, возвращает HTTP 200.
Проверки:
- Бот должен принадлежать тому же space, что и канал.
- Канал должен существовать.
- Для
/joinподдерживаются только групповые каналы. DM создаются черезPOST /api/v1/bot/dmили пользователем в UI и не требуют join.
Response (200):
{"ok": true}Ошибки:
| Status | Причина |
|---|---|
| 400 | Канал не найден, space mismatch, неподдерживаемый тип канала. |
| 401 | Невалидный/отозванный token. |
| 503 | Платформа временно недоступна. Ретраить с backoff. |
POST /api/v1/bot/interactions/{interaction_id}/respond
Асинхронный ответ на interactive-событие, которое poll-бот получил через
GET /api/v1/bot/events. Синтаксис body такой же, как у sync callback:
{"update_message": {"text": "Approved", "metadata_json": ""}}{"send_message": {"text": "Deploy started", "metadata_json": ""}}{"ephemeral_text": "Действие принято."}{"open_modal": {"title": "Next step", "fields": []}}{"noop": true}Response (200):
{"ok": true, "outcome": "update_message"}interaction_id одноразовый. По умолчанию он живёт 15 минут. Для цепочек
модалок можно вернуть open_modal после modal.submit; глубина ограничена
настройкой инстанса.
4. Чтение истории канала
GET /api/v1/channels/{conversation_id}/messagesВозвращает окно истории канала — для AI-ботов, которым нужен context (/summarize, long-memory, indexing). Бот должен быть участником канала — иначе 403.
Query параметры:
| Параметр | Тип | По умолчанию | Описание |
|---|---|---|---|
limit |
int 1..100 | 50 | Макс. количество сообщений в ответе. |
before_msg_index |
int64 ≥ 0 | 0 (новейшие) | Курсор пагинации в прошлое. Передавайте next_msg_index из предыдущего ответа, чтобы листать вглубь истории. |
after_msg_index |
int64 ≥ 0 | — | Курсор пагинации в будущее: "дай мне сообщения после этой точки". Используется для catch-up после реконнекта. |
around_msg_index |
int64 ≥ 0 | — | Окно вокруг конкретного сообщения — N сообщений до и после. Полезно когда outgoing webhook триггернул бота и ему нужен контекст триггерующего сообщения. |
updated_since |
ISO 8601 | — | Delta-sync: вернёт сообщения с modified_at > T. Индексер-боты используют для эффективной синхронизации без ре-пагинации всей истории. |
thread_id |
string | — | Если указан, возвращаются только сообщения треда (root + replies). Фильтр делается chat-side — над-выборка не шлётся в ответе. |
Ограничения: только один из before_msg_index, after_msg_index, around_msg_index можно передать в одном запросе. Если указано больше одного — ответ 400.
Успешный ответ 200:
{
"messages": [
{
"id": "msg_uuid",
"text": "Hello",
"author_id": "user_uuid",
"author_name": "Alice",
"author_type": "user",
"author_subtype": "",
"created_at": "2026-04-17T10:00:00.000Z",
"modified_at": "2026-04-17T10:00:00.000Z",
"msg_index": 42,
"parent_message_id": null,
"is_deleted": false,
"is_system": false,
"system_type": null,
"system_data": null,
"reaction_count": 0,
"attachments": [],
"bot_metadata_json": null,
"mentions": []
}
],
"has_more": true,
"next_msg_index": 23
}Сортировка — новейшие первые. Для pagination передавайте next_msg_index последнего ответа как before_msg_index следующего запроса; когда has_more=false — история исчерпана.
System-события (is_system: true) — joins/leaves/renames. Ценны для AI summarizers:
{
"id": "sys-msg",
"is_system": true,
"system_type": "user_joined",
"system_data": {
"user_id": "user-42",
"user_name": "Alice",
"target_id": "conv-1",
"target_name": "#general",
"old_value": null,
"new_value": null
},
"text": "",
"author_id": "",
"msg_index": 5
}Привилегии и приватность:
read_receipts,edit_history,delivery_status,parent_preview,mention_detailsНЕ возвращаются ботам (privacy).system_data.extra_jsonскрыто — поле может содержать device/IP; если нужно поле из extra_json, запросите добавление typed атрибута через platform team.- Для
is_deleted=trueполяtextобнуляются (tombstone),attachmentsвсегда[]; id/author/timestamps сохраняются для audit. mentions— толькоuser_idупомянутых пользователей, без display names (для имён используйтеauthor_nameтого, кто @упомянут — но только если он автор самого сообщения).attachmentsиmentionsвсегда массивы, никогдаnull— JSON-schema клиенты итерируют без nil-checks.
Rate limits:
| Scope | Лимит |
|---|---|
| Per bot × channel | 10 запросов / минуту |
| Per bot (все каналы) | 100 запросов / минуту |
Превышение любого лимита → HTTP 429 + заголовок Retry-After: <секунд-до-окна>.
Ошибки:
| Status | Причина |
|---|---|
| 400 | Некорректный limit/before_msg_index/path. |
| 401 | Невалидный/отозванный token. |
| 403 | Бот не участник канала ИЛИ канал в чужом space. |
| 429 | Rate limit. Читайте Retry-After и повторите после ожидания. |
| 502 | Платформа временно недоступна. |
Пример:
curl -H "Authorization: Bearer $TOKEN" \
"$BASE/api/v1/channels/$CHANNEL_ID/messages?limit=50&thread_id=$ROOT_MSG_ID"Типовой сценарий
BASE='https://api.partyflow.ru'
TOKEN='fri_bot_...'
CHANNEL_ID='<uuid-канала>'
# 1. Проверить, что бот жив
curl "$BASE/api/v1/bot/me" \
-H "Authorization: Bearer $TOKEN"
# 2. Вступить в канал (идемпотентно)
curl -X POST "$BASE/api/v1/bot/conversations/$CHANNEL_ID/join" \
-H "Authorization: Bearer $TOKEN"
# 3. Отправить сообщение
curl -X POST "$BASE/api/v1/bot/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"conversation_id\":\"$CHANNEL_ID\",\"content\":\"Good morning, team!\"}"Python
import requests
BASE = "https://api.partyflow.ru"
TOKEN = "fri_bot_..."
session = requests.Session()
session.headers.update({"Authorization": f"Bearer {TOKEN}"})
# Self-check
me = session.get(f"{BASE}/api/v1/bot/me").json()
print(f"Bot: {me['bot']['display_name']}, active: {me['bot']['is_active']}")
# Join channel (idempotent)
channel_id = "..."
session.post(f"{BASE}/api/v1/bot/conversations/{channel_id}/join")
# Send message
resp = session.post(
f"{BASE}/api/v1/bot/messages",
json={"conversation_id": channel_id, "content": "Hello from Python bot!"},
)
resp.raise_for_status()
print(resp.json())Node.js
const BASE = "https://api.partyflow.ru";
const TOKEN = "fri_bot_...";
const headers = { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json" };
// Self-check
const me = await fetch(`${BASE}/api/v1/bot/me`, { headers }).then(r => r.json());
console.log(`Bot: ${me.bot.display_name}, active: ${me.bot.is_active}`);
// Join
const channelId = "...";
await fetch(`${BASE}/api/v1/bot/conversations/${channelId}/join`, { method: "POST", headers });
// Send
const resp = await fetch(`${BASE}/api/v1/bot/messages`, {
method: "POST",
headers,
body: JSON.stringify({ conversation_id: channelId, content: "Hello from Node bot!" }),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
console.log(await resp.json());5. Создать DM с пользователем
POST /api/v1/bot/dmБот инициирует direct-чат с пользователем. Если DM уже существует — возвращается HTTP 200 с ID существующего conversation.
Request body:
{
"user_id": "<uuid-пользователя>"
}| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
user_id |
string (uuid) | Да | ID пользователя, с которым начать личку. Пользователь должен быть участником того же space'а. |
Response (200):
{
"ok": true,
"conversation_id": "<uuid>"
}Ошибки:
| Status | Причина |
|---|---|
| 400 | Отсутствует user_id, пользователь не найден в space'е, user_id == bot_id. |
| 401 | Невалидный/отозванный token. |
| 429 | Превышен rate limit — 1 запрос/сек на бота. |
6. SSE Stream — real-time сообщения из DM
GET /api/v1/bot/streamServer-Sent Events endpoint для получения сообщений из direct-чатов бота в реальном времени.
Auth: Bearer token в заголовке Authorization (как для всех bot endpoints).
Headers ответа:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-aliveФормат сообщений:
data: {"event":"message.new","message_id":"...","conversation_id":"...","author_id":"...","text":"...","msg_index":1042,"sent_at":"2026-05-02T12:00:00Z","conversation_context":{"conversation_id":"...","type":"chat","scope":"dm","is_direct":true,"is_public":false}}
Каждое сообщение завершается двумя \n. Поле data — JSON-строка.
Автор сообщения передаётся плоским полем author_id, как в Bot Event Polling API и outgoing webhook data. Объект author / author.user_id в SSE payload не возвращается.
conversation_context совпадает с payload у MESSAGE_CREATED в Bot Event Polling, Bot Webhook и outgoing webhook data. Для DM scope="dm" и is_direct=true; для публичных/приватных каналов scope будет public или private. Для тредов type="thread", а scope наследуется от родительской беседы; Call Thread из гостевого voice-чата дополнительно получает subtype="call_thread".
Keep-alive: если в течение 30 секунд нет сообщений, сервер шлёт:
:ping
Это пустой comment в SSE-спецификации; клиент должен игнорировать его, но использовать для определения «соединение живо».
Offline backlog: если бот был offline, сообщения накапливались в inbox (до 50 штук, TTL 24ч). При подключении backlog доставляется первым в том же SSE-потоке, затем сервер переключается на live-режим.
Пример на JavaScript (EventSource не поддерживает custom headers — используйте fetch):
const TOKEN = "fri_bot_...";
const BASE = "https://api.partyflow.ru";
const response = await fetch(`${BASE}/api/v1/bot/stream`, {
headers: { "Authorization": `Bearer ${TOKEN}` },
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
// Парсить SSE-фреймы: разделить по "\n\n", для каждого фрейма:
// - игнорировать если начинается с ":"
// - иначе убрать префикс "data: ", распарсить JSON
console.log(chunk);
}Обрыв соединения: рекомендуется reconnect с exponential backoff (начиная с 1с, max 30с). При reconnect backlog доставляется заново только если сообщения не были получены ранее — сервер atomically читает и удаляет inbox.
Ограничения:
- SSE работает только для DM. Сообщения из групповых каналов бот получает через outgoing webhooks, как раньше.
- Нельзя открывать более одного SSE-соединения на один bot token одновременно: новое соединение заменит предыдущее.
Связанное
- concepts/bots.md — концепция ботов (lifecycle, authentication, membership).
- guides/create-bot.md — пошаговый гайд от нуля до первого сообщения.
- guides/bot-interactive-quickstart.md — кнопки/selects/modals за 5-10 минут.
- reference/interactive-components.md — полный справочник interactive-схемы
metadata_json. - concepts/security.md — хранение bot tokens.