Reference: Message Format
Полное описание структурированных данных, которые отправитель (бот, incoming webhook) вкладывает в сообщение, чтобы канал отрендерил его rich — с цветной полоской, грид-полями, кнопками, attachments, вложениями.
Эта страница — reference для отправителя. Как оно потом рендерится в UI — забота клиента PartyFlow, и её можно игнорировать: достаточно отдать валидный JSON по схеме ниже, всё остальное сделает платформа.
Где это используется
Структурированный payload бывает двух типов: sender-provided rich metadata
(attachments, blocks, buttons, files) и PartyFlow-generated metadata
для Agent Runs.
| Контекст | Как попадает в сообщение |
|---|---|
| Incoming webhook | Поля верхнего уровня JSON-тела запроса (attachments, blocks, buttons, files). См. reference/http-webhook-endpoint.md. |
| Bot response | В ответах бота на button.click / modal.submit — поле update_message.metadata_json или send_message.metadata_json (JSON-строка). См. reference/interactive-components.md. |
| Agent Run | PartyFlow генерирует bot_metadata_json.kind="agent_run" для долгих AI-ответов, созданных через Bot REST API. |
Для incoming webhooks и bot responses формат sender-provided rich metadata идентичный: endpoint автоматически детектит Slack или Pachca формат по набору полей. Agent Run metadata не отправляется ботом напрямую и не проходит через Slack/Pachca autodetect.
Файлы, загруженные через Bot REST Bot Files API, не являются частью
metadata_json: они передаются отдельным top-level полем attachments: [{ "file_id": "..." }] в Bot REST API.
Не смешивайте это поле со Slack legacy metadata_json.attachments.
Верхнеуровневая структура
type BotMetadata = {
attachments?: SlackAttachment[]; // Slack legacy
blocks?: SlackBlock[]; // Slack Block Kit
buttons?: PachcaButton[]; // Pachca URL-кнопки
files?: PachcaFile[]; // Pachca вложения
severity?: "critical" | "warning" | "info"; // влияет на push-policy
kind?: "agent_run"; // server-generated Agent Run status
agent_run?: AgentRunMetadata; // только когда kind === "agent_run"
};Правило автодетекта формата:
attachmentsилиblocks→ Slack format.buttonsилиfiles→ Pachca format.- Форматы не смешиваются в одном сообщении.
kind="agent_run"→ отдельный server-generated формат для долгих AI-ответов; он не смешивается с Slack/Pachca rich blocks.- Если ни одно из полей не передано, а в
textесть контент — шлётся как обычное текстовое сообщение.
severity (опциональное)
Указывает приоритет сообщения. Если поле опущено — трактуется как warning (default).
| Значение | Использовать для | Что делает PartyFlow |
|---|---|---|
critical |
P0/P1 incident, outage, alarming event | Красный бейдж в UI. Push пробивает quiet hours и DND получателя (но уважает явно заглушённые им каналы). |
warning |
Обычные alerts, CI уведомления | Бейдж не показывается. Push работает по стандартным правилам DND получателя. |
info |
Success-сообщения, FYI, completions | Серый бейдж. Push не триггерится для этого сообщения. |
Синонимы — endpoint приводит к трём внутренним значениям:
| Прислали | Станет |
|---|---|
error, fatal, emergency, alert, critical |
critical |
warn, warning |
warning |
debug, notice, info |
info |
| что-то другое | warning (fallback) |
Поле взаимодействует с push-policy — см. reference/http-webhook-endpoint.md § Push policy. Само по себе severity только вешает бейдж и влияет на поведение push, не на рендер контента.
Agent Run metadata
Для долгих AI-ответов бот может создать Agent Run. PartyFlow сразу отправит
placeholder-сообщение, а затем будет обновлять его metadata безопасными
статусами. Бот не передаёт status_text напрямую: текст статуса выбирается
по разрешённому сервером списку.
interface AgentRunEnvelope {
version: 1;
kind: "agent_run";
agent_run: AgentRunMetadata;
}
interface AgentRunMetadata {
run_id: string;
widget_id?: string;
status:
| "accepted"
| "queued"
| "gathering_context"
| "using_tool"
| "waiting_tool"
| "waiting_user"
| "finalizing"
| "completed"
| "failed"
| "cancelled"
| "expired";
status_text: string;
sequence: number;
is_terminal: boolean;
trigger_message_id: string | null;
updated_at: string;
completed_at: string | null;
error_code: string;
}widget_id появляется, когда Agent Run связан с Execution Widget. Полное
состояние widget читайте через Bot REST API;
не кладите task state в metadata_json. Для изменения task используйте
PATCH /api/v1/bot/execution_tasks/{widget_id} или terminal update связанного
Agent Run.
| Status | status_text |
|---|---|
accepted |
Запрос принят |
queued |
В очереди |
gathering_context |
Ищу контекст |
using_tool |
Использую инструмент |
waiting_tool |
Жду ответ инструмента |
waiting_user |
Жду ответа пользователя |
finalizing |
Готовлю финальный ответ |
completed |
Готово |
failed |
Не удалось выполнить |
cancelled |
Остановлено |
expired |
Остановлено по тайм-ауту |
В public_text, error_code и metadata нельзя помещать raw reasoning,
prompt'ы, token'ы, секреты, tool payloads, stack traces, приватные
идентификаторы файлов или постоянные download URLs.
Порядок рендера
Клиент PartyFlow рисует rich-контент в этом порядке (сверху вниз):
┌──────────────────────────────────────────┐
│ [BOT badge] Display name 12:34 │
├──────────────────────────────────────────┤
│ msg.text (только если blocks отсутствуют)│
├──────────────────────────────────────────┤
│ blocks[]: header / section / divider / … │
├──────────────────────────────────────────┤
│ ┃ attachments[]: color-bar + content │
├──────────────────────────────────────────┤
│ [Button 1] [Button 2] │
├──────────────────────────────────────────┤
│ 📎 file.pdf (200 KB) │
└──────────────────────────────────────────┘Важное правило Slack-совместимости: если вы прислали и blocks, и text — в UI показывается blocks, text скрывается. Поле text в таком случае используется только для push-уведомлений, предпросмотров в листинге каналов и полнотекстового поиска. Всегда заполняйте text понятным plain-fallback'ом — это ровно то, что увидит пользователь в push-notification.
Slack Attachments
Используют: Grafana Alerting, GitLab CI, Sentry, Jenkins, Prometheus Alertmanager.
interface SlackAttachment {
color?: string; // "#36a64f" | "good" | "warning" | "danger"
title?: string;
title_link?: string; // URL — title становится ссылкой
pretext?: string; // текст ДО attachment (без цветной полоски)
text?: string; // основной текст (Slack mrkdwn)
fallback?: string; // plain-fallback для push
fields?: SlackField[]; // key-value grid
author_name?: string;
author_icon?: string; // 16x16
author_link?: string;
footer?: string;
footer_icon?: string; // 16x16
ts?: number; // Unix timestamp → рендерится как дата
image_url?: string; // большое изображение
thumb_url?: string; // миниатюра справа (~75x75)
}
interface SlackField {
title: string; // bold label
value: string; // значение (Slack mrkdwn допустим)
short?: boolean; // true = 2 колонки, false = full width
}Color aliases: "good" → #2EB67D, "warning" → #ECB22E, "danger" → #E01E5A.
Пример: Grafana alert
{
"text": "🔥 High CPU on prod-web-01",
"severity": "critical",
"attachments": [
{
"color": "danger",
"title": "[FIRING:1] High CPU Usage",
"title_link": "https://grafana.example.com/alerting/abc123/view",
"text": "CPU usage on *prod-web-01* exceeded 90% for 5 minutes.",
"fields": [
{"title": "Status", "value": "Firing", "short": true},
{"title": "Severity", "value": "critical", "short": true},
{"title": "Instance", "value": "prod-web-01:9090","short": true},
{"title": "Dashboard", "value": "<https://grafana.example.com/d/abc|Infrastructure>", "short": true}
],
"footer": "Grafana Alerting",
"footer_icon": "https://grafana.example.com/public/img/grafana_icon.svg",
"ts": 1744721696
}
]
}Грейд вниз: если ваш Grafana контакт-поинт шлёт только text без attachments — отрисуется как plain-текст, severity всё равно применяется.
Slack Blocks (Block Kit)
Используют: PagerDuty, GitHub Actions, новые версии Grafana.
type SlackBlock = HeaderBlock | SectionBlock | DividerBlock | ContextBlock | ImageBlock;
interface HeaderBlock {
type: "header";
text: { type: "plain_text"; text: string };
}
interface SectionBlock {
type: "section";
text?: TextElement; // основной текст
fields?: TextElement[]; // grid, max 10 элементов
accessory?: { type: "image"; image_url: string; alt_text: string };
}
interface DividerBlock {
type: "divider";
}
interface ContextBlock {
type: "context";
elements: (TextElement | { type: "image"; image_url: string; alt_text: string })[];
}
interface ImageBlock {
type: "image";
image_url: string;
alt_text: string;
title?: { type: "plain_text"; text: string };
}
type TextElement =
| { type: "plain_text"; text: string }
| { type: "mrkdwn"; text: string };Неизвестный type → клиент молча пропустит блок (forward compatibility: мы не ломаем ренедер, когда появится новый тип).
Лимиты: до 50 блоков на сообщение, до 10 fields внутри section, до 10 elements внутри context, plain_text.text до 3000 символов, mrkdwn.text до 3000 символов.
Пример: PagerDuty incident
{
"text": "[P1] DB connection pool exhausted",
"severity": "critical",
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "Incident: DB Connection Pool Exhausted"}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Service:*\nPayment API"},
{"type": "mrkdwn", "text": "*Severity:*\nP1 - Critical"},
{"type": "mrkdwn", "text": "*Started:*\n2026-04-19 12:34 UTC"},
{"type": "mrkdwn", "text": "*On-call:*\n<@user-42>"}
]
},
{"type": "divider"},
{
"type": "context",
"elements": [
{"type": "image", "image_url": "https://pagerduty.com/icon.png", "alt_text": "PagerDuty"},
{"type": "mrkdwn", "text": "PagerDuty | <https://pd.example.com/incidents/P123|View incident>"}
]
}
]
}Interactive blocks (actions)
Используется ботами для кнопок, select menus и модалок. Только для бот-сообщений — incoming webhooks и Slack/Pachca mainline форматы их не используют.
interface ActionsBlock {
type: "actions";
elements: (ButtonElement | SelectElement)[];
}
interface ButtonElement {
type: "button";
action_id: string; // ^[a-z0-9_-]{1,64}$, unique в рамках сообщения
text: string; // до 75 символов
style?: "primary" | "danger"; // иначе neutral
data?: string; // до 2000 chars, произвольный payload
visibility_user_ids?: string[]; // 1..100, кому показывать кнопку
confirm?: { // второй клик для подтверждения
title: string; // до 75
text: string; // до 300
confirm_label?: string;
cancel_label?: string;
};
}
interface SelectElement {
type: "select";
action_id: string;
placeholder?: string; // до 100
options: Array<{
value: string; // до 150, уникален
label: string; // до 75
}>; // до 25 опций
}Полный справочник поведения (лимиты, signed tokens, визуальные стили, click-response flow) — reference/interactive-components.md. Эта страница описывает только schema отправки.
Pachca Buttons
URL-кнопки в payload входящего webhook'а от Pachca-совместимых источников:
interface PachcaButton {
text: string; // label кнопки
url?: string; // → кнопка-ссылка в новое окно
data?: string; // есть без url → НЕ рендерится в MVP
}Пример
{
"message": {
"content": "Pipeline finished. Approve deploy?",
"buttons": [
{"text": "Approve", "url": "https://ci.example.com/deploy/42/approve"},
{"text": "View Logs", "url": "https://ci.example.com/deploy/42/logs"},
{"text": "Rollback", "url": "https://ci.example.com/deploy/42/rollback"}
]
}
}Кнопки с только data (без url) пока не рендерятся — механизм click-callback для Pachca-формата не подключён. Если нужна интерактивная кнопка, используйте Slack Interactive Components через бота (см. выше).
Pachca Files
Вложения:
interface PachcaFile {
name: string; // отображаемое имя
url: string; // HTTPS URL
size?: number; // bytes → рендер как "200 KB" / "1.4 MB"
}Пример
{
"message": {
"content": "Build artifacts ready",
"files": [
{"name": "build.log", "url": "https://ci.example.com/artifacts/42/build.log", "size": 204800},
{"name": "coverage.html", "url": "https://ci.example.com/artifacts/42/coverage.html", "size": 1048576}
]
}
}Файлы отображаются ссылками; PartyFlow не копирует их к себе — клиент скачивает по URL напрямую. URL должен быть доступен получателю (без auth, либо с кросс-site токеном в URL).
Обработка mrkdwn
Slack-формат использует mrkdwn (свой диалект Markdown). PartyFlow автоматически конвертирует его в стандартный Markdown только в поле верхнего уровня text входящего webhook'а. Внутри blocks и attachments текст передаётся как есть — клиент обрабатывает сам.
Что конвертируется на верхнем уровне text:
| Slack mrkdwn | Markdown |
|---|---|
*bold* |
**bold** |
_italic_ |
*italic* |
~strike~ |
~~strike~~ |
<url|label> |
[label](url) |
<url> |
url |
& < > |
& < > |
Если вы шлёте сложное форматирование через blocks — просто используйте Slack mrkdwn синтаксис (*bold*, _italic_, <url|label>). Клиент PartyFlow его сам отрендерит по тем же правилам.
Сводка: кто что шлёт
Ориентировочный матрикс — какой инструмент какой формат использует «из коробки».
| Инструмент | Формат | Типовые поля |
|---|---|---|
| Grafana Alerting | Slack attachments | color, title, title_link, fields, footer, ts |
| GitLab CI/CD | Slack attachments | color, title, title_link, fields, author_name |
| Sentry | Slack attachments | color, title, title_link, text, fields |
| Jenkins | Slack attachments | color, title, title_link, fields |
| PagerDuty | Slack Block Kit | header, section с fields, divider, context |
| GitHub Actions | Block Kit + attachments | blocks для заголовка, attachments для details |
| Prometheus Alertmanager | Slack attachments | color, title, text, несколько fields |
| Pachca-боты | Pachca buttons / files |
URL-кнопки, файловые ссылки |
| Custom боты (ваши) | любой из форматов | зависит от сценария |
Для отладки: все эти источники успешно тестируются на reference/http-webhook-endpoint.md — endpoint определит формат и применит соответствующий рендерер.
Связанное
- reference/http-webhook-endpoint.md — где именно в HTTP-запросе оказывается это поле.
- reference/interactive-components.md — buttons, select menus и модалки с callback или Poll delivery.
- reference/bot-rest-api.md — как бот читает
bot_metadata_jsonиз истории канала. - reference/error-codes.md — что вернёт endpoint на невалидный JSON в metadata.
- guides/send-grafana-alerts.md — готовый сценарий для Grafana (Planned).