Подключение Telegram Webhook на чистом PHP: setWebhook, secret_token и идемпотентность

Для продакшн-ботов вебхук — единственно правильный выбор. Long polling подходит для локальной отладки, но на боевом сервере даёт лишнюю нагрузку, задержки и проблемы с масштабированием. Telegram требует HTTPS с валидным сертификатом (не самоподписанным), открытый порт 443, 80, 88 или 8443 и ответ 200 OK в течение нескольких секунд. Ниже — минимальный рабочий стек на чистом PHP 8.1+ без фреймворков.

Требования к серверу и PHP

Нужны расширения curl, json, mbstring, openssl и pdo (для БД). Проверьте: php -m | grep -E 'curl|json|pdo|mbstring|openssl'. Веб-сервер (Nginx/Apache) должен отдавать PHP-скрипт по публичному HTTPS-URL, например https://bot.example.com/webhook.php. Убедитесь, что post_max_size и upload_max_filesize не режут входящие апдейты (до 30 Мб при файлах).

Регистрация вебхука: setWebhook через cURL

Не используйте file_get_contents для API Telegram — нет контроля HTTP-кодов и таймаутов. Пишем однократный скрипт set_webhook.php для запуска из CLI при деплое или ротации токена.

Параметр secret_token генерируется один раз (bin2hex(random_bytes(32))) и хранится в .env. Telegram пришлёт его в заголовке X-Telegram-Bot-Api-Secret-Token при каждом запросе — это защита от посторонних POST-запросов к вашему эндпоинту. drop_pending_updates=true чистит очередь при перерегистрации, чтобы не обрабатывать старые апдейты после деплоя. max_connections ограничивает параллельность доставки (1–100, дефолт 40).

Точка входа: webhook.php

Скрипт должен отработать максимально быстро: прочитать тело, проверить секрет, распарсить JSON, записать update_id в БД для идемпотентности и вернуть 200. Вся тяжёлая логика (рассылки, внешние API, БД-записи лидов) — в очередь (RabbitMQ, Redis Streams, таблица jobs + воркер) или асинхронный процесс.

Важно: JSON_BIGINT_AS_STRING сохраняет update_id, user.id, chat.id как строки, избегая переполнения на 32-битных сборках и потери точности в JSON.

Схема БД для идемпотентности

Таблица должна быть в той же транзакционной БД, что и бизнес-данные (MySQL/PostgreSQL/SQLite). Индекс на update_id — первичный ключ.

Очистка processed_updates по крону раз в сутки/неделю: DELETE FROM processed_updates WHERE received_at . Telegram гарантирует монотонный рост update_id, поэтому старые записи не нужны.

Обработка апдейтов в воркере

Воркер читает jobs где status=0, помечает status=1, парсит payload, выполняет логику. При успехе — status=2, при ошибке — инкремент attempts, бэкофф, при превышении лимита — status=3 и алерт. Так вебхук всегда отвечает 200 за

Новые статьи — в Telegram

Разбираем, что автоматизировать в бизнесе и как это работает на практике. Без спама.