Концепция: Bots
Bot account — именованный участник канала, от лица которого работает ваша интеграция. Он отправляет сообщения, читает историю (для AI-ботов), регистрирует кастомные slash-команды и обрабатывает нажатия кнопок. В отличие от webhook'а бот — это субъект в канале: у него есть имя, аватар, упоминания (@bot-name) и membership.
Эта страница — концепция: зачем нужен бот, чем он отличается от webhook'а, какой у него жизненный цикл и как с ним работать безопасно. Всю техническую часть (endpoints, параметры, примеры запросов) смотрите в reference/bot-rest-api.md.
Bot vs Webhook
Коротко: webhook — труба, бот — участник.
| Incoming webhook | Bot | |
|---|---|---|
| Идентичность в канале | Анонимная, либо настроенный для webhook'а display name | Именованный участник с @mention, аватаром, постоянным ID |
| Auth | Token в URL + опциональный HMAC | Bearer token в Authorization header |
| Направление | Только входящие POST → в канал |
Двустороннее: отправка, чтение, interactive, slash-команды |
| Membership | Автоматически привязан к одному каналу | Отдельная операция /join, бот может состоять в нескольких каналах |
| Используют | Grafana, GitLab CI, Sentry, Prometheus Alertmanager | Standup-боты, AI-ассистенты, approval-боты, deployment-боты |
Если цель — просто доставить alert из внешнего сервиса, бот не нужен: используйте webhook. Бот нужен, когда интеграции надо:
- Отвечать пользователям в канале как именованный участник (
@standup-bot). - Загружать и прикреплять файлы к сообщениям или final Agent Run updates.
- Читать историю канала (summarize, search, index).
- Регистрировать собственные slash-команды (
/deploy,/review). - Показывать кнопки / select menus / модалки с двусторонней логикой.
Lifecycle
create → store token → invite to channels → send / read messages → (optional) regenerate token → (optional) disable1. Create
Админ space'а создаёт бота в UI: Integrations → Bots → Create. Указывает:
name— системное имя (^[a-z0-9_-]{1,32}$), по нему бота можно @упоминать.display_name— что показывается в канале.description,avatar_url— опционально.
При создании PartyFlow возвращает raw-токен формата fri_bot_<base64url> и показывает его один раз. Token — SHA-256 hash которого хранится в БД; plaintext после closing диалога не восстановить.
2. Store token
Сохранить токен в secret manager (AWS Secrets Manager, HashiCorp Vault, Doppler, GitHub Actions secrets). Не хардкодить в исходниках, не коммитить в git.
Минимум прав для runtime: read-only доступ к секрету у того процесса, где крутится бот. Ротация — через UI (см. ниже).
3. Invite to channels
Бот не попадает в каналы автоматически. Для каждого канала, где он должен работать, вызываем:
POST /api/v1/bot/conversations/{conversation_id}/joinИдемпотентно. Повторный вызов возвращает HTTP 200 без дубликатов membership. Admin также может добавить бота вручную через UI канала.
Бот может состоять в неограниченном числе каналов одного space'а. Cross-space membership невозможно — если бот принадлежит space A, он не может быть приглашён в канал space B (возвращается HTTP 400 space mismatch).
4. Send / Read messages
- Send:
POST /api/v1/bot/messages— отправка сообщения от имени бота. Поддерживается thread reply черезthread_id, per-message overridedisplay_name/display_avatar_url. - Bot Files:
POST /api/v1/bot/files/upload_sessions→ direct upload →POST /api/v1/bot/files/{file_id}/confirm— загрузка файла для top-levelattachmentsв сообщении или terminal Agent Run update. - Agent Runs:
POST /api/v1/bot/agent_runs+PATCH /api/v1/bot/agent_runs/{run_id}— для долгих AI-ответов: сразу создаёт placeholder-сообщение и затем обновляет его безопасными статусами. - Execution Tasks:
POST /api/v1/bot/execution_tasks— task widget для долгой работы агента, где пользователи видят состояние, final artifacts и review/acceptance. - Read:
GET /api/v1/channels/{conversation_id}/messages— чтение истории канала с курсорамиbefore_msg_index/after_msg_index/around_msg_index, фильтромthread_id, delta-sync черезupdated_since. Privacy-фильтр применяется: ботам не возвращаютсяread_receipts,edit_history,delivery_status,parent_preview,mention_details. - DM:
POST /api/v1/bot/dm— создание direct-чата с пользователем,GET /api/v1/bot/stream— SSE-поток для real-time получения сообщений из DM. См. раздел DM с ботом ниже.
Полный справочник — в reference/bot-rest-api.md.
5. Regenerate token
Если токен утёк (попал в лог, git, скриншот) — Regenerate token в UI. Старый token становится невалидным немедленно (без grace period): следующий запрос с ним вернёт HTTP 401.
Плюс-эффект: после regenerate cache токена в PartyFlow инвалидируется, так что даже если процесс с старым токеном где-то ещё живёт, доступ у него пропадает в пределах секунд.
6. Disable
Admin может отключить бота (toggle is_active: false) без удаления. После этого:
- Все запросы с токенами бота возвращают
HTTP 401. - Membership в каналах сохраняется, но сообщения от бота не проходят.
GET /api/v1/bot/meс тем же токеном тоже возвращаетHTTP 401; полеis_activeв успешном ответе нужно для self-check активного токена.
Включение обратно — тоже toggle в UI. Автоматического re-enable после fix'а на стороне бота не предусмотрено: policy делается явным действием админа.
Полное удаление бота — отдельная операция Delete bot, она сносит membership во всех каналах, revoke'ает все токены, удаляет запись.
Authentication
Model
- Bot использует Bearer token в заголовке
Authorization: Bearer fri_bot_<token>на каждом REST-запросе. - Токен хранится в БД PartyFlow как SHA-256 hash, не plaintext. Это значит — при компрометации БД токен не восстановить, только инвалидировать.
- Токен связан с ботом one-to-many: у одного бота может быть несколько активных токенов (например, blue/green deploy),
Regenerateротирует все активные токены. - Валидация токена — timing-safe (
hmac.Equalна hash), так что перебор по времени ответа не работает.
Если токен утёк
- Немедленно Regenerate token в UI. Старый мёртв мгновенно.
- Обновить секрет в secret manager, перезапустить процесс бота с новым токеном.
- Посмотреть в логах space'а (admin UI), какие IP/UA использовали утёкший токен последние 24 часа — понять blast radius.
- Если бот проводил write-действия (отправлял сообщения, вступал в каналы): ревью audit-трейла канала. Webhook-подобная подделка через бота возможна только с валидным токеном, так что после regenerate новых write'ов быть не должно.
Bot token vs webhook signing secret
Разные концепции, не путать:
- Bot token (
fri_bot_...) — identity. Доказывает, что запрос делает именно этот бот. Аналог пароля. - Webhook signing secret (
whsec_...) — integrity. Доказывает, что тело запроса не изменили по дороге. Аналог TLS для HTTP, но на уровне приложения.
Бот использует только Bearer-token. HMAC-подпись бот проверяет только когда PartyFlow шлёт ему запросы (button click callback, custom slash callback, outgoing webhook) — тогда используется buttons_signing_secret / signing_secret webhook'а. См. concepts/security.md.
Membership
Membership бота в канале — явная запись в таблице участников, такая же как у обычного user'а. Это значит:
- Бот появляется в списке участников канала, в поиске по
@mention, в autocomplete. - Напрямую из приглашения в один канал бот не получает доступ к другим каналам того же space'а.
is_active: falseна боте — глобальный kill-switch, но не affects membership: после re-enable бот остаётся в тех же каналах.- Удаление бота (
Delete bot) каскадом сносит membership во всех каналах.
Нет auto-rejoin. Если кто-то выкинул бота из канала (/kick @bot), он там больше не состоит и должен быть заново приглашён — бот сам себя обратно не вступит, даже если его код сейчас зовёт /join. Это осознанно: админы должны уметь выгнать бота, и бот не должен это обходить.
Read-scope
Bot Read API позволяет боту получать историю канала под тем же Bearer auth, что и отправку. Используется для:
- AI-summarizers: "перескажи последние 50 сообщений" → бот читает историю и публикует summary.
- Long-memory агентов: бот хранит свой контекст о канале между запросами.
- Indexing / search: бот экспортирует сообщения во внешний search engine.
Важное из privacy-policy:
- Ботам не возвращаются:
read_receipts,edit_history,delivery_status,parent_preview,mention_details. Эти поля — user-to-user metadata, которая не должна утекать в AI-индекс. system_data.extra_jsonскрыто (может содержать device/IP). Если нужен конкретный typed атрибут — запрашивайте через platform team.is_deleted: true— сообщение возвращается как tombstone (id/author/timestamps сохранены,text= "",attachments= []). Для audit, но контент больше не видно.
Rate limit: 10 запросов/минуту на канал × 100 запросов/минуту на бота.
Полный справочник: reference/bot-rest-api.md → Чтение истории канала.
AI agents и task widgets
Для короткого ответа бот может просто отправить сообщение. Для долгой работы AI-агента лучше использовать две сущности вместе:
- Agent Run показывает пользователю, что агент принял запрос и в каком он runtime-статусе: ищет контекст, вызывает инструмент, финализирует ответ.
- Execution Task widget хранит долговечное состояние работы: title, description, task status, публичный результат, final artifacts и review flow.
Рекомендуемый порядок:
- Создайте
execution_taskв том же канале или треде, где пользователь дал запрос. - Создайте Agent Run с top-level
widget_id. - Обновляйте Agent Run для runtime-статусов. Обновляйте task widget только для изменений, которые должны жить как состояние задачи.
- На terminal Agent Run (
completed,failed,cancelled,expired) PartyFlow обновит связанный task и прикрепит только проверенные финальные файлы.
Ограничения безопасности:
- Бот может мутировать только task widgets, созданные тем же bot actor.
space_id,bot_idи actor всегда выводятся из Bearer token, не из body.- В public state нельзя класть prompts, chain-of-thought, raw tool payloads, stack traces, приватные идентификаторы файлов, long-lived URLs или секреты.
agent_run.sequenceиexecution_task.sequenceне взаимозаменяемы: храните оба значения отдельно.
Полный contract: reference/bot-rest-api.md → Execution Tasks.
DM с ботом
Бот может участвовать в личных переписках (direct messages) — как с человеком, так и наоборот.
Как создаётся DM
- Пользователь создаёт DM через обычный UI чата: "New direct message" → выбирает бота из списка участников space'а. Бекенд определяет, что peer — бот, и создаёт direct-чат.
- Бот инициирует DM сам:
POST /api/v1/bot/dmсuser_idцелевого пользователя. Пользователь должен быть участником того же space'а. Endpoint идемпотентен — повторный вызов вернёт тот жеconversation_id.
Как бот получает сообщения из DM
Для групповых каналов real-time события доставляются через outgoing webhooks (HTTP POST на ваш URL). Для DM добавлен SSE Stream:
GET /api/v1/bot/stream— Server-Sent Events endpoint.- Auth: тот же Bearer token.
- Каждое сообщение —
data: <json>\n\nс событиемmessage.new. - Payload сообщения совпадает с
MESSAGE_CREATEDв Poll/Webhook, плюс SSE-полеevent. Внутри естьconversation_context: для DM этоscope="dm"иis_direct=true. - Keep-alive
:pingкаждые 30 секунд. - Offline persistence: если бот не подключён, сообщения сохраняются во временный inbox (до 50, TTL 24ч). При следующем подключении backlog доставляется первым, затем поток переключается на live.
Как отличать DM, public/private и треды
Во всех bot-facing событиях сообщений (MESSAGE_CREATED, MESSAGE_UPDATED,
MESSAGE_DELETED, Bot Poll, Bot Webhook, outgoing webhook data и Bot DM SSE)
есть единый объект conversation_context.
type— raw conversation type:chat,channel,voice,threadили будущее значение как есть.scope— клиентский scope:dm,public,private.- Для тредов
scopeберётся от родительской беседы, аparent_conversation_id,parent_conversation_type,parent_is_publicпоказывают родителя. subtype="call_thread"ставится только для Call Thread гостевого voice-чата. В остальном такой чат остаётся обычнымtype="thread".
Старые flat-поля (conversation_id, thread_id, parent_message_id) остаются в payload для совместимости, но новый код должен использовать conversation_context как основной индикатор.
Почему разные механизмы для DM и каналов?
- Групповые каналы — много подписчиков, сложная routing-логика (filters, keywords, mentions), нужна надёжная доставка с retry. Outgoing webhook с HMAC и exponential backoff решает это.
- DM — ровно один получатель (бот), низкая latency важнее сложной retry-логики. SSE даёт мгновенную доставку без необходимости публиковать HTTPS endpoint на стороне бота.
Ограничения
- SSE работает только для DM. Попытка использовать его для группового канала не имеет смысла — бот в групповом канале не получит туда сообщения через SSE.
- Rate limit на
POST /api/v1/bot/dm— 1 запрос/сек на бота. - Одно SSE-соединение на bot token. Новое соединение заменит предыдущее.
Custom commands и Interactive
Бот может расширить функциональность канала двумя смежными фичами:
- Custom slash commands — бот регистрирует свою команду (
/deploy prod). Если бот работает вevent_delivery_mode="poll", invocation приходит черезGET /api/v1/bot/events; иначе PartyFlow шлёт HMAC-подписанный callback на URL команды. См. reference/slash-commands.md. - Interactive components — бот прикрепляет кнопки / select menus / модалки к сообщениям. При клике PartyFlow доставляет
button.click/select.submit/modal.submitлибо HMAC callback'ом, либо через Bot Poll API сinteraction_id. См. reference/interactive-components.md.
В callback mode эти фичи используют отдельные signing secrets — не путать с Bearer token'ом бота. В poll mode отдельный callback secret для доставки не нужен: бот забирает события авторизованным Bearer token'ом и отвечает на interactive-события через POST /api/v1/bot/interactions/{interaction_id}/respond.
Best practices
- Token hygiene. Один инсталляция бота — один токен. Не переиспользовать токен между dev/staging/prod. Если нужно — создавайте отдельных ботов (или используйте несколько токенов одного бота через
Regenerateдля blue/green). - Idempotent retry. PartyFlow не дедуплицирует
POST /api/v1/bot/messages— если вы ретраите5xx, считайте, что сообщение может задвоиться. Делайте сам контент idempotent (включайтеrequest_idв текст или проверяйте перед retry через Read API, что предыдущий POST не прошёл). - Graceful 401. После
Regenerate tokenстарые токены мгновенно недействительны. Бот должен уметь прочитать свежий секрет из secret manager и перезапустить HTTP-клиент, а не крэшить в бесконечный401-цикл. - Handle 403 on join. Если
send_messageвернул403, это значит бота выкинули из канала. СначалаPOST /api/v1/bot/conversations/{id}/joinи только потом retry send. - Backoff at 429. Уважайте
Retry-After. Для Bot Read API лимит 10 req/min/channel — если вы делаете summarize на большом канале, подождите окно вместо спама. - Не полагайтесь только на HTTP 200 как на health-check. Сначала
GET /api/v1/bot/me:401означает недействительный/перевыпущенный токен или отключённого бота, а при200проверяйте оба поля —ok: trueиbot.is_active: true. - Real-time для DM через SSE. Для direct-чатов бот может открыть
GET /api/v1/bot/stream(SSE) и получать сообщения в реальном времени. Для групповых каналов real-time по-прежнему доступен только через outgoing webhooks — SSE работает исключительно в DM. См. reference/bot-rest-api.md → SSE Stream. - Poll для серверов без публичного HTTPS. Если бот не может принять callback извне, включите
event_delivery_mode="poll"и забирайте message, slash и interactive-события черезGET /api/v1/bot/events. - Для долгих AI-ответов используйте Agent Runs. Не отправляйте "думаю..." отдельными сообщениями: создайте один run, обновляйте
sequenceмонотонно и завершайтеcompletedс финальнымpublic_text. Не передавайте raw reasoning, prompt'ы, token'ы, секреты или tool payloads. - Для агентских задач используйте Execution Task widget. Создайте task,
свяжите Agent Run через
widget_id, а финальные файлы передавайте только как полеattachmentsв terminal update Agent Run после проверки PartyFlow.
Что дальше
- reference/bot-rest-api.md — все endpoints, параметры, примеры.
- reference/bot-event-poll.md — long-polling доставки событий боту.
- reference/message-format.md — структура
bot_metadata_jsonдля rich-сообщений. - concepts/security.md — хранение токенов, проверка HMAC входящих callback'ов.
- reference/slash-commands.md — кастомные команды бота.
- reference/interactive-components.md — кнопки, select, модалки.