Зачем эта инструкция

Если вы ищете как создать простого бота в мессенджере MAX с нуля — эта статья проведёт вас от регистрации в кабинете до первого ответа пользователю через MAX Bot API. Мы опираемся на официальную документацию MAX и даём пошаговый план для начинающих: токен, проверка GET /me, простой цикл на Python с long polling, затем путь к вебхуку и HTTPS для постоянной работы. Ключевые термины: чат-бот MAX — программа, которая общается с людьми в MAX; MAX Bot API — HTTP-интерфейс (https://platform-api.max.ru), через который бот отправляет и получает сообщения.

Что такое MAX Bot API простыми словами

MAX Bot API — это набор методов, к которым ваш сервер обращается обычными HTTPS-запросами (как к сайту): отправить текст, получить обновления, добавить кнопки. У каждого бота есть токен — секретный ключ; его передают в заголовке Authorization (передача токена в query-параметрах не поддерживается — см. документацию авторизации). Типичный сценарий для бизнеса: запись на услугу, ответы на частые вопросы, уведомления, переход на сайт по кнопке. Для этого не обязательна сложная архитектура: начните с короткого сценария и одного языка программирования.

Что понадобится до кода

  • Аккаунт и кабинет на business.max.ru — там создаётся бот и выдаётся токен (раздел вроде «Чат-боты» → «Интеграция» → «Получить токен» — названия шагов в интерфейсе могут обновляться).
  • Компьютер с Python 3.10+ (удобно для примеров) или любой другой стек, умеющий в HTTP.
  • Для постоянной работы в интернете — сервер с HTTPS (домен и сертификат от доверенного УЦ). Для первых экспериментов часто используют long polling (см. ниже) или туннель к локальной машине; для продакшена MAX рекомендует вебхук — см. события и подписки.
Важно: правила доступа к созданию ботов, модерации и публикации задаёт платформа MAX. Перед запуском проекта сверьтесь с актуальными условиями и верификацией в кабинете и на dev.max.ru — они меняются быстрее, чем любая статья.

Шаг 1. Создайте бота в кабинете

  • Войдите на business.max.ru/self и пройдите шаги регистрации организации / сервиса, которые требует интерфейс (верификация через провайдеров идентификации встречается на практике часто).
  • Откройте раздел чат-ботов и выберите создание нового бота.
  • Заполните имя, описание, загрузите аватар — это влияет на доверие пользователей и на модерацию.
  • Отправьте бота на модерацию, если кнопка есть в интерфейсе. Сроки проверки зависят от нагрузки поддержки; закладывайте от нескольких часов до пары рабочих дней и следите за уведомлениями в кабинете.
  • После одобрения откройте блок интеграции и скопируйте токен в менеджер паролей или в защищённое хранилище секретов на сервере.
Безопасность: не вставляйте токен в публичные репозитории, скриншоты и тикеты. При утечке перевыпустите токен в кабинете.

Шаг 2. Проверьте токен запросом GET /me

Убедитесь, что ключ рабочий. В терминале:
curl -s -X GET "https://platform-api.max.ru/me" \
  -H "Authorization: ВАШ_ТОКЕН"
В ответе должен быть JSON с данными бота (user_id, имя, признак is_bot: true и т.д.) — см. метод GET /me. Если видите ошибку 401 — токен неверный или отозван.

Шаг 3. Long polling: расширенный пример с callback, 429 и защитой от дублей

Чтобы не настраивать домен и HTTPS в первый день, удобно получать события методом GET /updates (long polling). Для продакшена MAX рекомендует вебхук; long polling и вебхук нельзя использовать одновременно (справка «События»).

Справочник: update_type и где искать данные

Ниже — ориентир для чтения JSON; точные поля всегда сверяйте с объектом Update и при необходимости выведите print(update) один раз.
  • message_created — новое сообщение. Текст: обычно update["message"]["body"]["text"]. Чат: update["message"]["recipient"]["chat_id"]. Тип чата (если есть): update["message"]["recipient"].get("chat_type") — например dialog, chat, channel (названия зависят от версии API).
  • message_callback — нажата inline-кнопка с type: "callback". Идентификатор для POST /answers: update["callback"]["callback_id"] (в документации: «идентификатор кнопки в поле callback.callback_id»). Данные кнопки: чаще всего update["callback"].get("payload") — сверьте с вашим фактическим JSON.
  • bot_added — бота добавили в чат или канал. См. поля вроде chat_id, user, is_channel в описании Update.
  • user_added — в чат или канал добавился пользователь (удобно для приветствий в группе).
Отдельного типа chat_member_updated в официальном перечне Update может не быть — для сценария «бота добавили в группу» ориентируйтесь на bot_added.

Код: сообщения, кнопки, ответ на callback, retry при 429

Установка: pip install requests. Токен — в MAX_BOT_TOKEN.
import os
import time
import logging
from collections import deque

import requests

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("max-bot")

API = "https://platform-api.max.ru"
TOKEN = os.environ["MAX_BOT_TOKEN"]
HEADERS = {"Authorization": TOKEN, "Content-Type": "application/json"}

# Простая защита от повторной обработки одного и того же update (long polling / ретраи)
_SEEN: deque = deque(maxlen=200)


def dedup_key(update: dict) -> tuple:
    msg = update.get("message") or {}
    body = msg.get("body") or {}
    mid = body.get("mid")
    cb = update.get("callback") or {}
    return (
        update.get("update_type"),
        update.get("timestamp"),
        mid,
        cb.get("callback_id"),
    )


def poll_updates(marker=None, timeout=30):
    params = {"timeout": timeout, "limit": 100}
    if marker is not None:
        params["marker"] = marker
    r = requests.get(f"{API}/updates", headers=HEADERS, params=params, timeout=timeout + 10)
    r.raise_for_status()
    return r.json()


def send_message_safe(chat_id: int, text: str, retries: int = 3) -> None:
    """POST /messages с обработкой 429 (Retry-After) и повтором."""
    url = f"{API}/messages"
    body = {"chat_id": chat_id, "text": text}
    for attempt in range(retries):
        resp = requests.post(url, headers=HEADERS, json=body, timeout=20)
        if resp.status_code == 429:
            wait = int(resp.headers.get("Retry-After", 5))
            log.warning("429 messages, ждём %s с (попытка %s)", wait, attempt + 1)
            time.sleep(wait)
            continue
        if not resp.ok:
            log.error("messages: %s %s", resp.status_code, resp.text[:400])
        else:
            break


def answer_callback(callback_id: str, notification: str = "Готово") -> None:
    """Снимает «часики» с кнопки — см. POST /answers."""
    if not callback_id:
        return
    r = requests.post(
        f"{API}/answers",
        headers=HEADERS,
        params={"callback_id": callback_id},
        json={"notification": notification},
        timeout=15,
    )
    if not r.ok:
        log.error("answers: %s %s", r.status_code, r.text[:300])


def handle_update(update: dict) -> None:
    key = dedup_key(update)
    if key in _SEEN:
        return
    _SEEN.append(key)

    ut = update.get("update_type")

    if ut == "message_created":
        msg = update.get("message") or {}
        recipient = msg.get("recipient") or {}
        chat_id = recipient.get("chat_id")
        body = msg.get("body") or {}
        text = (body.get("text") or "").strip()
        if chat_id is None:
            return

        if text.startswith("/start"):
            parts = text.split(maxsplit=1)
            payload = parts[1] if len(parts) > 1 else ""
            if payload:
                send_message_safe(int(chat_id), f"Старт с параметром: {payload}")
            else:
                send_message_safe(int(chat_id), "Привет! Напишите /help.")
        elif text == "/help":
            send_message_safe(int(chat_id), "Доступно:\n/start [код]\n/help")
        else:
            send_message_safe(int(chat_id), f"Вы написали: {text}")

    elif ut == "message_callback":
        cb = update.get("callback") or {}
        callback_id = cb.get("callback_id")
        payload = cb.get("payload", "")
        msg = cb.get("message") or {}
        recipient = msg.get("recipient") or {}
        chat_id = recipient.get("chat_id")

        answer_callback(callback_id, "Принято")
        if chat_id is not None:
            send_message_safe(int(chat_id), f"Нажата кнопка, payload: {payload}")

    elif ut == "bot_added":
        log.info("Бот добавлен в чат: %s", update.get("chat_id"))


def main():
    marker = None
    log.info("Бот запущен (long polling). Остановка: Ctrl+C")
    while True:
        try:
            data = poll_updates(marker)
            for u in data.get("updates") or []:
                handle_update(u)
            if data.get("marker") is not None:
                marker = data["marker"]
        except requests.RequestException as e:
            log.warning("Сеть/API: %s — пауза 5 с", e)
            time.sleep(5)


if __name__ == "__main__":
    main()
Структура полей описана в Update. Для идемпотентности в проде часто хранят mid входящего сообщения или иной стабильный ключ из документации; здесь — упрощённый deque по комбинации полей.

Шаг 4. Отправка сообщений: POST /messages

Исходящий текст — POST https://platform-api.max.ru/messages с JSON (chat_id, text до 4000 символов — POST /messages). Заголовок Authorization — токен бота.

Шаг 5. Inline-кнопки и ссылка под сообщением

Кнопки — вложение inline_keyboard. Пример одной строки: callback + link (как в прошлой версии статьи). После нажатия callback обязательно вызывайте POST /answers с callback_id, иначе у пользователя долго крутятся «часики» на кнопке.

Шаг 6. Deep link: параметр после /start

Текст в message_created часто выглядит как /start promo_2026. Разбор:
if text.startswith("/start"):
    parts = text.split(maxsplit=1)
    promo = parts[1] if len(parts) > 1 else ""
    # promo — условный «код» из рекламной ссылки; сохраните в БД или в состоянии FSM
Точный формат ссылок приглашения в MAX смотрите в актуальной справке платформы и в кабинете.

Шаг 7. Группы и каналы: чек-лист для владельца чата

  • Добавьте бота в группу или канал через интерфейс MAX.
  • Выдайте права, достаточные для сценария: как минимум отправка сообщений; для чтения всех сообщений в группе (если платформа это разделяет) — соответствующее право; чтобы пользователи вызывали бота по /start@username, нужен публичный username бота и понятные команды в описании.
  • В коде смотрите recipient.chat_type (если поле приходит): различайте личку, группу и канал — логика ответов может отличаться.
  • Если бот «молчит» в группе: проверьте права, видимость сообщений (упоминание бота, команды), а также что вы подписаны на нужные update_types при вебхуке.

Шаг 8. Вебхук в бою: проверка X-Max-Bot-Api-Secret

Для публичного URL любой может прислать POST. Задайте secret в POST /subscriptions и сверяйте заголовок X-Max-Bot-Api-Secret (лучше через hmac.compare_digest, чтобы не светить секрет в логах и не дать лишних подсказок по времени ответа).
import os
import hmac
from flask import Flask, request, abort, jsonify

app = Flask(__name__)
MY_SECRET = os.environ["MAX_WEBHOOK_SECRET"]  # тот же, что в подписке


@app.route("/webhook", methods=["POST"])
def webhook():
    got = request.headers.get("X-Max-Bot-Api-Secret", "")
    if not MY_SECRET or not hmac.compare_digest(got, MY_SECRET):
        abort(403)
    update = request.get_json(silent=True) or {}
    # handle_update(update) — ту же логику, что и для long polling
    return jsonify({"ok": True}), 200
Полный разбор HTTPS, 443, таймаута 30 с и эхо-примера — в статье Вебхуки в MAX Bot API: настройка webhook с примером.

Фишки для бизнес-бота (кратко)

  • Напоминания и отложенные сообщения — планируйте задачи планировщиком (APScheduler, Celery beat, cron) и в срок вызывайте POST /messages.
  • Клавиатура под полем ввода (reply): во многих API она отделена от inline_keyboard. В MAX для кнопок под сообщением стандартно используют inline_keyboard; отдельный тип «обычной» клавиатуры, если он доступен, ищите в актуальной схеме вложений в документации к POST /messages.
  • Многошаговые сценарии — храните шаг пользователя в Redis, SQLite или памяти процесса (для одного инстанса); это и есть простейшая FSM.

Быстрая диагностика

  • 401 Unauthorized — неверный или отозванный токен; заголовок Authorization, не query.
  • 400 Bad Request — проверьте JSON, типы (chat_id числом), обязательные поля метода.
  • 429 Too Many Requests — снизьте частоту запросов, читайте Retry-After, введите очередь.
  • Вебхук не вызывается — валидный TLS, порт 443, совпадение secret, ответ 200 до таймаута (POST /subscriptions).
  • В группе нет message_created — права бота, тип чата, упоминание; сверьтесь с Update и логами.

Путь развития: от учебного бота к продакшену

  • Заменить print на логирование в файл или централизованный сбор логов.
  • Вынести состояние диалога (простая FSM) в Redis/SQLite.
  • Перейти на вебхук (FastAPI + uvicorn или Flask за nginx) по гайду на Bothost.
  • Подключить БД для заявок и аналитики.
  • Добавить мониторинг (ошибки, 429, задержка ответа).

Ограничения и лимиты, о которых стоит помнить

  • Частота запросов к platform-api.max.ru ограничена; при перегрузке — 429 (см. send_message_safe выше).
  • Длина текста — до 4000 символов (POST /messages).
  • Вебхук: повторные доставки — проектируйте идемпотентность (учёт mid, callback_id и т.д.).

Типичные ошибки начинающих

  • Токен в коде вместо переменных окружения.
  • Нет разбора 429 и нет паузы — бот «забивает» API.
  • После нажатия callback не вызывается /answers — плохой UX.
  • Вебхук без проверки X-Max-Bot-Api-Secret — риск поддельных POST.
  • Ожидание, что бот сам первым пишет незнакомому пользователю — в типичных сценариях первым пишет человек, по правилам платформы.

Размещение бота на сервере и на Bothost

Учебный скрипт можно запустить на VPS или на хостинге приложений. На Bothost для ботов MAX задают шаблон, MAX_TOKEN / MAX_BOT_TOKEN и WEBHOOK_URL для продакшена.

Частые вопросы (FAQ)

Сколько времени занимает модерация бота в MAX?

Сроки зависят от загрузки модерации и полноты данных. Ориентируйтесь от нескольких часов до нескольких рабочих дней; статус — в business.max.ru.

Можно ли разрабатывать бота без публичного домена?

Для long polling публичный входящий адрес не обязателен. Для вебхука нужен HTTPS на 443 (POST /subscriptions).

Чем MAX Bot API отличается от Telegram Bot API?

Схожи идеи, но отличаются базовый URL, поля JSON и правила платформы.

Где описан вебхук?

POST /subscriptions, FAQ по событиям, наша статья: вебхук с примером.

Как проверить токен?

GET /me.

Полезные ссылки (официальные)

Если интерфейс кабинета или ответ API разошлись с текстом статьи — ориентируйтесь на официальные страницы MAX и поддержку платформы.

476 просмотров
0 лайков
0 комментариев