Як тестувати вебхук Telegram-бота

Спрямовуємо бота на публічну адресу через setWebhook, роздивляємося сирі апдейти від Telegram і пересилаємо їх боту, що працює на вашій машині.

Оновлено:

Telegram-бот отримує апдейти двома способами: сам опитує сервер через getUpdates або Telegram штовхає кожен апдейт на вебхук. У продакшені зазвичай вебхук, але налагоджувати його складніше, бо не видно, що саме приходить. Покажемо, як спрямувати бота на адресу-перехоплювач, роздивитися сирі апдейти і переслати їх боту, запущеному локально.

Як працюють вебхуки Telegram

Ви реєструєте HTTPS-адресу через setWebhook. Відтоді на кожен новий апдейт Telegram надсилає туди POST із JSON-об’єктом Update. Якщо статус відповіді не 2xx, Telegram повторює запит і після розумної кількості спроб здається.

Два правила, про які варто пам’ятати:

  • Вебхук і getUpdates взаємовиключні. Поки вебхук встановлено, getUpdates не працює. Щоб повернутися до polling, викличте deleteWebhook.
  • Порти. Вебхуки підтримуються лише на портах 443, 80, 88 і 8443. Адреса перехоплювача працює на стандартному HTTPS-порту 443 з валідним сертифікатом.

Крок 1: створіть адресу для перехоплення

Відкрийте Webhook Inspector і створіть адресу з назвою, скажімо, tgbot. Підшлях після неї теж ловиться, тож зареєструємо бота із суфіксом /webhook, який потім збігатиметься з маршрутом локального обробника:

https://webhook.voronyuk.com/abcd23efgh/tgbot/webhook

Крок 2: викличте setWebhook

Замість <BOT_TOKEN> підставте токен від @BotFather:

curl -X POST "https://api.telegram.org/bot<BOT_TOKEN>/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://webhook.voronyuk.com/abcd23efgh/tgbot/webhook",
    "secret_token": "my_bot_secret_123",
    "allowed_updates": ["message", "callback_query"],
    "drop_pending_updates": true
  }'
Параметр Що робить
url HTTPS-адреса для апдейтів. Порожній рядок знімає вебхук
secret_token 1–256 символів (A-Z, a-z, 0-9, _, -). Повертається в заголовку X-Telegram-Bot-Api-Secret-Token кожного запиту
allowed_updates Які типи апдейтів отримувати. Якщо не вказати, лишається попереднє налаштування
drop_pending_updates true викидає апдейти, що чекають на доставку
max_connections Скільки одночасних HTTPS-з’єднань, 1–100 (за замовчуванням 40)

Крок 3: напишіть боту й подивіться на апдейт

Надішліть боту /start. В інспекторі одразу з’явиться POST із заголовком X-Telegram-Bot-Api-Secret-Token і тілом приблизно такого вигляду:

{
  "update_id": 123456789,
  "message": {
    "message_id": 42,
    "from": {
      "id": 111111111,
      "is_bot": false,
      "first_name": "Taras",
      "language_code": "uk"
    },
    "chat": {
      "id": 111111111,
      "first_name": "Taras",
      "type": "private"
    },
    "date": 1760950000,
    "text": "/start",
    "entities": [{ "offset": 0, "length": 6, "type": "bot_command" }]
  }
}

Натисніть inline-кнопку, відредагуйте повідомлення або додайте бота в групу. Кожна дія дає інший тип апдейту (callback_query, edited_message, my_chat_member), і коли бачиш точний JSON, обробники пишуться значно швидше. Пошуком в інспекторі зручно знаходити конкретний chat.id чи текст серед усіх перехоплених апдейтів.

Крок 4: перевірте стан вебхука

curl "https://api.telegram.org/bot<BOT_TOKEN>/getWebhookInfo"

У відповіді є url, pending_update_count, last_error_date, last_error_message, max_connections і allowed_updates. Якщо апдейти не доходять, причину зазвичай видно в last_error_message.

Крок 5: перевірте secret token

Secret token — не підпис, а спільне значення, яке Telegram повертає без змін. Порівнюйте його за сталий час:

import hmac
import os

from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["TG_WEBHOOK_SECRET"]


@app.post("/webhook")
def webhook():
    token = request.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
    if not hmac.compare_digest(token, SECRET):
        abort(403)
    update = request.get_json()
    if "message" in update:
        print(update["message"]["chat"]["id"], update["message"].get("text"))
    return "", 200


if __name__ == "__main__":
    app.run(port=3000)

Та сама перевірка на Node.js:

const crypto = require('crypto');

function validSecret(header, secret) {
  const a = Buffer.from(header || '');
  const b = Buffer.from(secret);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Крок 6: перешліть апдейти локальному боту

Вебхук лишається на адресі перехоплювача, а кожен апдейт пересилається вашому боту на localhost. У панелі Пересилання вкажіть ціль http://localhost:3000. Підшлях дописується до цілі, тож .../abcd23efgh/tgbot/webhook прийде на http://localhost:3000/webhook — саме той маршрут, що в прикладі вище. Запустіть CLI-агент:

WI_TOKEN='<токен>' inspector listen https://webhook.voronyuk.com/abcd23efgh/tgbot --to localhost:3000

Точну команду з токеном скопіюйте з панелі. Агент працює без браузера, сам перепідключається і доганяє пропущені апдейти. Relay через браузер теж підійде, якщо локальний сервер дозволяє CORS. Порівняння варіантів — у гайді як тестувати вебхуки локально.

Коли обробник падає, виправте код і повторіть перехоплений апдейт із тестера вебхуків Telegram, замість того щоб знову писати боту.

Крок 7: поверніться до polling

curl "https://api.telegram.org/bot<BOT_TOKEN>/deleteWebhook?drop_pending_updates=true"

Після цього getUpdates знову працює.

Схожі гайди: Slack Events API і вебхуки Twilio.

Часті питання

Як побачити, що отримує мій Telegram-бот?

Встановіть вебхук на адресу перехоплювача через setWebhook і напишіть боту. Повний JSON Update і заголовки з’являться наживо.

Чому getUpdates не працює, коли встановлено вебхук?

Ці два способи взаємовиключні. Перед polling через getUpdates викличте deleteWebhook.

Які порти підтримує вебхук Telegram?

443, 80, 88 і 8443. Адреса має бути HTTPS.

Що таке X-Telegram-Bot-Api-Secret-Token?

Це secret_token, який ви передали в setWebhook. Telegram надсилає його в заголовку з кожним апдейтом, а ви порівнюєте зі своїм значенням, щоб переконатися, що запит справді від Telegram.

Як налагодити вебхук Telegram-бота локально?

Ловіть апдейти на публічну адресу і пересилайте їх на localhost через CLI-агент або relay у браузері. Поки виправляєте обробник, будь-який перехоплений апдейт можна повторити.

Спробуйте зараз

Отримайте безкоштовний URL для вебхуків і дивіться, як приходять запити, — без реєстрації.

Отримати URL для вебхуків

Інші гайди

Localhost

Як тестувати вебхуки локально

Чому Stripe, GitHub та інші сервіси не бачать ваш localhost і як зловити справжній вебхук на публічній адресі, а потім переслати його собі на машину.

GitHub

Як тестувати вебхуки GitHub

Налаштовуємо вебхук репозиторію, розбираємо заголовки GitHub, правильно перевіряємо X-Hub-Signature-256 і повторно доставляємо події під час налагодження.

MCP

Тестування вебхуків із Claude і ChatGPT через MCP

Підключіть Webhook Inspector як MCP-сервер, і AI-асистент сам створить URL, дочекається вебхука й розбере його разом із вами.

Shopify

Як тестувати вебхуки Shopify

Створюємо вебхук магазину або підписку застосунку, розбираємо заголовки X-Shopify, перевіряємо X-Shopify-Hmac-Sha256 і враховуємо тайм-аути та повтори Shopify.

Slack

Як тестувати Slack Events API та interactivity

Дивимося, що Slack надсилає на Request URL, проходимо перевірку url_verification, валідуємо X-Slack-Signature і розкодовуємо form-encoded payload від interactivity.

Stripe

Як тестувати вебхуки Stripe

Налаштовуємо ендпоінт у Stripe, дивимося, що саме приходить, перевіряємо Stripe-Signature на Node.js і Python та пересилаємо події на локальний застосунок.

Twilio

Як тестувати вебхуки Twilio для SMS і дзвінків

Спрямовуємо номер Twilio на адресу-перехоплювач, читаємо form-encoded параметри, відповідаємо TwiML без власного сервера і перевіряємо X-Twilio-Signature через офіційні бібліотеки.