Перейти к содержанию
Innovialabs

Как отправлять заявки с сайта в Telegram

Практика4 мин

Коротко

Форма отправляет данные на ваш сервер, сервер проверяет их, сохраняет заявку и вызывает sendMessage Bot API с токеном из переменных окружения; при ошибке повторяет отправку, а заявка остаётся в базе и не теряется.

Короткий ответ

Правильная схема выглядит так:

браузер → ваш серверный обработчик → база или лог → Bot API sendMessage → чат или группа.

Токен бота хранится только на сервере. Если вызывать Bot API прямо из JavaScript на странице, токен увидит любой посетитель во вкладке «Сеть» и сможет писать от имени бота, засыпать спамом вашу группу или перехватить управление ботом.

Шаг 1. Бот и чат для заявок

  1. Создайте бота в BotFather и сохраните токен.
  2. Создайте группу для заявок и добавьте в неё бота. Для отправки сообщений права администратора не нужны.
  3. Узнайте chat_id: отправьте в группу сообщение с упоминанием бота, например /start@your_bot, и откройте https://api.telegram.org/bot<ТОКЕН>/getUpdates. В ответе найдите chat.id.

Что важно знать про chat_id:

  • у групп он отрицательный, у супергрупп начинается с -100;
  • если группа превратилась в супергруппу, ID меняется — Bot API вернёт ошибку с полем migrate_to_chat_id;
  • getUpdates не работает, если у бота настроен вебхук;
  • чтобы получать заявки в личку, нужно сначала самому запустить бота — без этого он не сможет вам написать.

Шаг 2. Переменные окружения

TELEGRAM_BOT_TOKEN=123456789:replace-with-your-token
TELEGRAM_CHAT_ID=-1001234567890

Не добавляйте к этим переменным префиксы, которые делают их доступными в браузере, например NEXT_PUBLIC_ в Next.js. Файл .env не должен попадать в репозиторий.

Шаг 3. Серверный обработчик

Пример route handler для Next.js. Та же логика переносится на любой бэкенд.

// app/api/lead/route.ts
const API = `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`;

const esc = (s: string) =>
  s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

async function notifyTelegram(text: string): Promise<boolean> {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      const res = await fetch(API, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ chat_id: process.env.TELEGRAM_CHAT_ID, text, parse_mode: "HTML" }),
        signal: AbortSignal.timeout(5000),
      });
      if (res.ok) return true;
      const data = await res.json().catch(() => ({}));
      if (res.status !== 429 && res.status < 500) {
        console.error("Telegram rejected lead", res.status, data.description);
        return false; // ошибка настройки: повтор не поможет
      }
      const wait = data.parameters?.retry_after ?? 2 ** attempt;
      await new Promise((r) => setTimeout(r, wait * 1000));
    } catch {
      // таймаут или сеть: пробуем ещё раз
    }
  }
  return false;
}

export async function POST(req: Request) {
  const body = await req.json().catch(() => null);
  if (!body) return Response.json({ ok: false }, { status: 400 });
  if (body.website) return Response.json({ ok: true }); // honeypot: тихо игнорируем спам-бота

  const name = String(body.name ?? "").trim().slice(0, 100);
  const phone = String(body.phone ?? "").trim().slice(0, 30);
  if (!name || !phone) return Response.json({ ok: false }, { status: 400 });

  const lead = await saveLead({ name, phone }); // сначала сохраняем заявку
  const text = `<b>Новая заявка #${lead.id}</b>\nИмя: ${esc(name)}\nТелефон: ${esc(phone)}`;
  if (!(await notifyTelegram(text))) await markForRetry(lead.id);

  return Response.json({ ok: true });
}

saveLead и markForRetry — ваши функции работы с базой.

Шаг 4. Обработка сбоев

Telegram — канал уведомлений, а не хранилище заявок. Поэтому:

  • сначала сохраняйте заявку в базу или хотя бы в лог, потом отправляйте уведомление;
  • ставьте таймаут на запрос к Bot API, чтобы форма не зависала;
  • повторяйте только при 429 (ждите retry_after) и ошибках 5xx, с ограниченным числом попыток;
  • не повторяйте при 400 и 403: это неверный chat_id, бот удалён из группы или ошибка разметки — нужен алерт, а не повтор;
  • дублируйте канал для неотправленных заявок: фоновая очередь повторов или письмо на email;
  • отвечайте пользователю успехом, когда заявка сохранена, а не когда дошло уведомление.

В serverless-окружении долгие ожидания внутри запроса нежелательны, поэтому повторы лучше переносить в фоновую задачу.

Защита от спама и ошибок разметки

  • экранируйте &, < и > при parse_mode: "HTML" — иначе символ в имени сломает сообщение;
  • ограничивайте длину полей: у сообщения в Telegram есть лимит длины;
  • добавьте скрытое поле-ловушку (honeypot) и ограничение частоты запросов по IP;
  • валидируйте данные на сервере, даже если они уже проверены в браузере.

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

Можно, если вы запустили бота и указали свой ID как chat_id. Но группа удобнее для команды: заявки видят все менеджеры, и их можно обсуждать в ответах.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.