- 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>
145 lines
7.8 KiB
Markdown
145 lines
7.8 KiB
Markdown
# Как активировать Webhook для бота MAX
|
||
|
||
## 1. В n8n: воркфлоу с Webhook
|
||
|
||
1. Открой n8n (https://n8n.clientright.pro).
|
||
2. Создай новый воркфлоу или открой существующий для MAX.
|
||
3. Добавь ноду **Webhook** (Trigger → Webhook).
|
||
4. Настрой Webhook:
|
||
- **HTTP Method:** POST
|
||
- **Path:** должен совпадать с путём из URL в `.env`. Сейчас в `.env` указано:
|
||
- `N8N_MAX_WORKFLOW=https://n8n.clientright.pro/webhook/sprf_max`
|
||
- значит в ноде Webhook задай **Path** = `sprf_max` (без `/webhook/`).
|
||
- **Authentication:** Optional (проверку секрета можно сделать следующей нодой: сравнить заголовок `X-Max-Bot-Api-Secret` с переменной `MAX_WEBHOOK_SECRET`).
|
||
5. Включи воркфлоу (Production mode), чтобы URL был доступен по HTTPS.
|
||
|
||
Итог: запросы на `https://n8n.clientright.pro/webhook/sprf_max` будут попадать в этот воркфлоу.
|
||
|
||
## 2. Регистрация URL в MAX
|
||
|
||
Из каталога проекта выполни:
|
||
|
||
```bash
|
||
python3 register_max_webhook.py
|
||
```
|
||
|
||
Скрипт читает из `.env`:
|
||
- `MAX_BOT_TOKEN` — токен бота
|
||
- `N8N_MAX_WORKFLOW` — полный URL webhook (HTTPS)
|
||
- `MAX_WEBHOOK_SECRET` — секрет (опционально; если задан, MAX будет присылать его в заголовке `X-Max-Bot-Api-Secret`)
|
||
|
||
После успешного запуска MAX начнёт отправлять события (новые сообщения, нажатия кнопок, старт бота) на этот URL.
|
||
|
||
## 3. Нормализация входящего (Code node под MAX)
|
||
|
||
Чтобы не обрабатывать сырой Update, а получать один и тот же формат, что и для Telegram (для общего воркфлоу), используй Code node с содержимым из файла **`n8n-code-node-max-normalize.js`** в корне проекта. Он отдаёт один объект с полями:
|
||
|
||
- `max_id` — id пользователя MAX (sender)
|
||
- `max_chat_id` — id чата/диалога (для лички может совпадать с user_id)
|
||
- `answer_text` — текст сообщения, подпись к медиа или данные callback
|
||
- `answer_type` — `text` | `command` | `callback` | `voice` | `audio` | `video` | `file` | `photo`
|
||
- `channel` — `'max'`
|
||
- `reply_to_*` — если было ответ/пересланное (из `message.link`)
|
||
- `callback_id` — только при `answer_type === 'callback'` (для POST /answers)
|
||
- `attachment_token` / `file_id` — при медиа-вложениях
|
||
- `raw_update` — исходное тело Webhook
|
||
|
||
Групповые чаты и каналы отфильтровываются (возвращается пустой массив).
|
||
|
||
## 4. Отправка ответа пользователю (пушим в MAX)
|
||
|
||
Чтобы бот написал пользователю, вызывай **MAX Bot API**: отправка сообщения — метод **POST /messages**.
|
||
|
||
### Параметры
|
||
|
||
- **URL:** `https://platform-api.max.ru/messages?user_id={user_id}` или `?chat_id={chat_id}`
|
||
В личке можно использовать либо `user_id` (id отправителя), либо `chat_id` (id диалога). Из нашей нормализации: `max_id` — это user_id, `max_chat_id` — chat_id; для ответа подойдёт любой из них в query.
|
||
- **Метод:** POST
|
||
- **Заголовки:**
|
||
- `Authorization: <MAX_BOT_TOKEN>` — токен бота (из .env или из credentials в n8n)
|
||
- `Content-Type: application/json`
|
||
- **Тело (JSON):** объект **NewMessageBody**:
|
||
- `text` (string) — текст до 4000 символов, обязателен если нет вложений
|
||
- `format` (опц.) — `"markdown"` или `"html"` для форматирования
|
||
- `attachments` (опц.) — массив вложений (например inline_keyboard с кнопками)
|
||
- `notify` (опц., по умолч. true) — уведомлять ли пользователя
|
||
|
||
Пример тела:
|
||
|
||
```json
|
||
{
|
||
"text": "Привет! Ваше сообщение получено.",
|
||
"format": "markdown"
|
||
}
|
||
```
|
||
|
||
### В n8n (HTTP Request node)
|
||
|
||
1. Добавь ноду **HTTP Request** после логики (после Code или ветки, где есть нормализованный объект с `max_id`/`max_chat_id`).
|
||
2. Настрой:
|
||
- **Method:** POST
|
||
- **URL:** `https://platform-api.max.ru/messages?user_id={{ $json.max_id }}`
|
||
(или `?chat_id={{ $json.max_chat_id }}` — оба варианта для лички рабочие)
|
||
- **Authentication:** Generic Credential Type → **Header Auth**
|
||
- Name: `Authorization`
|
||
- Value: твой `MAX_BOT_TOKEN` (создай в n8n Credentials или подставь через переменную окружения)
|
||
- **Body Content Type:** JSON
|
||
- **Specify Body:** Using JSON
|
||
- **JSON Body:** например `{ "text": "{{ $json.answer_text }}", "format": "markdown" }` или свой текст/поля из предыдущих нод
|
||
|
||
Токен бота лучше хранить в n8n Credentials (тип Header Auth или просто в переменной workflow/environment), а не в коде.
|
||
|
||
### Ответ на нажатие кнопки (callback)
|
||
|
||
Если пользователь нажал кнопку, приходит `message_callback` и в нормализованном объекте есть **`callback_id`**. Чтобы обновить сообщение с кнопкой или показать уведомление:
|
||
|
||
- **URL:** `https://platform-api.max.ru/answers?callback_id={{ $json.callback_id }}`
|
||
- **Method:** POST
|
||
- **Headers:** те же (`Authorization`, `Content-Type: application/json`)
|
||
- **Body (JSON):**
|
||
- `message` (опц.) — объект NewMessageBody (обновить сообщение)
|
||
- `notification` (опц.) — строка, одноразовое уведомление пользователю
|
||
|
||
Подробнее: `docs/max-api/02-methods.md`.
|
||
|
||
## 5. Проверка
|
||
|
||
Напиши боту в мессенджере MAX — в n8n во входящих данных Webhook должен появиться объект с полями `update_type`, `message` и т.д.
|
||
|
||
## Проверка: зарегистрирован ли Webhook
|
||
|
||
Выполни в каталоге проекта:
|
||
|
||
```bash
|
||
python3 -c "
|
||
import os, json, urllib.request
|
||
from pathlib import Path
|
||
for line in Path('.env').read_text().splitlines():
|
||
s = line.strip()
|
||
if s and not s.startswith('#') and '=' in s:
|
||
k, v = s.split('=', 1)
|
||
os.environ[k.strip()] = v.strip()
|
||
r = urllib.request.urlopen(urllib.request.Request(
|
||
os.environ.get('MAX_API_BASE','https://platform-api.max.ru').rstrip('/') + '/subscriptions',
|
||
headers={'Authorization': os.environ['MAX_BOT_TOKEN']}, method='GET'))
|
||
print(r.read().decode())
|
||
"
|
||
```
|
||
|
||
В ответе должен быть твой URL в списке `subscriptions`. Если список пустой — заново запусти `python3 register_max_webhook.py`.
|
||
|
||
---
|
||
|
||
## Отписка от Webhook
|
||
|
||
Чтобы отключить доставку на этот URL, вызови в MAX API:
|
||
|
||
```bash
|
||
curl -X DELETE "https://platform-api.max.ru/subscriptions" \
|
||
-H "Authorization: ВАШ_MAX_BOT_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"url": "https://n8n.clientright.pro/webhook/sprf_max"}'
|
||
```
|
||
|
||
Точный формат отписки см. в документации MAX (DELETE /subscriptions).
|