Интеграция формы заявки с Telegram-ботом: пошагово
Как принимать заявки с сайта в Telegram-чат через бота: создание токена, привязка PHP, обработка ошибок и анти-спам. Готовые сниппеты.
Содержание
- Что мы сделаем
- Шаг 1: создание бота
- Шаг 2: получение chat_id
- Шаг 3: проверка отправки
- Шаг 4: PHP-обработчик формы
- Шаг 5: HTML-форма
- Шаг 6: JavaScript для отправки
- Шаг 7: продвинутая защита от спама
- Шаг 8: дублирование на email
- Шаг 9: интеграция с CRM
- Чего не делать
- Чек-лист рабочей интеграции
- Когда стоит делегировать
- Частые вопросы
Форма с уведомлением в Telegram собирается за 1-2 часа: создать бота, узнать chat_id, отправить тестовое сообщение, добавить PHP-обработчик. Заявка долетает за 2-3 секунды после нажатия кнопки. Скрытое поле-ловушка и проверка времени заполнения отбивают около 80 процентов ботов.
Telegram-бот для приёма заявок это самый простой и надёжный способ получать уведомления о новых лидах в режиме реального времени. Не нужно проверять почту, не нужно ждать письмо, никто не пропустит важную заявку. Заявка пришла в Telegram-канал или в личку через 2-3 секунды после нажатия Отправить.
Разберу, как сделать с нуля: от создания бота через BotFather до полностью работающей интеграции с PHP-формой на сайте, плюс защита от спама и обработка ошибок.

Что мы сделаем
Полная схема:
- Пользователь заполняет форму на сайте.
- JS отправляет данные на ваш PHP-обработчик (например,
mail.php). - PHP-обработчик валидирует, проверяет анти-спам, сохраняет данные.
- PHP-обработчик через Telegram Bot API отправляет сообщение в указанный чат.
- Параллельно может отправлять email и/или сохранять в CSV.
- Возвращает успех или ошибку обратно в JS.
- JS показывает пользователю подтверждение или сообщение об ошибке.
Время реализации с нуля: 1-2 часа на простую форму, 4-6 часов на форму с валидацией и анти-спамом.
Шаг 1: создание бота
В Telegram пишете боту @BotFather. Команды:
/newbotсоздать нового бота.- BotFather просит имя (отображаемое, например
Saitfix Bot) и username (@saitfix_bot, должен заканчиваться на_bot). - После регистрации он отдаёт API-токен в формате
0123456789:AAAA....
Сохраните этот токен в безопасном месте, не показывайте никому. С ним любой может писать от имени вашего бота.
Шаг 2: получение chat_id
Telegram API не знает, кому слать сообщение, без chat_id получателя. Получаем.
Вариант 1: личные сообщения
Открываете чат с вашим ботом, пишете /start. Бот пока ничего не отвечает (мы его ещё не запрограммировали), но Telegram уже знает, что вы с ним переписывались.
Открываете в браузере:
https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates
Видите JSON с историей. Ищете блок from > id. Это ваш chat_id (положительное число).
Вариант 2: групповой чат
Создаёте группу в Telegram, добавляете туда бота. Пишете в группе любое сообщение. Снова getUpdates. В JSON ищете chat > id для группы. Это отрицательное число с минусом, например -1001234567890.
Используете chat_id для отправки. В личке только лично, в группе все участники видят.
Вариант 3: канал (для уведомлений в моноголосовом виде)
Создаёте Telegram-канал, добавляете бота как администратора с правом постить. Постите туда что-нибудь, через getUpdates находите chat > id. Используется тот же.
Я обычно делаю групповой чат для приёма заявок: туда добавлены все, кто реагирует на лиды.
Шаг 3: проверка отправки
Простая команда через curl или браузер:
https://api.telegram.org/bot<ТОКЕН>/sendMessage?chat_id=<CHAT_ID>&text=Привет%20мир
Если бот пришёл в указанный чат с текстом Привет мир, всё работает. Запоминаем формат API.
Шаг 4: PHP-обработчик формы
Базовый обработчик mail.php:
<?php
header('Content-Type: application/json; charset=utf-8');
// 1. Принимаем только POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['ok' => false, 'error' => 'Method not allowed']);
exit;
}
// 2. Конфиг (в production выносим в отдельный файл вне webroot)
$BOT_TOKEN = '0123456789:AAAA...';
$CHAT_ID = '-1001234567890';
$RECAPTCHA_SECRET = ''; // если используете
// 3. Валидация полей
$name = trim($_POST['name'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$email = trim($_POST['email'] ?? '');
$message = trim($_POST['message'] ?? '');
$consent = $_POST['consent'] ?? '';
if (!$name || !$phone || $consent !== 'on') {
http_response_code(400);
echo json_encode(['ok' => false, 'error' => 'Заполните обязательные поля']);
exit;
}
if (!preg_match('/^[+d-()s]{7,20}$/', $phone)) {
http_response_code(400);
echo json_encode(['ok' => false, 'error' => 'Некорректный телефон']);
exit;
}
// 4. Анти-спам: honeypot
if (!empty($_POST['website'])) {
// honeypot заполнен ботом
http_response_code(200);
echo json_encode(['ok' => true]);
exit;
}
// 5. Анти-спам: проверка времени
$formStart = (int)($_POST['ts'] ?? 0);
if ($formStart > 0 && (time() - $formStart) < 3) {
http_response_code(400);
echo json_encode(['ok' => false, 'error' => 'Слишком быстрая отправка']);
exit;
}
// 6. Формируем сообщение для Telegram
$text = "🆕 Новая заявка с сайтаnn";
$text .= "👤 Имя: " . htmlspecialchars($name) . "n";
$text .= "📱 Телефон: " . htmlspecialchars($phone) . "n";
if ($email) {
$text .= "✉️ Email: " . htmlspecialchars($email) . "n";
}
if ($message) {
$text .= "💬 Сообщение: " . htmlspecialchars($message) . "n";
}
$text .= "n🌐 Источник: " . ($_SERVER['HTTP_REFERER'] ?? 'unknown');
$text .= "n📅 " . date('d.m.Y H:i');
// 7. Отправка в Telegram
$telegramUrl = "https://api.telegram.org/bot{$BOT_TOKEN}/sendMessage";
$payload = [
'chat_id' => $CHAT_ID,
'text' => $text,
'parse_mode' => 'HTML',
];
$ch = curl_init($telegramUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
// Логируем ошибку (но не показываем пользователю)
error_log("Telegram API failed: $response");
http_response_code(500);
echo json_encode(['ok' => false, 'error' => 'Не удалось отправить заявку. Попробуйте позже.']);
exit;
}
// 8. Параллельно сохраняем в CSV для бэкапа
$logEntry = [
date('c'),
$name,
$phone,
$email,
str_replace(["n", "r"], ' ', $message),
$_SERVER['REMOTE_ADDR'],
];
$logFile = __DIR__ . '/../private/leads.csv';
$fp = fopen($logFile, 'a');
fputcsv($fp, $logEntry);
fclose($fp);
// 9. Возвращаем успех
echo json_encode(['ok' => true, 'message' => 'Заявка отправлена']);
Этот код: — Принимает POST с формы. — Валидирует поля. — Проверяет honeypot (скрытое поле, которое заполняют только боты). — Проверяет время заполнения (если меньше 3 секунд, скорее всего бот). — Формирует красивое сообщение с эмодзи. — Отправляет в Telegram. — Сохраняет в CSV для бэкапа. — Возвращает JSON о результате.
Шаг 5: HTML-форма
Минимальная форма:
<form id="contact-form">
<input type="hidden" name="ts" value="">
<!-- Honeypot, скрыт от пользователей -->
<input type="text" name="website"
style="position:absolute;left:-9999px"
tabindex="-1" autocomplete="off">
<label>
Имя <input type="text" name="name" required>
</label>
<label>
Телефон <input type="tel" name="phone" required pattern="[+d-()s]{7,20}">
</label>
<label>
Email <input type="email" name="email">
</label>
<label>
Сообщение <textarea name="message" rows="3"></textarea>
</label>
<label>
<input type="checkbox" name="consent" required>
Я согласен на обработку персональных данных.
<a href="/privacy/" target="_blank">Политика конфиденциальности</a>
</label>
<button type="submit">Отправить заявку</button>
<div id="form-status"></div>
</form>
Несколько важных моментов:
name="website"это honeypot. Поле невидимо для пользователя, но боты заполняют все поля.patternдля телефона добавляет браузерную валидацию.consentобязателен по 152-ФЗ.
Шаг 6: JavaScript для отправки
const form = document.getElementById('contact-form');
const status = document.getElementById('form-status');
// При фокусе на форму запоминаем время
form.addEventListener('focusin', () => {
if (!form.querySelector('[name="ts"]').value) {
form.querySelector('[name="ts"]').value = Math.floor(Date.now() / 1000);
}
}, { once: true });
form.addEventListener('submit', async (e) => {
e.preventDefault();
status.textContent = 'Отправка...';
const formData = new FormData(form);
try {
const response = await fetch('/mail.php', {
method: 'POST',
body: formData,
});
const data = await response.json();
if (data.ok) {
status.textContent = 'Заявка отправлена. Свяжемся в течение часа.';
form.reset();
} else {
status.textContent = data.error || 'Ошибка отправки.';
}
} catch (err) {
status.textContent = 'Ошибка сети. Попробуйте позже.';
}
});
Простой fetch, обработка ответа. Никаких внешних библиотек.

Шаг 7: продвинутая защита от спама
Honeypot и проверка времени отбивают 80 процентов ботов. Для оставшихся 20 несколько вариантов.
Вариант 1: yandex-CAPTCHA
Российский аналог reCAPTCHA. Бесплатно, работает в РФ. Подключается похоже на Google.
Регистрируетесь в cloud.yandex.ru/services/smartcaptcha, получаете client key и server key. На странице вставляете виджет, в обработчике сверяете токен через API.
Вариант 2: rate limiting
Один IP не может отправить больше 5 заявок в час. Реализуется через файл с временем последней отправки или через Redis.
$ipFile = __DIR__ . '/../private/rate-limit/' . md5($_SERVER['REMOTE_ADDR']);
if (file_exists($ipFile)) {
$count = (int)file_get_contents($ipFile);
if ($count > 5) {
http_response_code(429);
echo json_encode(['ok' => false, 'error' => 'Слишком много заявок']);
exit;
}
}
file_put_contents($ipFile, ((int)@file_get_contents($ipFile) + 1));
// Отдельным cron'ом сбрасываем папку каждый час
Вариант 3: проверка ключевых слов
Простой блек-лист: casino, viagra, crypto, forex. Если в имени или сообщении встречается, отбрасываем.
$blacklist = ['casino', 'viagra', 'crypto', 'forex', 'bitcoin'];
foreach ($blacklist as $word) {
if (stripos($name . ' ' . $message, $word) !== false) {
// молча отбрасываем как успешное
echo json_encode(['ok' => true]);
exit;
}
}
Вариант 4: проверка JS
Если форма отправляется через fetch, и заголовок X-Requested-With: XMLHttpRequest отсутствует, скорее всего бот отправляет вне браузера.
В JS добавляете заголовок:
fetch('/mail.php', {
method: 'POST',
body: formData,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
});
В PHP проверяете:
if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest') {
http_response_code(403);
exit;
}
Эти четыре уровня в комбинации отбивают почти всех ботов.
Шаг 8: дублирование на email
Telegram удобный, но нужен и email-бэкап. Если Telegram упал, email сохранит заявку.
Добавляем в обработчик после Telegram:
$to = 'info@saitfix.ru';
$subject = 'Заявка с сайта от ' . $name;
$body = "Имя: $namenТелефон: $phonenEmail: $emailnСообщение: $message";
$headers = "From: noreply@saitfix.rurnReply-To: $emailrnContent-Type: text/plain; charset=utf-8";
mail($to, $subject, $body, $headers);
mail() это базовая функция PHP. На большинстве хостингов работает без настройки. Если у вас настроен корпоративный SMTP (Yandex 360 или другой), лучше отправлять через PHPMailer с авторизацией для лучшей доставляемости.
Шаг 9: интеграция с CRM
Часто хочется не только Telegram и email, но и CRM. Добавляем третий вызов после двух предыдущих.
amoCRM
$amoUrl = 'https://your-domain.amocrm.ru/api/v4/leads';
$amoToken = 'BEARER_TOKEN_HERE';
$leadData = [
'name' => "Заявка от $name",
'pipeline_id' => 12345,
'_embedded' => [
'contacts' => [[
'name' => $name,
'custom_fields_values' => [
['field_id' => 678, 'values' => [['value' => $phone]]]
]
]]
]
];
$ch = curl_init($amoUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([$leadData]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $amoToken,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
Bitrix24
Через webhook:
$bitrixWebhook = 'https://your.bitrix24.ru/rest/1/SECRET_TOKEN/crm.lead.add';
$leadData = [
'fields' => [
'TITLE' => "Заявка от $name",
'NAME' => $name,
'PHONE' => [['VALUE' => $phone, 'VALUE_TYPE' => 'WORK']]
]
];
$ch = curl_init($bitrixWebhook);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($leadData));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
Webhook создаётся в Bitrix24 в Разработчикам > Другое > Входящий вебхук.
Чего не делать
1. Не хранить токен в коде на GitHub
Токен бота это полный контроль. Кто его получит, шлёт сообщения от вашего имени. Храните в .env или в private/config.php вне webroot и git.
2. Не доверять данным из формы
Любая входящая строка от пользователя должна валидироваться. Не вставляйте напрямую в URL, в SQL, в HTML без экранирования.
3. Не делать асинхронную отправку без проверки
Если PHP-обработчик не дождался ответа Telegram (например, упал в timeout), пользователь видит успех, а заявка не пришла. Лучше: отправить, дождаться ответа, и только потом ответить пользователю.
4. Не ставить очень короткий timeout
Если Telegram API задерживается, ваш CURLOPT_TIMEOUT = 3 может оборвать связь. Ставьте 10-15 секунд минимум.
5. Не игнорировать ошибки
Если Telegram вернул ошибку, нужно записать в лог, чтобы потом разобраться. Не просто echo error, а error_log() для администратора.

Чек-лист рабочей интеграции
- Бот создан через BotFather, токен сохранён.
- Получен chat_id целевого чата или канала.
- Тестовое сообщение через API доходит.
- PHP-обработчик валидирует поля.
- Honeypot и проверка времени установлены.
- Заявка отправляется в Telegram.
- Бэкап в CSV или email включён.
- При ошибке Telegram пользователь видит понятное сообщение.
- Токен и chat_id хранятся вне webroot и git.
- Ошибки логируются.
- Анти-спам тестировался реальной нагрузкой.
Когда стоит делегировать
Простая интеграция формы с Telegram это работа на 2-4 часа. С CRM и расширенным анти-спамом до 6-10 часов. Если форма с многими полями и сложной логикой, до 16 часов.
Эта работа входит в часовую ставку или в любой из тарифов на /#pricing. Если вам нужна форма с интеграцией Telegram плюс CRM, опишите ситуацию через /#contact. Связанные материалы про интеграции и формы в /blog/category/legal-and-integrations/.
Частые вопросы
Как настроить отправку заявок в Telegram
Создать бота через служебного бота платформы, получить токен, узнать chat_id нужного чата или канала, добавить в обработчик формы запрос к API с текстом заявки. Простая форма собирается за час-два.
Как узнать chat_id
Написать боту любое сообщение и запросить у API список обновлений: chat_id будет в ответе. Для канала бота сначала добавляют администратором, иначе он не сможет туда писать.
Как защитить форму от спама
Скрытым полем, которое человек не видит, и проверкой времени заполнения: отправка быстрее нескольких секунд почти наверняка бот. Связка убирает около 80 процентов мусора без капчи.
Стоит ли дублировать заявки на почту
Стоит. Telegram может быть недоступен, а сообщение легко пролистать. Почта остаётся архивом, по которому потом восстанавливают историю обращений.