Telegram Bot API
🌐 Русский

Вебхук для Telegram-бота: настройка setWebhook, проверка и удаление

· 9 мин чтения

Вебхук Телеграм-бота — это HTTPS-адрес вашего сервера, на который Telegram сам отправляет POST-запрос с каждым новым апдейтом. Включается он одним вызовом setWebhook, проверяется через getWebhookInfo, а удаляется методом deleteWebhook. Ниже — требования к серверу, готовые команды curl, обработчики с проверкой secret_token на Python и Node.js и разбор типичных ошибок, включая n8n на localhost.

Вебхук или getUpdates: что выбрать

getUpdates (long polling)Вебхук
Кто инициируетБот сам опрашивает TelegramTelegram присылает апдейты на ваш сервер
Что нужноЛюбая машина с интернетом, даже за NATПубличный HTTPS-адрес и сертификат
Когда удобенРазработка, небольшие боты, нет доменаПродакшен, serverless, нагрузка с пиками

Способы взаимоисключающие: пока вебхук установлен, getUpdates не работает. В обоих случаях Telegram хранит недоставленные апдейты не дольше 24 часов.

Требования к серверу для вебхука

Как установить вебхук через setWebhook

ПараметрЗачем нужен
urlHTTPS-адрес обработчика. Пустая строка удаляет вебхук
secret_token1–256 символов A-Z, a-z, 0-9, _, -; приходит в заголовке X-Telegram-Bot-Api-Secret-Token
allowed_updatesКакие типы апдейтов присылать, например ["message", "callback_query"]
drop_pending_updatestrue — выбросить накопившиеся апдейты
max_connectionsОдновременных соединений к серверу: 1–100, по умолчанию 40
certificateПубличный ключ самоподписанного сертификата (только файлом, multipart)
ip_addressФиксированный IP вместо адреса из DNS
export BOT_TOKEN="123456789:AAEexampleTokenReplaceWithYours"
export WEBHOOK_SECRET="$(openssl rand -hex 32)"   # сохраните — он нужен обработчику

curl -s "https://api.telegram.org/bot$BOT_TOKEN/setWebhook" \
  --data-urlencode "url=https://bot.example.com/telegram/webhook" \
  -d "secret_token=$WEBHOOK_SECRET" \
  --data-urlencode 'allowed_updates=["message","callback_query"]' \
  -d drop_pending_updates=true \
  -d max_connections=40
{"ok": true, "result": true, "description": "Webhook was set"}

Учтите: если allowed_updates не передать, сохранится прежний список. Пустой список означает все типы, кроме chat_member, message_reaction и message_reaction_count. Попробовать без терминала можно в Bot API Tester на методе setWebhook.

С самоподписанным сертификатом в CN можно указать IP-адрес сервера, а публичный ключ передать файлом:

openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 365 \
  -out public.pem -subj "/CN=203.0.113.10"

curl -s "https://api.telegram.org/bot$BOT_TOKEN/setWebhook" \
  -F "url=https://203.0.113.10:8443/telegram/webhook" \
  -F "certificate=@public.pem" \
  -F "secret_token=$WEBHOOK_SECRET"

Проверка вебхука: getWebhookInfo

curl -s "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo"
{
  "ok": true,
  "result": {
    "url": "https://bot.example.com/telegram/webhook",
    "has_custom_certificate": false,
    "pending_update_count": 12,
    "last_error_date": 1793275800,
    "last_error_message": "Wrong response from the webhook: 502 Bad Gateway",
    "max_connections": 40,
    "allowed_updates": ["message", "callback_query"]
  }
}

Обработчик вебхука с проверкой secret_token

Адрес вебхука публичный, поэтому любой может отправить на него поддельный апдейт. Заголовок X-Telegram-Bot-Api-Secret-Token отсекает такие запросы: сравнивайте его с секретом за постоянное время и отвечайте 403 на чужие запросы.

Python, FastAPI (pip install fastapi uvicorn):

import hmac
import os

from fastapi import FastAPI, Header, HTTPException, Request

WEBHOOK_SECRET = os.environ["WEBHOOK_SECRET"]
app = FastAPI()


@app.post("/telegram/webhook")
async def telegram_webhook(
    request: Request,
    x_telegram_bot_api_secret_token: str | None = Header(default=None),
):
    received = (x_telegram_bot_api_secret_token or "").encode()
    if not hmac.compare_digest(received, WEBHOOK_SECRET.encode()):
        raise HTTPException(status_code=403)
    update = await request.json()
    # положите апдейт в очередь и сразу верните 200
    print("update", update["update_id"])
    return {"ok": True}

Node.js, Express (npm i express):

import crypto from 'node:crypto';
import express from 'express';

const expected = Buffer.from(process.env.WEBHOOK_SECRET);
const app = express();
app.use(express.json());

app.post('/telegram/webhook', (req, res) => {
  const received = Buffer.from(req.get('X-Telegram-Bot-Api-Secret-Token') ?? '');
  if (received.length !== expected.length || !crypto.timingSafeEqual(received, expected)) {
    return res.sendStatus(403);
  }
  res.sendStatus(200); // сначала ответ Telegram
  handleUpdate(req.body).catch(console.error); // потом обработка
});

async function handleUpdate(update) {
  console.log('update', update.update_id);
}

app.listen(8000); // TLS терминирует nginx или Caddy перед приложением

Отвечайте 2xx быстро

Бонус: в ответе на вебхук можно сразу вызвать метод Bot API. Верните JSON с полем method и параметрами — Telegram выполнит запрос, но узнать его результат вы не сможете:

{"method": "sendMessage", "chat_id": 123456789, "text": "Принято!"}

Как удалить вебхук телеграм-бота

Чтобы вернуться к getUpdates, вызовите deleteWebhook. Параметр drop_pending_updates=true заодно выбросит накопившиеся апдейты — удобно, если бот долго лежал и не должен отвечать на старые сообщения:

curl -s "https://api.telegram.org/bot$BOT_TOKEN/deleteWebhook?drop_pending_updates=true"

Без этого параметра очередь сохранится, и getUpdates отдаст её целиком. Тот же эффект, что и у deleteWebhook, даёт setWebhook с пустым url.

Частые ошибки вебхука

Bad Request: bad webhook: An HTTPS URL must be provided for webhook — в url передан адрес с http:// или без схемы. Нужен именно https:// и публичный домен или IP.

409 Conflict при вызове getUpdates — вебхук установлен, и long polling заблокирован. Если вебхук поставил другой сервис (например, n8n), а вам нужен polling, вызовите deleteWebhook. Если же нужен вебхук, остановите скрипт, который вызывает getUpdates.

n8n на localhost. Telegram-триггер в n8n регистрирует вебхук через setWebhook, а адрес вида http://localhost:5678 не подходит дважды: это не HTTPS, и Telegram не может достучаться до вашего компьютера. Нужен публичный HTTPS-адрес: n8n на сервере с доменом за nginx или Caddy с сертификатом либо туннель вроде cloudflared или ngrok. Публичный адрес нужно передать самой n8n (обычно через переменную окружения WEBHOOK_URL), чтобы она регистрировала у Telegram именно его.

Вебхук установлен, но апдейты не приходят. Смотрите last_error_message в getWebhookInfo. Типичные причины: неподдерживаемый порт, неполная цепочка сертификатов, редирект, обработчик падает с 5xx или файрвол не пускает подсети Telegram. Проверить TLS с внешней машины поможет curl -v https://bot.example.com/telegram/webhook.

Вебхук принимает апдейты, а отправка ответов работает как обычно — через sendMessage, подробности в гайде как отправить сообщение через бота. Если бот только создаётся, начните с инструкции по созданию бота, а при проблемах с токеном загляните в гайд токен бота Telegram. Про ограничения на число соединений и хранение апдейтов — в обзоре лимиты Telegram Bot API.

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

Как удалить вебхук Телеграм-бота?

Вызовите https://api.telegram.org/bot<token>/deleteWebhook. С параметром drop_pending_updates=true заодно удалятся накопившиеся апдейты. После этого снова работает getUpdates.

Можно ли использовать вебхук и getUpdates одновременно?

Нет, это взаимоисключающие способы. Пока вебхук установлен, getUpdates возвращает 409 Conflict.

Какие порты поддерживает вебхук Telegram?

Только 443, 80, 88 и 8443, причём HTTPS обязателен на любом из них. Порт, отличный от 443, указывается прямо в URL: https://example.com:8443/webhook.

Нужен ли платный SSL-сертификат для вебхука?

Нет. Подойдёт бесплатный сертификат, например Let's Encrypt, или самоподписанный — его нужно загрузить в параметре certificate при вызове setWebhook.

Как проверить, что запрос на вебхук пришёл от Telegram?

Передайте secret_token в setWebhook: Telegram будет присылать его в заголовке X-Telegram-Bot-Api-Secret-Token каждого запроса. Сравнивайте заголовок с ожидаемым значением и отклоняйте запросы без него.

Почему Telegram присылает один и тот же апдейт повторно?

Ваш сервер ответил не 2xx или не ответил вовремя, и Telegram повторил доставку. Отвечайте 200 сразу, тяжёлую обработку выносите в фон, а дубли отсекайте по update_id.

Как создать бота в Телеграм: от @BotFather до первого сообщения

Как создать бота в Телеграм: регистрация в @BotFather, токен, проверка через getMe, первое сообщение на curl и Python, команды и описание бота.

Что нового в Telegram Bot API 10.0–10.3: rich-сообщения, эфемерные сообщения и гостевой режим

Что нового в Telegram Bot API 10.0–10.3: rich-сообщения, эфемерные сообщения, гостевой режим, заявки на вступление — с примерами и чек-листом миграции.

Лимиты Telegram Bot API: сообщения в секунду, ошибка 429 и размеры файлов

Все лимиты Telegram Bot API в одном месте: сообщения в секунду, ошибка 429 и retry_after, платные рассылки, размеры файлов, длина текста и подписи.

Как отправить сообщение через бота Telegram: sendMessage, разметка и кнопки

Как отправить сообщение через бота Telegram: sendMessage на curl, Python и JavaScript, parse_mode HTML и MarkdownV2, кнопки и ошибки 400, 403, 429.

Токен бота Telegram: как получить, где найти, как проверить и отозвать

Как получить токен бота Телеграм в @BotFather, где взять токен уже созданного бота, как проверить его через getMe и что делать, если токен утёк.

Как узнать chat id в Telegram: пользователь, группа, канал и тема форума

Как узнать chat id в Telegram через getUpdates: личный чат, группа, супергруппа, канал и тема форума. Форматы id с -100 и что делать с пустым result.

Тестирование Telegram Mini App: от браузера до отладки на телефоне

Тестирование Telegram Mini App по шагам: mock-режим в браузере, HTTPS-туннель для localhost, тестовая среда, DevTools на телефоне и проверка initData.