Как подключить Telegram-бота к CRM и формам: базовая схема передачи лидов без сайта

Реклама может вести сразу в Telegram-бота: человек выбирает услугу, оставляет контакт и подтверждает отправку заявки. Менеджер при этом получает карточку в CRM, а не ищет нужный диалог среди сообщений. Отдельная посадочная страница для такого маршрута не обязательна. Однако «без сайта» не означает «без серверной части»: кто-то должен принимать события бота, хранить состояние разговора и обращаться к CRM.
Разберём авторскую схему для небольшой команды, которая продаёт консультации. В качестве CRM возьмём Битрикс24 и создадим лид через универсальный crm.item.add с entityTypeId=1. Лид здесь — входящее обращение; создание лида само по себе не создаёт сделку и не подтверждает продажу. Переход к сделке команда настраивает отдельно.
Что связывает бот и CRM
Прямого перехода «любое сообщение — новая карточка» лучше избегать: приветствие, исправление имени и повторное нажатие кнопки превратятся в разные лиды. Между Telegram и CRM предусмотрим небольшой интеграционный сервис с хранилищем и очередью. Он собирает одну законченную заявку и только после подтверждения передаёт её дальше.
| Участок | Ответственность в нашей схеме |
|---|---|
| Бот | Вопросы, кнопки, показ собранных данных и сообщение о результате |
| HTTPS-приёмник | Проверка входящего события и надёжная запись в очередь |
| Обработчик | Состояние диалога, проверка полей, предотвращение повторной обработки |
| CRM | Карточка лида, ответственный менеджер и дальнейшая работа |
| Журнал интеграции | Связь заявки с событиями и идентификатором созданного лида |
Если нужен только ответ оператора в чате, подобная связка может оказаться избыточной. Она полезна, когда важно распределять обращения, видеть незавершённые запросы и сверять количество подтверждённых заявок с CRM. Выбор здесь зависит от рабочего процесса, а не от наличия красивой кнопки.
Маршрут человека: от ссылки до подтверждения
Для учебной кампании используем ссылку https://t.me/your_bot?start=consult_demo. В личном чате deep link передаёт параметр start; документация Telegram допускает буквы A–Z и a–z, цифры, подчёркивание и дефис, длину до 64 символов. Это удобная метка кампании, но не надёжное удостоверение личности. Не помещайте в неё пароль, телефон или секрет интеграции.
Наш бот предлагает выбрать «Первая консультация» или «Повторное обращение», затем спрашивает имя и удобный контакт. Кнопка клавиатуры с request_contact позволяет отправить номер пользователя и доступна в личном чате. Альтернатива — вручную введённый контакт. Не считайте произвольный текст телефона доказательством владения номером.
Далее бот показывает итог: «Услуга: первая консультация. Имя: Анна. Контакт: указанный вами номер. Заявка будет передана менеджеру компании N». Кнопки «Изменить» и «Отправить заявку» завершают понятный человеку сценарий. В нашей реализации обработчик сохраняет факт подтверждения и версию показанного текста. Это проектирование интерфейса, а не утверждение, что такое нажатие автоматически выполняет все юридические требования к обработке данных.
Для inline-кнопки можно передать короткий callback_data, например submit:lead17. Bot API ограничивает это поле 1–64 байтами. Полную заявку храните на сервере, а по короткому ключу находите её состояние. На callback отвечайте методом answerCallbackQuery; отдельно проверяйте, что именно этот пользователь подтверждает свою ещё не отправленную заявку. Кнопка сама по себе не заменяет проверку состояния.
Два разных webhook
В Telegram метод setWebhook задаёт HTTPS-адрес, на который платформа отправляет POST с JSON-объектом Update. При неуспешном ответе, то есть статусе вне 2XY, доставка повторяется ограниченное число раз. Параметр secret_token позволяет получить специальный заголовок X-Telegram-Bot-Api-Secret-Token. Наш приёмник должен проверять его перед разбором заявки, а секрет хранить в серверной конфигурации.
Webhook Telegram — входящее событие. Авторизационный адрес REST-интеграции CRM — другой секрет и другой участок маршрута. Не вставляйте CRM-адрес с ключом в сообщение бота, клиентскую форму, скриншот или публичный репозиторий. Сервис обращается к CRM от своего имени с предусмотренными для интеграции правами.
После проверки и надёжной записи события приёмник может вернуть успешный HTTP-ответ, а дальнейшую работу выполнить из очереди. Если ответить успехом до сохранения, сбой процесса способен потерять заявку; если ждать CRM внутри каждого webhook, её задержки будут мешать приёму новых событий. Это выбранная нами архитектура, а не требование использовать конкретную очередь или облачный продукт.
Поля: переводим разговор в карточку
Перед интеграцией запросите crm.item.fields с entityTypeId=1 на своём портале: метод описывает поля и их конфигурацию. Не переносите вслепую набор из чужого примера: у вашей команды могут быть собственные поля и условия. В минимальном учебном запросе отделим имя от названия обращения, а источник сохраним в комментарии.
{
"entityTypeId": 1,
"fields": {
"title": "Консультация: заявка из Telegram",
"name": "Анна",
"comments": "Учебный пример; услуга: первая консультация; кампания: consult_demo; внутренний ключ: lead17"
}
}
Такое тело предназначено для crm.item.add после настройки авторизации и проверки полей конкретного портала. Для телефона универсальный API использует мультиполе fm: массив с typeId, valueType и value. Например, {"typeId":"PHONE","valueType":"WORK","value":"555888"} внутри массива fm. Число здесь демонстрационное: его не отправляют как настоящий контакт.
В старых инструкциях встречаются crm.lead.add, crm.lead.fields и поля TITLE/PHONE. Оба специализированных метода в документации помечены DEPRECATED: их развитие остановлено, рекомендованы crm.item.add и crm.item.fields. Не смешивайте прежний формат PHONE с новым fm. Пример выше использует универсальный API и строчные имена стандартных полей.
Сохраните идентификатор result.item.id из успешного результата crm.item.add рядом с внутренним ключом заявки. Сообщение «Заявка передана» отправляйте после подтверждённого результата, а при записи только в очередь говорите точнее: «Заявка принята в обработку». Пользовательские данные не должны превращаться в бесконтрольную копию всего диалога внутри COMMENTS.
Почему одной проверки телефона недостаточно
Дубликат события и повторное обращение человека — разные вещи. Update содержит update_id, уникальный идентификатор обновления. В нашем журнале сочетание идентификатора бота и update_id имеет уникальное ограничение: повтор доставки того же события не запускает обработку заново.
У законченной заявки есть отдельный внутренний ключ lead17. Повторное нажатие «Отправить» проверяет её состояние: уже созданному лиду соответствует сохранённый CRM ID. Но новая консультация того же человека не обязана исчезать только потому, что телефон уже встречался. Правило объединения контактов и обращений согласуйте с работой менеджеров.
Особенно важен неоднозначный сбой: CRM могла создать лид, но ответ потерялся по дороге. Слепой повтор crm.item.add способен создать вторую карточку. В нашей схеме такое задание получает состояние «результат неизвестен» и идёт на сверку. Можно разработать поиск по отдельному внешнему ключу в настроенном поле, но наличие этого поля и способ поиска нужно реализовать и проверить отдельно. Мы не предполагаем, что CRM автоматически обеспечивает идемпотентность любого запроса.
Если заявку присылает форма
Ту же очередь можно использовать для формы в другом сервисе. Добавьте адаптер, который проверяет предусмотренную поставщиком авторизацию webhook и переводит его поля во внутренний формат: ключ события, источник, имя, контакт, услуга и подтверждение пользователя. Схема Telegram Update к сторонней форме не применяется.
Например, условный поставщик прислал событие {"event_id":"form-28","full_name":"Анна","service":"consult","contact":"указанный контакт"}. Это наш учебный формат, а не стандарт всех форм. Адаптер создаёт внутренний ключ события form:provider_a:form-28, записывает name из full_name, выбранную услугу из service и источник form/provider_a. После проверки контакта и подтверждения обработчик собирает те же поля title, name, comments и при необходимости fm. Для другого поставщика названия полей и способ проверки подлинности будут другими.
Что ломается до появления карточки
| Симптом | Что проверяем |
|---|---|
| Telegram не доставляет события | HTTPS-адрес приёмника, ответы сервера и getWebhookInfo; неверный secret token не принимаем как доверенное событие |
| Кнопка нажата, но заявка не движется | Обработку callback, answerCallbackQuery и состояние подтверждения в журнале |
| CRM вернула INVALID_CREDENTIALS | Активность и корректность webhook-учётных данных; не создаём новую заявку вместо исправления доступа |
| ACCESS_DENIED или insufficient_scope | Права пользователя интеграции и доступный scope crm |
| expired_token | Срок действия OAuth access-токена и штатный механизм его обновления; не путать с секретом входящего webhook |
| QUERY_LIMIT_EXCEEDED | Ограничение интенсивности запросов; управляем очередь и повтор по правилам API, не отправляем бесконечный цикл |
| Ошибка значения или обязательного поля | Метаданные своего портала, типы и поля, обязательные для выбранной стадии |
Договоритесь, что делать с пустым контактом, неизвестной услугой и повторным событием формы. Лучше явно отклонить некорректное задание и показать причину оператору, чем создать внешне успешную карточку без данных для связи. В журнале оставляйте технические идентификаторы и необходимую диагностику; доступ и сроки хранения персональных сведений определяйте отдельно.
Приёмка: сверяем не только красивое сообщение
На тестовом боте и тестовой CRM пройдите маршрут целиком: ссылка кампании → вопросы → исправление контакта → подтверждение → один лид с правильными полями. Затем повторно доставьте то же событие, дважды нажмите отправку, смоделируйте отказ CRM и неизвестный результат после таймаута. Проверьте не только экран пользователя, но и очередь, журнал и количество карточек.
Эти испытания здесь предложены как план приёмки, а не как отчёт о подключении реального портала. Готовая интеграция должна позволять ответить на конкретный вопрос: «Куда делась заявка lead17?» Если видны время приёма, состояние обработки, причина сбоя и CRM ID, проблему можно исправить без повторного расспроса клиента.




