- register_max_webhook.py, fetch_schema.py - n8n-code-node-max-normalize.js (max_id, callback из callback.user, contact из vcf_info) - n8n-code-add-menu-buttons.js (меню с callback, request_contact, Главное меню) - docs: max-webhook, max-curl-http-request, max-api (форматы, кнопки, контакт), clpr vs sprf - README, SITUATION, схемы sprf_ и clpr_, .gitignore Co-authored-by: Cursor <cursoragent@cursor.com>
8.4 KiB
Форматы текста и кнопки (MAX Bot API)
Форматы текста (поле format в теле сообщения)
В NewMessageBody укажи "format": "markdown" или "format": "html". Тогда текст сообщения будет отформатирован.
Markdown
| Как написать | Результат |
|---|---|
*курсив* или _курсив_ |
курсив |
**жирный** или __жирный__ |
жирный |
~~зачёркнутый~~ |
|
++подчёркнутый++ |
подчёркнутый |
`код` |
моноширинный (переводы строк внутри — как пробелы) |
[текст ссылки](https://example.com) |
кликабельная ссылка |
| @упоминание | "text": "[Имя Фамилия](max://user/user_id)", "format": "markdown" — полное имя из профиля MAX |
HTML
| Теги | Результат |
|---|---|
<i>, <em> |
курсив |
<b>, <strong> |
жирный |
<del>, <s> |
зачёркнутый |
<ins>, <u> |
подчёркнутый |
<pre>, <code> |
моноширинный |
<a href="https://example.com">Текст</a> |
ссылка |
| @упоминание | "text": "<a href=\"max://user/user_id\">Имя Фамилия</a>", "format": "html" |
Пример тела с markdown:
{
"text": "**Внимание!** Вы отправили *голосовое*. Обрабатываем.",
"format": "markdown"
}
Кнопки (inline_keyboard)
Кнопки добавляются через attachments: один элемент с type: "inline_keyboard" и payload.buttons — массив рядов, каждый ряд — массив кнопок.
Ограничения:
- до 210 кнопок всего;
- до 30 рядов;
- до 7 кнопок в ряду (для типов
link,open_app,request_geo_location,request_contact— до 3 в ряду); - для кнопки типа
linkссылка до 2048 символов.
Структура
{
"text": "Текст сообщения над кнопками",
"format": "markdown",
"attachments": [
{
"type": "inline_keyboard",
"payload": {
"buttons": [
[
{ "type": "callback", "text": "Надпись кнопки", "payload": "значение при нажатии" }
],
[
{ "type": "link", "text": "Открыть сайт", "url": "https://example.com" }
]
]
}
}
]
}
buttons — массив рядов. Каждый ряд — массив кнопок. Одна кнопка — объект с полями в зависимости от типа.
Типы кнопок
| type | Описание | Поля кнопки |
|---|---|---|
| callback | При нажатии в Webhook приходит message_callback с callback_id и payload. Нужен для ответа через POST /answers. |
text, payload (строка или объект — то, что придёт в бот) |
| link | Открывает ссылку в браузере. | text, url (до 2048 символов) |
| message | Отправляет боту текстовое сообщение (как будто пользователь написал это). | text |
| request_contact | Запрос контакта (номер телефона). Пользователь нажимает → клиент MAX предлагает отправить контакт → в Webhook приходит message_created с данными контакта (телефон и т.д.) в теле сообщения. |
text (подпись на кнопке) |
| request_geo_location | Запрос геолокации. Пользователь нажимает → отправляет геолокацию → в Webhook приходит сообщение с координатами. | text |
| open_app | Открывает мини-приложение. | уточнять в доках |
Пример: кнопка «Поделиться контактом»
У кнопки тип request_contact, поле text — подпись (например «📱 Отправить номер телефона»). В одном ряду с такими кнопками MAX разрешает до 3 кнопок.
{
"text": "Чтобы мы могли связаться, поделитесь номером телефона:",
"format": "markdown",
"attachments": [
{
"type": "inline_keyboard",
"payload": {
"buttons": [
[
{ "type": "request_contact", "text": "📱 Отправить номер телефона" }
]
]
}
}
]
}
После нажатия пользователь подтверждает отправку контакта в клиенте MAX. В Webhook придёт message_created с вложением attachments[0].type === "contact". Структура:
- attachments[0].payload.vcf_info — строка VCARD (например
TEL;TYPE=cell:79262306381,FN:Имя Фамилия). Телефон достаётся из строкиTEL...:номер. - attachments[0].payload.max_info — объект пользователя MAX:
user_id,first_name,last_name,name,is_bot,last_activity_time.
В нормализаторе для такого сообщения: answer_type: 'contact', answer_text — извлечённый номер, contact_payload — весь payload, contact_name — из max_info.name.
Пример: одна callback-кнопка
{
"text": "Выберите действие:",
"format": "markdown",
"attachments": [
{
"type": "inline_keyboard",
"payload": {
"buttons": [
[
{ "type": "callback", "text": "Подтвердить", "payload": "confirm" },
{ "type": "callback", "text": "Отмена", "payload": "cancel" }
]
]
}
}
]
}
При нажатии «Подтвердить» в Webhook придёт update_type: "message_callback", в нормализованном объекте будет answer_text: "confirm" и callback_id для POST /answers (уведомление или обновление сообщения).
Пример: кнопка-ссылка и callback в одном сообщении
{
"text": "Официальный сайт и обратная связь:",
"format": "markdown",
"attachments": [
{
"type": "inline_keyboard",
"payload": {
"buttons": [
[
{ "type": "link", "text": "Перейти на сайт", "url": "https://example.com" }
],
[
{ "type": "callback", "text": "Написать в поддержку", "payload": "support" }
]
]
}
}
]
}
В n8n (HTTP Request — тело с кнопками)
В JSON Body ноды можно задать статичное тело или собрать через выражение. Пример статичного тела с кнопками:
{
"text": "Выберите действие:",
"format": "markdown",
"attachments": [
{
"type": "inline_keyboard",
"payload": {
"buttons": [
[
{ "type": "callback", "text": "Да", "payload": "yes" },
{ "type": "callback", "text": "Нет", "payload": "no" }
]
]
}
}
]
}
URL и заголовки — как раньше: POST https://platform-api.max.ru/messages?user_id={{ $json.max_id }}, Authorization: <token>, Content-Type: application/json.
После нажатия callback-кнопки пользователем обрабатывай событие в воркфлоу (по answer_type === 'callback' и answer_text / callback_id) и при необходимости вызывай POST /answers?callback_id=... для уведомления или обновления сообщения (см. 02-methods.md).