Вебхук для бота в MAX: порт 443, сертификат Минцифры и повторные события

Руководство2 мин чтения

Вебхук — самая частая причина, по которой перенос бота в MAX затягивается. Код отправки сообщений переписывается за вечер, а потом бот то молчит, то отвечает дважды. Ниже пять мест, где это происходит.

1. Только HTTPS на порту 443

Подписка на события создаётся через POST /subscriptions. Адрес вебхука должен работать по HTTPS на порту 443 с сертификатом доверенного центра. Самоподписанный сертификат и нестандартный порт не подойдут. Если бот жил на сервере без домена, понадобится домен и сертификат, например от Let’s Encrypt.

2. Сертификат Минцифры на стороне бота

Это обратная сторона: не MAX стучится к вам, а ваш бот стучится в API MAX. Сертификат API выпущен цепочкой Минцифры, которой нет в стандартных хранилищах сертификатов. Поэтому HTTP-клиент бота падает на проверке. Решение — добавить корневой сертификат Минцифры в доверенные в образе или контейнере бота. Отключать проверку сертификатов не стоит.

3. Ответ 200 за 30 секунд

MAX ждёт ответ на вебхук не дольше 30 секунд. Если бот сначала идёт в CRM или считает что-то долгое, а потом отвечает 200, событие может считаться недоставленным. Правило простое: сразу отвечайте 200, а тяжёлую работу делайте в фоне.

4. Повторная доставка и дубли

Если MAX не получил 200 вовремя, он доставит событие ещё раз. Без проверки бот ответит пользователю дважды, создаст две заявки или спишет два бонуса. Нужна дедупликация: храните идентификаторы обработанных событий и пропускайте повторы.

seen = set()  # в бою: Redis с TTL
 
def handle(update):
    key = (update['update_type'], update['timestamp'])  # упрощённо
    if key in seen:
        return  # повтор, уже обработали
    seen.add(key)
    process(update)

5. Long polling молчит при активной подписке

Для отладки удобно запускать бота на long polling через GET /updates. Но если на бота уже есть подписка на вебхук, long polling молча ничего не получает. Перед отладкой удалите подписку через DELETE /subscriptions, а перед запуском в бой верните её.

Как обойтись без всего этого

Шлюз BotHop сам держит вебхук MAX на 443, доверяет цепочке Минцифры, отвечает MAX вовремя и отсекает повторы. Бот получает события так, как привык в Telegram: через getUpdates или на свой вебхук. Меняется только адрес API — api.bothop.ru вместо api.telegram.org.

ПроблемаВручнуюЧерез BotHop
ВебхукПоднять HTTPS на порту 443 с сертификатом доверенного центраДержит шлюз
Сертификат MAXДобавить цепочку Минцифры, иначе клиент падает на проверкеУже настроено
Повторные апдейтыНаписать защиту, иначе бот отвечает дваждыДубли отсекаются
Длинные сообщенияРезать текст: в MAX лимит 4 000 символовРежутся по абзацам
Связь с TelegramДержать отдельный сервер для связи с TelegramСтабильная связь через BotHop

Частые вопросы

Можно ли в MAX использовать long polling?

Можно, через `GET /updates`. Но пока активна подписка на вебхук, long polling ничего не получает, а для работы в бою MAX требует вебхук.

Почему бот в MAX отвечает дважды?

MAX повторяет доставку события, если не получил ответ 200 вовремя. Без проверки на дубли бот обрабатывает одно и то же событие два раза.

Зачем нужен сертификат Минцифры?

Сертификат API MAX выпущен цепочкой Минцифры, которой нет в стандартных хранилищах. Без неё HTTP-клиент бота не доверяет серверу MAX и падает на проверке.