Почему заявки из Telegram теряются, даже если менеджеры «всё видят»

Классическая картина: клиент пишет в Telegram-канал или боту, менеджер отвечает прямо в чате, сделка «как-то» движется — а в CRM по ней ничего нет. Через месяц никто не может сказать, сколько лидов пришло из Telegram, на каком шаге отвалились и кто именно их вёл. Вручную дублировать переписку в CRM никто не успевает: это лишняя рутина, которую физически невозможно делать без ошибок при сколько-нибудь заметном потоке обращений.

Технически задача решается одной связкой: Telegram отправляет вебхук → сервер-приёмник разбирает данные → CRM получает готовую сделку/контакт. Дальше — детали архитектуры, пошаговая реализация на n8n и вариант без no-code слоя, если нужен полный контроль над логикой.

Как устроена связка технически

Вебхук Telegram: что это и как работает

Bot API поддерживает два режима получения обновлений: long polling (бот сам стучится в Telegram и спрашивает «есть что новое?») и webhook (Telegram сам присылает POST-запрос на ваш URL при каждом новом событии). Для интеграции с CRM нужен именно webhook — это единственный вариант с доставкой в реальном времени без постоянного опроса.

Требования Telegram к принимающему серверу:

  • адрес обязательно на HTTPS, с валидным сертификатом (TLS 1.2+);
  • один из портов: 443, 80, 88 или 8443;
  • метод setWebhook регистрирует URL, пустая строка в параметре url — снимает вебхук;
  • полезно сразу передать secret_token — Telegram будет присылать его в заголовке X-Telegram-Bot-Api-Secret-Token, и вы сможете отбрасывать запросы без правильного токена;
  • у одного бота может быть только один активный вебхук — если используете n8n, платформу автоматизации или свой сервер параллельно, они конкурируют за этот единственный слот.

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

curl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.ru/webhook/telegram",
    "secret_token": "your-random-secret",
    "allowed_updates": ["message", "callback_query"]
  }'

Что попадает в CRM: лид, сделка, контакт

Прежде чем писать код, нужно решить модель данных на стороне CRM — от этого зависит, что конкретно вебхук должен извлечь из апдейта Telegram:

  • Контакт — telegram-username, имя из профиля, chat_id (обязательно сохраняйте — это единственный способ потом написать пользователю в ответ);
  • Лид/сделка — текст первого сообщения как описание, источник = «Telegram», привязка к каналу/боту, если их несколько;
  • История переписки — не всегда нужна в CRM целиком, но минимум последнее сообщение стоит подтягивать как комментарий к сделке.

Архитектура интеграции: три рабочих варианта

Вариант 1 — n8n как связующий слой (рекомендуется для большинства случаев)

n8n берёт на себя приём вебхука, парсинг, маппинг полей и вызов API CRM — без необходимости поднимать и поддерживать отдельный сервер. Дальше — рабочий сценарий.

Вариант 2 — собственный сервер-приёмник

Node.js/Express, FastAPI или любой другой стек, который сам принимает вебхук и обращается к API CRM. Оправдано, когда логика маппинга сложная (много условий, обогащение данных из сторонних источников, специфичная дедупликация) или когда n8n уже не вписывается в требования по инфраструктуре/безопасности.

Вариант 3 — встроенные интеграции CRM (если есть)

Некоторые CRM (например Bitrix24) имеют «открытые каналы» с готовым коннектором к Telegram без вебхуков вручную. Это быстрее внедрить, но менее гибко: кастомная логика маппинга полей, фильтрация спама, объединение нескольких ботов в одну воронку — обычно требует всё равно выйти за пределы коробочного коннектора.

Пошаговая настройка через n8n

Шаг 1. Создать бота и получить токен

Через @BotFather в Telegram: команда /newbot, задать имя и username, получить токен вида 123456789:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Токен — секрет уровня пароля от CRM, хранить только в n8n credentials, не в коде воркфлоу.

Шаг 2. Telegram Trigger в n8n

Нода Telegram Trigger при активации воркфлоу сама регистрирует вебхук в Telegram (вызывает setWebhook) на адрес, который выдаёт n8n. Ручной curl-запрос из раздела выше нужен только если вы делаете кастомный сервер вместо n8n — дублировать регистрацию для одного и того же бота нельзя, останется активным только последний вызов setWebhook.

В настройках триггера выбирайте конкретные типы обновлений (message, при необходимости callback_query для inline-кнопок) — это снижает шум и число лишних срабатываний сценария.

Шаг 3. Разобрать и нормализовать данные

Нода Set (или Code, если маппинг нетривиальный) приводит сырой апдейт Telegram к плоской структуре под CRM:

// Code node — нормализация входящего апдейта Telegram
const msg = $input.first().json.message;

return [{
  json: {
    chat_id: msg.chat.id,
    username: msg.from.username || null,
    first_name: msg.from.first_name || '',
    last_name: msg.from.last_name || '',
    text: msg.text || '',
    message_date: new Date(msg.date * 1000).toISOString(),
    source: 'telegram'
  }
}];

Шаг 4. Проверка на дубль

Без этого шага один активный клиент, который пишет несколько сообщений подряд, породит несколько «лидов» в CRM. Логика на основе chat_id: нода HTTP Request ищет в CRM существующий контакт/сделку по этому идентификатору (обычно поле хранится как «внешний ID» или кастомное поле), и дальше ветвление через IF — создавать новую сущность или дописывать комментарий к существующей.

Шаг 5. Запись в CRM

Дальше — либо готовый нод CRM в n8n (для Bitrix24, HubSpot, Pipedrive и части других систем есть нативные ноды), либо универсальный HTTP Request с вызовом REST API. Общий вид для двух популярных CRM:

Bitrix24 — через входящий вебхук (Настройки → Разработчикам → Другое → Входящий вебхук), без OAuth-приложения:

POST https://ваш-портал.bitrix24.ru/rest/USER_ID/WEBHOOK_KEY/crm.lead.add.json

{
  "fields": {
    "TITLE": "Обращение из Telegram",
    "NAME": "{{ $json.first_name }}",
    "SOURCE_ID": "OTHER",
    "COMMENTS": "{{ $json.text }}",
    "UF_CRM_TELEGRAM_CHAT_ID": "{{ $json.chat_id }}"
  }
}

amoCRM — через REST API v4 с OAuth2-токеном интеграции:

POST https://ваш-домен.amocrm.ru/api/v4/leads
Authorization: Bearer {{ access_token }}

[
  {
    "name": "Обращение из Telegram",
    "custom_fields_values": [
      {
        "field_code": "TELEGRAM_CHAT_ID",
        "values": [{ "value": "{{ $json.chat_id }}" }]
      }
    ]
  }
]

Названия кастомных полей и точные ID полей всегда свои для каждого аккаунта — их нужно получить через соответствующий метод API (список полей сделки) при настройке, а не угадывать по документации.

Шаг 6. Обратная связь клиенту (опционально, но обычно нужно)

После записи в CRM полезно сразу же сообщить в Telegram, что обращение принято: нода Telegram → sendMessage с chat_id из шага 3. Это снимает часть нагрузки с менеджеров и снижает число повторных сообщений «ну что там».

Вариант без n8n: свой webhook-сервер

Минимальный обработчик на Node.js/Express, если нужен полный контроль или n8n не вписывается в инфраструктуру:

import express from 'express';
const app = express();
app.use(express.json());

const SECRET_TOKEN = process.env.TELEGRAM_SECRET_TOKEN;

app.post('/webhook/telegram', async (req, res) => {
  // Проверка, что запрос действительно от Telegram
  if (req.header('X-Telegram-Bot-Api-Secret-Token') !== SECRET_TOKEN) {
    return res.sendStatus(401);
  }

  const update = req.body;
  const msg = update.message;
  if (!msg) return res.sendStatus(200); // не все апдейты — сообщения

  await createOrUpdateCrmLead({
    chatId: msg.chat.id,
    username: msg.from.username,
    text: msg.text,
  });

  // Telegram ждёт быстрый 200 OK, тяжёлую логику лучше выносить в очередь
  res.sendStatus(200);
});

app.listen(3000);

Важно: Telegram ждёт ответ в течение нескольких секунд, иначе повторяет отправку апдейта. Долгую логику (запрос к CRM, обогащение данных) стоит выносить в очередь (BullMQ, RabbitMQ и т.п.), а на сам вебхук отвечать 200 сразу после валидации.

Частые ошибки при внедрении

  • Забыли secret_token — вебхук принимает вообще любой POST-запрос на нужный URL, а не только от Telegram. Это открытая дверь для спама и подделки лидов.
  • Нет дедупликации по chat_id — один диалог превращается в десяток сделок в CRM.
  • Два вебхука на одного бота — например, тестовый n8n-воркфлоу и продовый сервер одновременно пытаются вызвать setWebhook. Активным остаётся только последний, второй молча перестаёт получать апдейты.
  • Синхронная тяжёлая обработка — если сервер отвечает Telegram дольше нескольких секунд, апдейты начинают дублироваться повторной отправкой.
  • Игнорирование лимитов CRM API — при всплеске сообщений (рассылка, вирусный пост) можно упереться в rate limit CRM; нужна очередь с ретраями, а не прямой синхронный вызов из вебхука.
  • Хранение токена бота и ключей CRM в коде воркфлоу — только через credentials/секрет-хранилище.

Безопасность: как не превратить вебхук в дыру

  • Всегда проверяйте заголовок X-Telegram-Bot-Api-Secret-Token на бэкенде, если делаете свой сервер;
  • ограничивайте доступ к webhook-эндпоинту по IP, если это возможно (список подсетей Telegram публикуется в документации Bot API и может меняться — фильтрацию по IP стоит держать как дополнительный, а не единственный слой защиты);
  • логируйте все входящие вебхуки отдельно от бизнес-логики — это единственный способ быстро разобраться, что произошло, если лид «пропал»;
  • для CRM с исходящими вебхуками (события «сделка изменена» и т.п.) в обратную сторону — проверяйте подпись/токен, который CRM присылает, аналогично Telegram.

Чек-лист внедрения

  • Бот создан через BotFather, токен сохранён в secrets/credentials;
  • Определена модель данных: что в CRM = лид, что = контакт, где хранится chat_id;
  • Вебхук зарегистрирован с secret_token и ограниченным списком allowed_updates;
  • Реализована дедупликация по chat_id перед созданием сущности в CRM;
  • Настроен маппинг кастомных полей CRM (ID полей получены из API, а не угаданы);
  • Есть быстрый ответ 200 на вебхук, тяжёлая логика — асинхронно/через очередь;
  • Настроена обратная связь клиенту в Telegram после обработки;
  • Проверены лимиты API CRM и поведение при их превышении (retry-логика);
  • Логирование входящих вебхуков включено отдельно от бизнес-логики.

Частые вопросы (FAQ)

Можно ли подключить несколько Telegram-каналов/ботов к одной CRM?

Да. Каждый бот регистрирует собственный вебхук на свой URL (или на общий URL с параметром, идентифицирующим бота). В n8n это либо отдельные воркфлоу с разными Telegram Trigger, либо один воркфлоу с веткой по bot_id из URL вебхука.

Нужен ли отдельный сервер, если вся автоматизация уже строится в n8n?

Обычно нет — n8n сам поднимает HTTPS-эндпоинт для Telegram Trigger. Отдельный сервер имеет смысл только при нестандартных требованиях к инфраструктуре (изоляция, комплаенс) или очень сложной кастомной логике, которую неудобно вести в визуальном редакторе.

Что делать, если CRM не поддерживает вебхуки/REST API?

Такие системы редки среди современных облачных CRM, но если это так — остаётся RPA-подход (эмуляция действий в интерфейсе) или экспорт/импорт по расписанию через файлы/базу данных. Оба варианта менее надёжны и требуют дополнительного мониторинга.

Как обрабатывать голосовые сообщения, фото и файлы из Telegram, а не только текст?

В апдейте будут поля voice, photo, document вместо text. Файл в Telegram скачивается отдельным вызовом (getFile → получить временную ссылку → скачать), после чего можно приложить его к сделке в CRM через API загрузки файлов конкретной системы.

Безопасно ли пропускать вебхук Telegram напрямую в API CRM без промежуточного слоя?

Технически возможно, но не рекомендуется: пропадает точка для дедупликации, валидации и логирования, а формат данных Telegram и формат полей CRM почти никогда не совпадают один в один. Промежуточный слой (n8n или свой сервер) — это не лишняя сложность, а обязательный слой трансформации и защиты.