AI‑бот в MAX: от кабинета до защищённого webhook
Разберём не только код, но и архитектуру. MAX отправляет событие на наш HTTPS‑адрес, приложение проверяет секрет, получает ответ AI и вызывает Bot API.
Webhook и API простыми словами
API — набор адресов, к которым программа обращается по правилам. Webhook — обратная схема: MAX сам отправляет POST‑запрос на наш сервер при новом сообщении. Для продуктового запуска официальный MAX рекомендует webhook, а не постоянный опрос.
Webhook должен работать по HTTPS на стандартном порту 443 и быстро возвращать ответ 200. Поэтому до финальной проверки понадобятся домен, VPS, Nginx и сертификат.
1. Создаём бота и получаем токен
- Откройте платформу MAX для партнёров.
- Перейдите в раздел чат‑ботов и создайте нового.
- Заполните имя, описание и изображение.
- В расширенных настройках откройте настройку бота и скопируйте токен.
Не публикуйте токен и не отправляйте его в чат. API принимает его в заголовке Authorization.
2. Готовим Python‑проект
python3 -m venv .venv
source .venv/bin/activate
pip install fastapi uvicorn httpx python-dotenv openai
MAX_WEBHOOK_SECRET=придумайте_длинную_строку
AI_API_KEY=ключ_ai_провайдера
Секрет webhook — это отдельная строка от 5 символов. MAX будет присылать её в заголовке, а наше приложение — сравнивать.
3. Создаём обработчик
from fastapi import FastAPI, Header, HTTPException, Request
from dotenv import load_dotenv
load_dotenv()
app = FastAPI()
WEBHOOK_SECRET = os.environ["MAX_WEBHOOK_SECRET"]
@app.get("/health")
async def health():
return {"status": "ok"}
@app.post("/webhook")
async def webhook(
request: Request,
x_max_bot_api_secret: str | None = Header(default=None),
):
if x_max_bot_api_secret != WEBHOOK_SECRET:
raise HTTPException(status_code=403)
update = await request.json()
print(update) # временно изучаем структуру события
return {"ok": True}
Сначала сознательно только печатаем событие. Так вы увидите фактическую структуру Update своего типа события и не будете угадывать названия полей.
4. Проверяем локально
В другом SSH‑окне:
Ожидаемый ответ — {"status":"ok"}. Порт 8000 наружу не открываем.
5. Подключаем домен и HTTPS
Настройте Nginx по отдельной инструкции RateHost. Внешний адрес должен выглядеть как https://bot.example.ru/webhook. Самоподписанный сертификат не подойдёт.
6. Регистрируем webhook
-H "Authorization: ВАШ_MAX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://bot.example.ru/webhook",
"update_types": ["message_created", "bot_started"],
"secret": "ВАШ_WEBHOOK_SECRET"
}'
После успешной подписки напишите боту. Посмотрите событие в терминале и сопоставьте поля с объектом Update в официальной документации MAX.
7. Добавляем AI‑ответ
Логика состоит из трёх действий: извлечь текст и идентификатор чата из события, отправить текст модели, затем вызвать официальный метод POST /messages с заголовком авторизации. Делайте это после того, как увидели реальный Update: структура платформы меняется, а догадки здесь рождают трудноуловимые ошибки.
Тяжёлую обработку лучше вынести в очередь задач, а webhook вернуть 200 как можно быстрее. MAX повторяет неуспешные доставки и может отключить подписку после продолжительной недоступности.
Типовые ошибки
401— неверный или отозванный токен;403от вашего сервера — не совпал webhook secret;- события не приходят — проверьте HTTPS, порт 443 и активную подписку;
- дубли ответов — обрабатывайте идентификатор события только один раз;
- долгий ответ — верните 200, а AI‑запрос выполняйте фоновой задачей.
Что дальше
Закрепим приложение на сервере и настроим автоматический запуск: деплой бота на VPS →