Макс - это мессенджер, где разработчику официально предлагают не «пишите бота, как хотите», а «сначала станьте правильной организацией, потом поговорим». Подключение к платформе для партнёров и доступ к чат-ботам/мини-приложениям/каналам прямо в документации помечены как доступные лишь ограниченному списку юрлиц и ИП (через RuStore или МСП.РФ), а самозанятым и физлицам вход пока закрыт.
Технически Bot API Макс - это HTTP(S) REST-подобный интерфейс на домене https://platform-api.max.ru, а не WebSocket и не gRPC. События приходят либо через Webhook (push), либо через Long Polling (GET /updates) - одновременно нельзя, а для production документация прямо рекомендует Webhook.
По «железным фактам» из официальной документации:
- аутентификация - простым токеном бота в заголовке Authorization: <token>, передача токена в query больше не поддерживается; токен можно обновлять (ротировать).
- базовый лимит нагрузки - ориентир 30 rps на platform-api.max.ru, а при превышении - ожидайте 429.
- сообщения - JSON, text до 4000 символов, форматирование Markdown или HTML, есть упоминания через max://user/user_id, есть inline-клавиатуры и callback-ответы через отдельный метод.
- медиа грузится «в два шага»: POST /uploads даёт URL, потом заливаете файл, потом прикрепляете token в attachments; есть нюанс с обработкой (ошибка attachment.not.ready) и отдельная механика для видео/аудио.
- редактирование/удаление сообщений - только для сообщений моложе 24 часов, и удаление зависит от разрешений.
- чтобы ловить события из групповых чатов или каналов, бота нужно сделать администратором.
С каналами есть важная «бизнесовая реальность»: документация про создание каналов говорит, что публикация постов и управление контентом происходит в интерфейсе мессенджера, а не через публичный API. То есть «постинг в канал через API» официально не описан, и это надо проговаривать заранее, чтобы не было сюрприза в стиле «мы уже подписали SLA».
Сравнение по интеграции:
- Telegram - максимально инженерный в плане входа: Bot API - чистый HTTPS, вебхук или long polling, понятные лимиты (например, массовые рассылки около 30 msg/sec и типичные 429 при превышении), плюс богатая экосистема.
- WhatsApp для бизнеса - это Graph API и webhooks, токены доступа, жёсткие продуктовые ограничения (шаблоны вне «окна», лимиты на отправку и качество), зато очень зрелая модель статусов доставки/прочтения и ожидания enterprise-уровня.
- Макс - «молодая» платформа, но уже с внятным REST, вебхуками, правами администраторов и большой ставкой на мини-приложения (MAX Bridge + валидация initData через HMAC).
Где Макс живет в экосистеме автоматизации
Если ты автоматизатор и хочешь «просто токен и поехали», Макс сначала попросит тебя доказать, что ты бизнес. В документации прямо сказано:
- подключение к партнёрской платформе и сервисам (чат-боты, мини-приложения, каналы) пока доступно ограниченному списку юрлиц и ИП (например, кто разместил приложение в RuStore или зарегистрировался на МСП.РФ).
- самозанятые, физические лица и нерезиденты пока не могут авторизоваться или зарегистрироваться на платформе.
С практической точки зрения это влияет на архитектуру интеграций сильнее, чем выбор языка:
- жизненный цикл бота включает модерацию, а токен появляется после успешной проверки (и его можно обновлять).
- на одну организацию - до 5 ботов.
- создание бота делается через платформу business.max.ru (UI), а не через публичный API.
Историческая ремарка: Макс связывают с VK как разработчиком/инициатором, но для интегратора важнее не происхождение, а то, что официальный dev-портал и публичный Bot API уже существуют и описаны.
Отдельная ловушка для ожиданий бизнеса: каналы в Макс есть, но документация про каналы подчёркивает, что контент, публикации и управление каналом идут «внутри клиента», то есть публичного «Channels API» в стиле Telegram пока не видно.
Bot API Макс: протоколы, объекты, авторизация, ограничения
Типы API и транспорт
- Официально описан HTTPS API на platform-api.max.ru с методами GET/POST/PUT/PATCH/DELETE и ответами JSON.
- Push-события - Webhook через POST /subscriptions, Pull-события - Long Polling через GET /updates.
- WebSocket/gRPC в официальной документации Bot API не заявлены (если где-то в интернете видишь «WebSocket API Макс», это почти наверняка про неофициальные клиентские/реверсные штуки). Например, сторонняя Python-библиотека описывает работу через WebSocket и вход по номеру телефона - это другой класс интеграций (и другой уровень риска).
Аутентификация
- Токен бота выдаётся на платформе для партнёров после модерации, и это «прямой доступ к боту», его рекомендуют не светить и при подозрении на компрометацию - обновлять.
- В запросах токен передаётся заголовком Authorization: <token>. Передача через query-параметры больше не поддерживается.
- Формально в API-описании это обозначено как apiKey (то есть это не OAuth 2.0, не JWT со сроком жизни, не refresh-токены - просто ключ).
Авторизация и права
- Для групповых чатов есть права (permissions) уровня администратора: read_all_messages, add_remove_members, add_admins, change_chat_info, pin_message, write, а также дополнительные вроде edit_message, delete_message и др. - они возвращаются, например, в GET /chats/{chatId}/members/me.
- Чтобы получать события из группового чата или канала, бота нужно назначить администратором.
- Удаление сообщений через DELETE /messages возможно только если у бота есть разрешение на удаление, и тоже ограничено по времени (см. ниже).
Форматы сообщений
- POST /messages принимает text (до 4000 символов) и attachments, плюс флаги вроде notify и format (markdown или html).
- Форматирование: либо Markdown, либо HTML; упоминание пользователя делается ссылкой на max://user/user_id.
- Inline-клавиатура: до 210 кнопок, 30 рядов, до 7 кнопок в ряду (а для отдельных типов - меньше), ссылки до 2048 символов; типы кнопок включают callback, link, request_contact, request_geo_location, open_app, message.
- Нажатия callback-кнопок обрабатываются через update типа message_callback, а ответ отправляется методом POST /answers?callback_id=... и может обновить сообщение и/или показать одноразовое уведомление.
Ограничения и квоты
- Практический лимит: для стабильной работы ботов рекомендуют считать максимум 30 rps на platform-api.max.ru; при превышении ожидаем 429.
- Редактирование сообщений PUT /messages - только если сообщение отправлено менее 24 часов назад.
- Удаление сообщений DELETE /messages - тоже только для сообщений младше 24 часов, плюс нужны права.
- Webhook: должен быть HTTPS, HTTP не поддерживается; можно самоподписанный сертификат. При подписке сервер должен слушать один из разрешённых портов (80/8080/443/8443/16384-32383).
Доставка, подтверждения, «а точно дошло?»
- Для Long Polling есть важная семантика: ответы GET /updates содержат marker, который указывает на следующий ожидаемый апдейт; «все предыдущие считаются завершёнными после прохождения marker». Это почти готовая модель «подтверждения» обработки на стороне клиента, если правильно хранить marker.
- Для «прочитано» у ботов есть действие mark_seen через POST /chats/{chatId}/actions. Это полезно как управляемый read-receipt со стороны бота.
- В объекте Message есть поле stat типа MessageStat, но публично структура MessageStat в видимом списке объектов описана не полностью - так что надёжный способ строить аналитику доставки по этому полю пока не получится без экспериментов.
Медиа: хранение, загрузка и боль обработки
- POST /uploads?type=image|video|audio|file возвращает URL для загрузки; загрузка может быть multipart (просто) или resumable (надёжнее, с возобновлением). При multipart есть лимит 4 ГБ и «один файл за раз».
- Токен для прикрепления потом используется в attachments. Есть нюансы по типам (для видео/аудио в документации отдельно описана механика) и есть типовая ошибка attachment.not.ready если отправить сообщение слишком быстро после загрузки - предлагается пауза и повтор с увеличением интервала, либо заранее загружать и переиспользовать токены.
Мини-приложения и фронтенд-интеграции (CORS/CSP тут реально важны)
- Для мини-приложений есть MAX Bridge: <script src="https://st.max.ru/js/max-web-app.js"></script> даёт доступ к window.WebApp, стартовым данным и событиям клиента.
- Стартовые параметры (initData) нужно валидировать: описана процедура HMAC-SHA256 с ключом "WebAppData" и Bot Token, сортировка ключей, исключение hash, разделитель \n. Это похоже на подход Telegram Web Apps, и да - это тот случай, когда «не проверять подпись» значит «самому себе выдать админку».
- Практика безопасности для мини-приложения: жёсткий CSP (запрет inline-скриптов где возможно, allowlist доменов, запрет connect-src *), аккуратный CORS (разрешать только нужные origin), и серверная валидация initData перед любыми чувствительными действиями. (Это уже best practice, не «факт документации».)
Реалистичная архитектура интеграции и два режима получения событий
Ниже - «нормальная» архитектура, которую можно поставить в production и не ненавидеть себя через месяц.
Ключевые детали, которые стоит заложить сразу:
- Webhook как режим production: в документации прямо сказано - для production используйте только Webhook, а Long Polling - для разработки и тестов.
- Секрет в заголовке: при подписке можно указать secret, и тогда в каждом webhook-запросе будет заголовок X-Max-Bot-Api-Secret. Проверка этого заголовка - минимальный baseline (иначе твой endpoint превращается в публичный «вход в систему по URL»).
- Idempotency: Макс не описывает официальный Idempotency-Key как в Stripe, поэтому делаем прикладной dedup:для webhook: ключ дедупликации по (update_type, message.body.mid) или (update_type, callback_id); хранить в Redis с TTL.
для long polling: базовый ключ - marker, хранить last seen marker durably. - Retry/backoff: платформой задокументированы 429 и 503, а для медиа известна ошибка attachment.not.ready - всё это требует экспоненциального backoff с jitter и ограничением по времени.
- Rate limit: ориентация на 30 rps - значит, если у тебя воркеров 20, им нельзя «всем дружно» долбить API. Нужен общий клиентский rate limiter (token bucket) на процесс/кластер.
Теперь sequence-диаграмма «пришло сообщение - ответили - подтвердили кнопку».
Практика: curl и SDK-стиль на Python и Node.js
Ниже примеры специально сделаны так, чтобы их было не стыдно положить в репозиторий: реальные URL, заголовки, JSON, обработка ошибок, backoff, и аккуратное отношение к «повторным доставкам».
Регистрация бота и получение токена
Факт: публичного API для «создать бота» в документации нет - бот создаётся на платформе для партнёров и проходит модерацию; токен появляется после этого.
Что можно автоматизировать с нуля:
- проверку, что токен рабочий: GET https://platform-api.max.ru/me.
curl -sS -X GET "https://platform-api.max.ru/me" \
-H "Authorization: ${MAX_BOT_TOKEN}"
Отправка сообщений: личка и групповой чат
cURL: сообщение пользователю
curl -sS -X POST "https://platform-api.max.ru/messages?user_id=1234567890" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"text": "Привет! Это тест интеграции.",
"format": "markdown",
"notify": true
}'
cURL: сообщение в групповой чат
curl -sS -X POST "https://platform-api.max.ru/messages?chat_id=987654321" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"text": "**Системное сообщение**\nПошла обработка задачи.",
"format": "markdown",
"notify": false
}'
Публикация в канал через API
Вот здесь начинается честная часть (она же самая полезная).
- В документации по каналам сказано, что публикация постов делается в интерфейсе мессенджера, то есть публичного «post-to-channel API» не описано.
- При этом в Message есть поле url - «публичная ссылка на пост в канале» (и оно отсутствует для диалогов и групповых чатов). Это намекает, что каналы внутри системы существуют как получатели сообщений, но как именно их адресовать публично - не раскрыто.
- Плюс отдельная ремарка: чтобы получать события из канала, бота нужно сделать админом.
Вывод: официально подтверждённый сценарий «пост в канал по API» - неуточнено. Безопасная позиция в проекте: либо вы публикуете в канал руками/через мини-приложение, либо договариваетесь, что API-постинг делается только если платформа/поддержка Макс подтвердит способ получить chat_id канала и разрешит писать боту.
Если у вас уже есть внутренний chat_id канала (неважно как вы его получили, это за рамками публичной доки), то «наиболее вероятная» структура отправки выглядит так же, как в чат:
# НЕУТОЧНЕНО официально: сработает только если канал адресуется chat_id и бот имеет право write в канале
curl -sS -X POST "https://platform-api.max.ru/messages?chat_id=${CHANNEL_CHAT_ID}" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"text": "Пост в канал (если платформа это разрешила).",
"notify": true
}'
Основание для такой гипотезы - единый POST /messages?chat_id=... и наличие url для постов в канале в объекте Message, но повторюсь: официально это не описано как публичный контракт.
Webhook: подписка, проверка секрета, обработка update
Подписка на Webhook (cURL)
Обрати внимание на:
- url строго https://...
- secret ограничен regex и уходит в заголовок X-Max-Bot-Api-Secret
- порты у сервера должны быть из allowlist (иначе подпишешься, но не взлетит)
curl -sS -X POST "https://platform-api.max.ru/subscriptions" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/webhook/max",
"update_types": ["message_created", "message_callback", "bot_started"],
"secret": "my_secret_12345"
}'
Python (FastAPI): webhook handler + ответ на сообщение
import os
import time
import random
import requests
from fastapi import FastAPI, Request, HTTPException
MAX_API_BASE = "https://platform-api.max.ru"
BOT_TOKEN = os.environ["MAX_BOT_TOKEN"]
WEBHOOK_SECRET = os.environ["MAX_WEBHOOK_SECRET"]
session = requests.Session()
session.headers.update({"Authorization": BOT_TOKEN})
app = FastAPI()
def _sleep_backoff(attempt: int, base: float = 0.4, cap: float = 10.0) -> None:
# exponential backoff + jitter
delay = min(cap, base * (2 ** attempt))
delay = delay * (0.5 + random.random()) # jitter
time.sleep(delay)
def max_api_post(path: str, *, params: dict | None = None, json: dict | None = None) -> dict:
url = f"{MAX_API_BASE}{path}"
last_err = None
for attempt in range(6):
try:
r = session.post(url, params=params, json=json, timeout=10)
if r.status_code in (429, 503):
_sleep_backoff(attempt)
continue
r.raise_for_status()
return r.json()
except Exception as e:
last_err = e
_sleep_backoff(attempt)
raise RuntimeError(f"MAX API POST failed after retries: {last_err}")
def send_message_to_chat(chat_id: int, text: str, *, fmt: str | None = None) -> dict:
body = {"text": text}
if fmt:
body["format"] = fmt # "markdown" or "html"
return max_api_post("/messages", params={"chat_id": chat_id}, json=body)
def answer_callback(callback_id: str, notification: str) -> dict:
return max_api_post("/answers", params={"callback_id": callback_id}, json={"notification": notification})
@app.post("/webhook/max")
async def max_webhook(req: Request):
# 1) verify secret header
secret = req.headers.get("X-Max-Bot-Api-Secret")
if secret != WEBHOOK_SECRET:
raise HTTPException(status_code=403, detail="bad secret")
# 2) parse update
update = await req.json()
utype = update.get("update_type")
# 3) fast ack principle - do minimal work here
if utype == "message_created":
msg = update.get("message", {})
recipient = msg.get("recipient", {})
chat_id = recipient.get("chat_id")
if isinstance(chat_id, int):
# respond
send_message_to_chat(chat_id, "Принял. Обрабатываю.", fmt="markdown")
elif utype == "message_callback":
cb = update.get("callback", {})
callback_id = cb.get("callback_id")
if callback_id:
answer_callback(callback_id, "Ок, нажато.")
return {"ok": True}
Факты, на которые опирается пример: POST /subscriptions с secret формирует заголовок X-Max-Bot-Api-Secret, есть update типы и есть POST /answers, а сообщения отправляются через POST /messages на platform-api.max.ru.
Long polling: когда нужно и как не потерять события
Официальная модель GET /updates:
- timeout до 90 секунд
- limit до 1000
- marker - курсор, который «подтверждает» получение предыдущих апдейтов
curl -sS -X GET "https://platform-api.max.ru/updates?timeout=30&limit=50&types=message_created,message_callback" \
-H "Authorization: ${MAX_BOT_TOKEN}"
Node.js: long polling loop (SDK-style клиент)
import fetch from "node-fetch";
const BASE = "https://platform-api.max.ru";
const TOKEN = process.env.MAX_BOT_TOKEN;
async function sleep(ms) {
await new Promise((r) => setTimeout(r, ms));
}
async function getUpdates({ marker, timeout = 30, limit = 100, types } = {}) {
const url = new URL(`${BASE}/updates`);
url.searchParams.set("timeout", String(timeout));
url.searchParams.set("limit", String(limit));
if (marker !== undefined && marker !== null) url.searchParams.set("marker", String(marker));
if (types?.length) url.searchParams.set("types", types.join(","));
const res = await fetch(url.toString(), {
method: "GET",
headers: { Authorization: TOKEN },
});
if (res.status === 429 || res.status === 503) {
const txt = await res.text();
throw new Error(`retryable ${res.status}: ${txt}`);
}
if (!res.ok) {
const txt = await res.text();
throw new Error(`http ${res.status}: ${txt}`);
}
return await res.json();
}
async function sendMessageToChat(chatId, text) {
const url = new URL(`${BASE}/messages`);
url.searchParams.set("chat_id", String(chatId));
const res = await fetch(url.toString(), {
method: "POST",
headers: {
Authorization: TOKEN,
"Content-Type": "application/json",
},
body: JSON.stringify({ text, notify: true }),
});
if (!res.ok) {
const txt = await res.text();
throw new Error(`sendMessage failed ${res.status}: ${txt}`);
}
return await res.json();
}
async function main() {
let marker = null;
for (;;) {
try {
const page = await getUpdates({
marker,
timeout: 30,
limit: 100,
types: ["message_created"],
});
const updates = page.updates || [];
for (const u of updates) {
if (u.update_type === "message_created") {
const chatId = u.message?.recipient?.chat_id;
if (typeof chatId === "number") {
await sendMessageToChat(chatId, "pong");
}
}
}
// commit marker AFTER processing
marker = page.marker ?? marker;
} catch (e) {
// backoff for retryable errors
await sleep(800);
}
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
Основание: описание GET /updates с marker/timeout/limit/types и общая модель авторизации/JSON.
Кнопки, inline-кнопки и «псевдо-карусель»
Inline-кнопки (cURL)
bashCopycurl -sS -X POST "https://platform-api.max.ru/messages?chat_id=987654321" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"text": "Выберите действие",
"attachments": [{
"type": "inline_keyboard",
"payload": {
"buttons": [[
{ "type": "callback", "text": "Обновить", "payload": "refresh" },
{ "type": "link", "text": "Открыть сайт", "url": "https://example.com" }
]]
}
}]
}'
Обработка callback
- ловите update message_callback
- достаёте callback_id
- отвечаете POST /answers?callback_id=... (можно обновить сообщение или показать notification)
Про «карусели» честно:
- В публичной документации Bot API Макс я не нашёл отдельного attachment-типа «carousel». В официальной JS-библиотеке показывают вложения (image/video/audio/file/sticker/location/share) и клавиатуры, но не «карусель» как у некоторых платформ. Значит, это либо отсутствует, либо реализуется через мини-приложение/редактирование сообщений.
Практический обходной путь, который обычно работает в мессенджерах:
- отправляете одно сообщение с «карточкой #1» и inline-кнопками «вперёд/назад»
- по callback делаете PUT /messages и подменяете текст/вложения (если сообщение моложе 24 часов)
Да, это «карусель для бедных». Зато без магии.
Загрузка медиа, отправка файлов и голосовых
Шаг 1: получить URL
curl -sS -X POST "https://platform-api.max.ru/uploads?type=file" \
-H "Authorization: ${MAX_BOT_TOKEN}"
Шаг 2: загрузить по URL (multipart)
curl -sS -X POST "%UPLOAD_URL%" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-F "data=@report.pdf"
Шаг 3: отправить сообщение с вложением (конкретный payload зависит от ответа загрузки; ключевой контракт - вложение с type и payload из ответа)
Для «голосовых» в Bot API явно выделенного voice-типа не показано, но есть type=audio для загрузки и sending_audio как чат-экшен - то есть практично отправлять голосовое как аудио-вложение.
И ещё один нюанс, который экономит часы жизни:
- после загрузки файл может ещё обрабатываться; если отправить сразу - можно получить attachment.not.ready; рекомендация - пауза и повтор с увеличением интервала, или заранее загрузить и переиспользовать token.
Редактирование и удаление сообщений
Редактирование (cURL)
curl -sS -X PUT "https://platform-api.max.ru/messages?message_id=mid_123" \
-H "Authorization: ${MAX_BOT_TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "text": "Изменённый текст", "format": "markdown" }'
Удаление (cURL)
curl -sS -X DELETE "https://platform-api.max.ru/messages?message_id=mid_123" \
-H "Authorization: ${MAX_BOT_TOKEN}"
Ограничение: и редактирование, и удаление - только для сообщений «моложе 24 часов». Это важно для любых «workflow-ботов», которые хотят править старые статусы.
Сравнение с Telegram и WhatsApp по API-интеграциям
Сразу договоримся: сравнение ниже про API и интеграцию, а не про «какой мессенджер кому нравится».
Доступ к API и онбординг
Макс
- боты создаются через платформу для партнёров, есть модерация, токен появляется после одобрения.
- доступ к платформе ограничен (юрлица/ИП, условия входа).
Telegram
- Bot API - HTTP-based интерфейс для ботов.
- лимиты рассылок и поведение при их превышении описаны очень прямо (и да, 429 там тоже часть жизни).
- бизнес-платформа завязана на Graph API и бизнес-идентификаторы (phone number id), а отправка идёт через /PHONE_NUMBER_ID/messages.
- ограничения «шаблоны вне окна» - часть продукта: шаблоны можно отправлять вне customer service window, но они должны быть заранее одобрены.
Webhooks и polling
Макс
- Webhook и Long Polling есть, но одновременно использовать нельзя; production рекомендуют на Webhook.
- Webhook только HTTPS, есть секрет в заголовке.
Telegram
- поддерживает и webhook, и long polling (это базовая архитектура Bot API).
- webhooks - основной механизм входящих событий и статусов (delivery/read и т.д.).
Группы и каналы
Макс
- групповые чаты в API есть (/chats, права админов, участники, действия).
- про каналы: создание/ведение каналов описано, но публикация контента заявлена как функция интерфейса клиента, а не публичного API.
Telegram
- боты могут получать сообщения из каналов, где они являются участниками.
- Bot API позволяет обращаться к каналам по @channelusername в параметре chat_id во многих методах (например, editMessageText).
- классический WhatsApp Business Messaging API ориентирован на 1:1 сообщения (в официальных гайдах это постоянно прослеживается).
Мультимедиа и хранение
Макс
- upload выдаёт URL, поддерживает resumable upload, есть 4 ГБ лимит для multipart и отдельная стадия обработки после загрузки.
Telegram
- у Bot API есть своя модель файлов/file_id и отдельная загрузка, но главное для интегратора - зрелая инфраструктура и предсказуемость контрактов.
- медиа и интерактивы есть, статусы доставки и чтения возвращаются вебхуками.
Шифрование и безопасность как фактор интеграции
Тут важный момент: мы обсуждаем не «кто лучше», а какие риски ты обязан закладывать в интеграцию.
- публично заявляет end-to-end encryption для сообщений и между людьми, и с бизнесами (Signal protocol).
Telegram
- end-to-end encryption относится к Secret Chats, где ключи у участников, и это описано в официальной документации.
- боты в секретные чаты не приглашаются (техническое ограничение).
Макс
- в официальной Bot API документации я не увидел раздела, который бы утверждал наличие E2E шифрования для пользовательских чатов. При отсутствии такого заявления безопаснее проектировать интеграцию как server-side: считать, что контент обрабатывается на стороне платформы. (Это рекомендация.)
- в публичных медиа много раз утверждалось, что сквозного шифрования нет (например, Forbes, январь 2026). Это не первоисточник платформы, но как риск-сигнал для интегратора - полезно учесть.
Безопасность, устойчивость, мониторинг и checklist внедрения
Типовые ошибки и как их пережить
HTTP-ошибки
- 401 - токен неверный/отозван (или вы забыли заголовок Authorization).
- 429 - превысили лимит запросов. Решение: глобальный rate limiter + backoff.
- 503 - сервис недоступен. Решение: retry с backoff, но с верхним пределом и алёртом (иначе вы «вечно ретраите» и не знаете, что всё умерло).
Прикрепление медиа
- attachment.not.ready - классика. Решение: ждать, ретраить, переиспользовать token/прегруз.
Webhook-доставка
- контракт ретраев webhook со стороны Макс публично не описан - значит, считаем доставку как минимум «at-least-once» и делаем idempotency сами. Основание здесь косвенное: наличие webhook и общий паттерн индустрии, плюс запрет на одновременный polling.
Best practices, которые реально окупаются
- Храните BOT_TOKEN только в secret manager, не в .env на проде и не в логах. Документация прямо говорит, что токен - прямой доступ к боту.
- Для webhook:проверка X-Max-Bot-Api-Secret обязательна
ответ 200 как можно быстрее, бизнес-логика в очередь
логируйте update_type, mid, callback_id, latency обработчика. - Для long polling:храните marker durably
обновляйте marker только после успешной обработки пачки. - Для медиа:делайте pre-upload популярных файлов и кешируйте token
закладывайте задержку на обработку
если файл критичен, делайте «проверочную отправку» в тестовый чат при деплое. - Для мини-приложений:валидируйте initData по HMAC (иначе любой «нарисует» себе пользователя)
ставьте CSP и урезайте внешние источники
не доверяйте initDataUnsafe для авторизации.
Советы по тестированию и отладке
- Локальная разработка под webhook упирается в HTTPS. Документация запрещает HTTP, но разрешает самоподписанные сертификаты - значит, можно поднять локальный endpoint на HTTPS и пробросить наружу через туннель/реверс-прокси, главное - попасть в разрешённые порты.
- Делайте отдельный «тестовый бот» и отдельный «тестовый чат» - в Макс это особенно актуально, потому что редактирование/удаление ограничены 24 часами и иначе вы быстро упрётесь в «Почему оно не обновилось?».
- Для регресса API держите контрактные тесты на:GET /me
POST /messages
POST /subscriptions (и проверку заголовка секрета)
POST /uploads (и полный цикл).
Checklist внедрения интеграции
Доступ
Организация верифицирована на партнёрской платформе и имеет право создавать ботов.
Бот прошёл модерацию, получен токен, настроена ротация токена.
Инфраструктура
Есть публичный HTTPS endpoint на разрешённом порту для webhook.
Настроен WAF/ingress и rate limiting со стороны вашей инфраструктуры (чтобы не стать «отражателем» чужих атак).
Безопасность
Проверяется X-Max-Bot-Api-Secret.
Секреты и токены не логируются, не попадают в трассировки, не утекают в клиент.
Надёжность
Реализован dedup (idempotency) по mid/callback_id и safe retries на 429/503.
Реализован глобальный лимитер под 30 rps на platform-api.max.ru.
Для медиа заложены ожидание обработки и ретраи на attachment.not.ready.
Функциональность
Поддержаны: входящие сообщения (webhook или polling), исходящие сообщения, кнопки/callback, загрузка файлов, редактирование/удаление (с учетом окна 24ч).
Отдельно зафиксировано: «публикация в канал через API» - неуточнено публично, требуется подтверждение способа адресации канала и прав бота.