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).
|