Для продакшн-ботов вебхук — единственно правильный выбор. 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 за