Legan Studio
Все статьи
~ 14 мин чтения

Telegram-бот + CRM: какие интеграции выбрать

Сравниваем интеграции Telegram-бота с amoCRM, Битрикс24, RetailCRM и кастомными CRM. Что выбрать под разные сценарии и сколько это стоит.

  • Telegram
  • CRM
  • интеграции
  • автоматизация

CRM-интеграция — то, что отличает «бот, собирающий заявки в чат» от системного канала продаж. Если лиды и заказы из Telegram не попадают в CRM, отдел продаж работает вслепую: менеджер забывает перезвонить, маркетинг не видит реальную конверсию по UTM, а руководитель не понимает, какой канал окупается. Разберём, какие варианты интеграций есть в России и за рубежом, какие сценарии реально приносят деньги, где грабли и сколько это стоит.

Зачем вообще интегрировать бота с CRM

Начнём с очевидного, но не всегда проговариваемого. Польза от связки бот + CRM сводится к пяти вещам.

  • Единая база лидов. Все обращения — из бота, с сайта, с email-рассылок, из звонков — в одной точке. Менеджер не открывает шесть вкладок, чтобы понять, кто этот человек.
  • Авто-распределение. Лид попал в CRM — система сама присвоила ответственного по правилам (по региону, продукту, нагрузке менеджеров). Никто вручную не «расхватывает» заявки.
  • История коммуникаций. В карточке клиента видно, что он спрашивал в боте полгода назад, какую услугу выбирал, какие возражения снимал менеджер. Передача между сотрудниками не теряет контекст.
  • Сквозная аналитика. UTM-метка из бота тянется в сделку, сделка — в выручку. Видно, какой источник трафика реально продаёт, а не только генерирует лиды.
  • Меньше ручной работы. Менеджеру не нужно копировать телефон, имя, текст обращения из чата в карточку. Автоматика делает это за миллисекунды и без опечаток.

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

Базовые сценарии автоматизации

Минимальный набор того, ради чего это всё затевается:

  1. Новый лид → создать сделку. Пользователь оставил заявку в боте — в CRM появилась сделка с контактом, источником, UTM, ответственным.
  2. Ответ клиента в боте → обновить статус. Клиент нажал «Готов обсуждать» — сделка двинулась по воронке. Ушёл в молчание на 3 дня — задача менеджеру «реактивировать».
  3. Сделка закрыта → отправить NPS. Через 7 дней после статуса «Оплачено» бот сам спрашивает: «Оцените от 1 до 10». Ответы складываются в кастом-поле сделки.
  4. Забытый лид → реактивация через бота. Сделка висит без активности 14 дней — CRM шлёт webhook, бот мягко напоминает клиенту: «Остались вопросы?».
  5. Эскалация на оператора. Бот не понял — ставит задачу менеджеру в CRM с прямой ссылкой на чат.
  6. Уведомления менеджеру. Новая горячая сделка — менеджер получает в личный Telegram сообщение от служебного бота с кнопкой «Открыть в CRM».

Каждый сценарий по отдельности экономит 1–3 минуты на лиде. На потоке в 200 лидов в месяц это уже 5–10 часов рабочего времени.

Российские CRM: краткий обзор

Рынок РФ в 2026 году достаточно консолидированный — большинство задач закрывают 4–5 систем.

amoCRM — самый популярный выбор для услуг и B2C. REST API на OAuth 2.0, понятная документация, цифровая воронка с автоматизацией, виджеты в карточке, встроенный мессенджер-канал (можно завести бот как источник). Лимит — 7 запросов в секунду на аккаунт.

Битрикс24 — тяжеловес для B2B и крупных компаний. REST + входящие/исходящие webhooks, OpenLine как канал для чатов, мощные права и БП, but порог входа высокий. Лимиты гибкие, зависят от тарифа.

Мегаплан — нишевый, но живой. Удобен в проектных продажах. REST API, webhooks по событиям. Менее активное комьюнити по сравнению с amoCRM/Битриксом.

RetailCRM — стандарт для интернет-магазинов и retail. Интеграции с 1С, эквайрингами, маркетплейсами. Бот тут создаёт не сделку, а заказ напрямую с составом корзины и параметрами доставки.

AmoTeam, Rocket — нишевые CRM для отделов продаж SaaS-продуктов. Хорошо подходят, когда нужна нестандартная воронка с длинным циклом и множеством касаний.

Зарубежные CRM: коротко

Если у клиента глобальный бизнес или legacy-инфраструктура на западных решениях:

  • HubSpot — мощный free-tier, REST API, webhooks, удобные workflows. Часто выбирают B2B SaaS.
  • Salesforce — корпоративный стандарт, REST + Bulk API, но интеграция дорогая и долгая (нужен сертифицированный партнёр).
  • Pipedrive — простая sales-pipeline CRM, REST, webhooks, дёшево и быстро поднимается.
  • Zoho CRM — недорогой комбайн, REST API, OAuth 2.0, поддержка кастом-полей и кастомных модулей.

Принципиально код интеграции Telegram-бота не меняется — отличаются только эндпоинты, схема авторизации и формат полей. Большинство решений умеют webhook'и, что критично для двусторонней синхронизации.

Сравнительная таблица

CRMAuthRate limitsWebhooksСтоимость интеграции
amoCRMOAuth 2.07 RPSВходящие + исходящие50–150 тыс ₽
Битрикс24OAuth 2.0 / вебхук-токен2 RPS на методВходящие + исходящие80–250 тыс ₽
МегапланAPI key10 RPSТолько входящие в МП60–180 тыс ₽
RetailCRMAPI key300/минТриггеры + webhooks80–200 тыс ₽
HubSpotOAuth 2.0 / API key100/10 секВходящие + workflows100–300 тыс ₽
SalesforceOAuth 2.015 000/24 ч (Enterprise)Platform Eventsот 300 тыс ₽
PipedriveAPI token / OAuth100/10 секВходящие50–150 тыс ₽
ZohoOAuth 2.0100/минВходящие60–180 тыс ₽

Цифры — ориентир для типового проекта «создание сделки + двусторонняя синхронизация статусов + UTM». Глубокая интеграция с кастомными воронками и виджетами в UI обычно дороже на 50–100%.

amoCRM: примеры кода

Самый частый стек у нас — Python + httpx. Создание контакта и сделки в amoCRM выглядит так:

import httpx

AMO_BASE = "https://example.amocrm.ru/api/v4"
HEADERS = {"Authorization": f"Bearer {ACCESS_TOKEN}"}

async def create_lead_amo(client: httpx.AsyncClient, lead: dict) -> int:
    # 1. Создаём контакт
    contact_payload = [{
        "name": lead["name"],
        "custom_fields_values": [
            {"field_code": "PHONE", "values": [{"value": lead["phone"], "enum_code": "MOB"}]},
            {"field_code": "EMAIL", "values": [{"value": lead["email"], "enum_code": "WORK"}]},
        ],
    }]
    r = await client.post(f"{AMO_BASE}/contacts", json=contact_payload, headers=HEADERS)
    r.raise_for_status()
    contact_id = r.json()["_embedded"]["contacts"][0]["id"]

    # 2. Создаём сделку с привязкой к контакту, тегами, UTM в кастом-поле
    deal_payload = [{
        "name": f"Заявка из Telegram: {lead['name']}",
        "price": lead.get("budget", 0),
        "pipeline_id": 1234567,
        "status_id": 7654321,            # «Первичный контакт»
        "responsible_user_id": 111,      # Авто-распределение по правилу
        "_embedded": {
            "contacts": [{"id": contact_id}],
            "tags": [{"name": "telegram_bot"}, {"name": lead["utm_source"]}],
        },
        "custom_fields_values": [
            {"field_id": 555001, "values": [{"value": lead["utm_source"]}]},
            {"field_id": 555002, "values": [{"value": lead["utm_campaign"]}]},
            {"field_id": 555003, "values": [{"value": str(lead["tg_user_id"])}]},
        ],
    }]
    r = await client.post(f"{AMO_BASE}/leads", json=deal_payload, headers=HEADERS)
    r.raise_for_status()
    return r.json()["_embedded"]["leads"][0]["id"]

Обратите внимание на field_code vs field_id: код используется для системных полей (PHONE, EMAIL), а ID — для кастомных. ID берутся из настроек аккаунта /api/v4/leads/custom_fields.

Битрикс24: REST и OpenLine

Битрикс попроще для старта — есть «входящий вебхук» (статичный URL с токеном), который не требует OAuth-флоу:

import httpx

BX_HOOK = "https://example.bitrix24.ru/rest/1/abc123def456/"

async def create_deal_bx(client: httpx.AsyncClient, lead: dict) -> int:
    # Сначала ищем контакт по телефону
    r = await client.post(f"{BX_HOOK}crm.contact.list", json={
        "filter": {"PHONE": lead["phone"]},
        "select": ["ID"],
    })
    contacts = r.json().get("result", [])
    contact_id = contacts[0]["ID"] if contacts else None

    if not contact_id:
        r = await client.post(f"{BX_HOOK}crm.contact.add", json={
            "fields": {
                "NAME": lead["name"],
                "PHONE": [{"VALUE": lead["phone"], "VALUE_TYPE": "MOBILE"}],
                "SOURCE_ID": "TELEGRAM",
            },
        })
        contact_id = r.json()["result"]

    r = await client.post(f"{BX_HOOK}crm.deal.add", json={
        "fields": {
            "TITLE": f"Telegram: {lead['name']}",
            "CONTACT_ID": contact_id,
            "CATEGORY_ID": 0,
            "STAGE_ID": "NEW",
            "ASSIGNED_BY_ID": lead.get("manager_id", 1),
            "UF_CRM_TG_USER_ID": str(lead["tg_user_id"]),
            "UF_CRM_UTM_SOURCE": lead.get("utm_source", ""),
        },
    })
    return r.json()["result"]

OpenLine («Открытые линии») — отдельная история. Это канал, через который сообщения из бота попадают в чат-карточку клиента в Битриксе, а ответы менеджера автоматически уходят клиенту обратно в Telegram. Подключение делается через REST-методы imopenlines.network.join + imconnector.activate. Это путь для двусторонней переписки без написания собственного middleware.

Двусторонняя синхронизация (OL)

Самое ценное — когда клиент пишет боту, а менеджер видит сообщение в карточке CRM и отвечает оттуда же. Архитектурно есть два пути.

  1. Через готовый канал (amoCRM Chat API, Битрикс OpenLine). CRM сама держит UI чата, бот выступает «коннектором»: получает сообщения из CRM по webhook и шлёт в Telegram, и наоборот.
  2. Через свой middleware. Бот пишет историю сообщений в собственную БД, в карточку CRM кладёт только ссылку «Открыть переписку». Менеджер кликает — открывается мини-веб-интерфейс с чатом. Гибче, но дороже в разработке.

Первый путь подходит, когда команда уже живёт в CRM и не хочет лишних инструментов. Второй — когда нужна нестандартная UX (шаблоны, быстрые ответы, AI-suggest, метки настроения клиента).

Идентификация клиента

Главный вопрос: как связать tg user_id с контактом в CRM? У клиента может не быть телефона в профиле Telegram, а может быть несколько аккаунтов (личный и рабочий). Стратегии в порядке убывания надёжности:

  • По верифицированному телефону. Бот просит поделиться контактом через request_contact — Telegram возвращает номер, привязанный к аккаунту. Этому номеру можно доверять.
  • По email. Менее надёжно — клиент может ввести чужой. Полезно, если CRM первична для email-маркетинга.
  • По кастом-полю tg_user_id. Сохраняем ID Telegram-пользователя в отдельное поле контакта при первом обращении. На повторных обращениях находим клиента за один запрос.
  • По deeplink с параметром. В рассылке менеджер шлёт ссылку t.me/yourbot?start=lead_12345 — бот при /start понимает, что это лид №12345 из CRM, и сразу его идентифицирует.

Хорошая практика — комбинировать. При первом контакте просим телефон, сохраняем tg_user_id в кастом-поле, дальше работаем по нему.

Безопасность токенов и доступов

CRM-токен с правами на запись — это ключ от всей базы клиентов. Утечка = катастрофа.

  • Только в env (.env, secrets manager, Vault). Никогда в репозиторий.
  • Регулярная ротация — раз в 90 дней меняем токены, OAuth refresh обновляем по расписанию.
  • Минимальные scopes. В amoCRM/Битриксе можно создать вебхук с правами только на нужные методы — не давайте полный доступ, если нужен только crm.deal.add.
  • IP-allowlist на стороне CRM, если поддерживается. Битрикс это умеет.
  • Аудит-лог. Все запросы к CRM логируем со стороны бота — кто, когда, что записал. При компрометации можно понять масштаб.

Очередь интеграций для надёжности

CRM может упасть, провести регламентные работы, получить таймаут на 30 секунд — а лиды поступать продолжают. Если бот пишет в CRM напрямую и синхронно — потеря лидов гарантирована.

Решение — брокер сообщений между ботом и CRM-коннектором:

# Producer: бот при получении заявки кладёт её в очередь
async def on_lead_received(lead: dict):
    await rabbitmq.publish(
        exchange="crm",
        routing_key="lead.new",
        body=json.dumps(lead).encode(),
        headers={"x-retry-count": "0"},
    )

# Consumer: отдельный воркер достаёт и шлёт в CRM
async def consume_leads():
    async for msg in rabbitmq.consume("crm.lead.new"):
        try:
            await create_lead_amo(http_client, json.loads(msg.body))
            await msg.ack()
        except RetryableError as e:
            await retry_or_dlq(msg, e)

Подходит RabbitMQ, NATS, Redis Streams. Главное — два требования: персистентность (сообщения переживают рестарт брокера) и подтверждение доставки (ack только после успешной записи в CRM).

Webhook от CRM в Telegram

Обратное направление: CRM сообщает боту о событиях. Битрикс шлёт POST на наш эндпоинт при изменении сделки:

from fastapi import FastAPI, Request, HTTPException
import hmac, hashlib

app = FastAPI()

@app.post("/webhook/bx/deal-update")
async def bx_deal_update(request: Request):
    # 1. Проверяем подпись (если включена)
    body = await request.body()
    signature = request.headers.get("X-Bitrix-Signature", "")
    expected = hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(signature, expected):
        raise HTTPException(403, "bad signature")

    payload = await request.form()
    event = payload.get("event")
    deal_id = payload.get("data[FIELDS][ID]")

    if event == "ONCRMDEALUPDATE":
        deal = await fetch_deal(deal_id)
        tg_user_id = deal.get("UF_CRM_TG_USER_ID")
        new_stage = deal["STAGE_ID"]

        # 2. Уведомляем клиента в боте о смене статуса
        if tg_user_id and new_stage in NOTIFY_STAGES:
            await tg_bot.send_message(
                int(tg_user_id),
                STAGE_TEMPLATES[new_stage].format(deal_id=deal_id),
            )

        # 3. Уведомляем ответственного менеджера в служебном боте
        manager_tg = await get_manager_tg(deal["ASSIGNED_BY_ID"])
        if manager_tg:
            await staff_bot.send_message(
                manager_tg,
                f"Сделка #{deal_id} перешла в «{new_stage}»",
            )
    return {"ok": True}

Сценарии «менеджеру в личный Telegram» особенно ценят руководители — не нужно держать вкладку с CRM открытой весь день.

Обработка ошибок и ретраи

API любой CRM иногда отвечает плохо. Шаблон обработки:

  • 401/403 — токен протух или прав не хватает. Останавливаем воркер, шлём алерт DevOps. Ретраить бессмысленно.
  • 404 — объект удалён в CRM. Помечаем сообщение как «не доставлено», в DLQ. Часто это нормально (клиент удалил тестовую сделку).
  • 429 — превысили rate limit. Ретраим с exponential backoff и Jitter, уважаем Retry-After если есть.
  • 5xx — временная проблема CRM. Ретраим 3–5 раз с backoff, потом в DLQ.
  • Сетевые таймауты — то же, что 5xx.

Простой helper для ретраев:

import asyncio, random, httpx
from typing import Awaitable, Callable, TypeVar

T = TypeVar("T")

async def with_retry(
    fn: Callable[[], Awaitable[T]],
    *,
    max_attempts: int = 5,
    base_delay: float = 0.5,
    max_delay: float = 30.0,
) -> T:
    for attempt in range(1, max_attempts + 1):
        try:
            return await fn()
        except httpx.HTTPStatusError as e:
            status = e.response.status_code
            if status in (401, 403, 404):
                raise          # бессмысленно ретраить
            if status == 429:
                retry_after = float(e.response.headers.get("Retry-After", base_delay))
                await asyncio.sleep(retry_after)
                continue
            if attempt == max_attempts or status < 500:
                raise
        except (httpx.TimeoutException, httpx.NetworkError):
            if attempt == max_attempts:
                raise
        delay = min(max_delay, base_delay * 2 ** (attempt - 1))
        delay += random.uniform(0, delay * 0.25)        # jitter
        await asyncio.sleep(delay)
    raise RuntimeError("unreachable")

Сообщения, упавшие после всех ретраев, складываем в Dead Letter Queue — отдельный топик/очередь, которую раз в день просматривает дежурный.

SaaS-конструкторы vs кастом

Альтернатива — собрать интеграцию без кода через визуальный конструктор:

  • n8n — open-source, self-hosted или cloud. Сотни готовых нод, включая Telegram, amoCRM, Битрикс. Подходит, когда логика умещается в DAG из 5–15 шагов.
  • Albato — российский SaaS, заточен под РФ-сервисы (amoCRM, МойСклад, ЮKassa, Wildberries). Работает быстро, поддержка отвечает на русском.
  • Zapier / Make (Integromat) — глобальные, удобны для зарубежных CRM. По РФ-картам не оплатить.

Когда конструктор — норм:

  • Бизнес-логика простая, без сложных условий и циклов.
  • Объём — до 10 000 сделок/месяц (дальше дорого).
  • Команда не хочет содержать инфраструктуру.

Когда нужен кастом:

  • Нестандартные сценарии (например, AI-анализ диалога перед записью в CRM).
  • Высокая нагрузка (сотни тысяч сделок).
  • Жёсткие требования по безопасности (изолированный контур, нет права слать данные в облако).
  • Двусторонняя синхронизация переписки с богатой UX.

Часто гибрид: критичный путь «лид → сделка» делаем кастомом, а вспомогательные сценарии (ежедневный отчёт в Telegram-чат, синхронизация справочников) — на n8n.

Аналитика: от лида до выручки

Главная цель сквозной аналитики — понять, какой источник трафика реально продаёт.

Как это работает:

  1. В рекламной ссылке UTM-метки: t.me/yourbot?start=utm_source-yandex_utm_campaign-promo2026.
  2. Бот при /start парсит payload, сохраняет UTM в сессии.
  3. При создании сделки в CRM UTM кладутся в кастом-поля сделки (utm_source, utm_medium, utm_campaign).
  4. Когда сделка переходит в «Оплачено», в BI (Метабаза, Tableau, DataLens) подтягивается выручка.
  5. Отчёт «выручка по utm_source» показывает реальный ROI каждого канала.

Без последнего шага вся работа по UTM теряет смысл — лиды считают все, выручку по источникам — единицы.

Итого

Интеграция Telegram-бота с CRM — это не «отправлять заявки в API». Полезная связка включает идемпотентную доставку, очередь с ретраями, маппинг полей, двустороннюю синхронизацию, идентификацию клиента и сквозную аналитику до выручки. amoCRM подходит для услуг и B2C, Битрикс24 — для крупных B2B-процессов с OpenLine, RetailCRM — для e-commerce, зарубежные системы — для глобальных команд. SaaS-конструкторы (n8n, Albato) закрывают простые сценарии, кастом нужен при высокой нагрузке или нестандартной логике. Сроки и бюджет сильно зависят от глубины: базовая связка за 1–2 недели окупается на первой же воронке.

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

Сколько стоит интеграция Telegram-бота с CRM?

Простая интеграция «заявка из бота → сделка в CRM с UTM-метками» — 50 000–120 000 ₽, срок 1–2 недели. Двусторонняя синхронизация статусов с уведомлениями пользователю — 100 000–250 000 ₽, 2–3 недели. Полноценный диалог из карточки CRM (менеджер пишет в CRM, клиент видит в Telegram) — от 250 000 ₽, 3–6 недель. Кастомная или самописная CRM обычно дороже на 30–50% — нет готовой документации API. Зарубежные системы вроде Salesforce — от 300 000 ₽ из-за сложной модели прав и необходимости сертифицированного партнёра.

Какую CRM выбрать для Telegram-бота?

amoCRM — для B2C и услуг в России: понятный REST API, цифровая воронка с автоматизацией, встроенный мессенджер-канал, виджеты в карточке. Битрикс24 — для B2B и крупных компаний: мощные права, отделы, бизнес-процессы, OpenLine как канал для бота. RetailCRM — для интернет-магазинов: интеграции с 1С, эквайрингами, маркетплейсами, бот создаёт заказ напрямую. HubSpot и Pipedrive — для глобальных команд и SaaS. Salesforce — для крупного enterprise. Самописная CRM — когда уже есть своя ERP, интеграция через REST/GraphQL/RabbitMQ.

Как сделать двустороннюю синхронизацию между Telegram-ботом и CRM?

Два пути. Первый — через готовый канал CRM (amoCRM Chat API, Битрикс OpenLine): сама CRM держит UI чата, бот выступает коннектором, который шлёт сообщения из CRM в Telegram и обратно. Второй — через свой middleware: бот пишет историю в собственную БД, в карточку CRM кладёт только ссылку «Открыть переписку», менеджер кликает и попадает в мини-веб-интерфейс. Первый путь проще и быстрее, второй гибче по UX (шаблоны, быстрые ответы, AI-подсказки, метки настроения клиента).

Что нужно учесть в интеграции бота с CRM, чтобы не было сбоев?

Шесть обязательных моментов. Идемпотентность через дедуп-ключ по update_id или хэшу содержимого, чтобы Telegram-ретраи не задваивали заявки. Очередь Redis/RabbitMQ между ботом и CRM, чтобы при падении CRM лиды не терялись. Учёт rate limits (у amoCRM 7 RPS, у Битрикса 2 RPS на метод). Маппинг полей в ТЗ заранее (источник, UTM, теги, ответственный). Ссылка обратно на чат в карточке. Корректная обработка ошибок: 401/403 не ретраить, 429 уважать Retry-After, 5xx ретраить с exponential backoff и складывать в DLQ после исчерпания попыток.

Как идентифицировать клиента из Telegram в CRM?

Самый надёжный способ — попросить телефон через request_contact: Telegram возвращает номер, привязанный к аккаунту, и этому номеру можно доверять. По нему ищем контакт в CRM или создаём новый. Дополнительно при первом обращении сохраняем tg_user_id в кастом-поле контакта — на повторных обращениях находим клиента за один запрос без необходимости снова спрашивать телефон. Для рассылок менеджеры используют deeplink с параметром (t.me/bot?start=lead_12345) — бот при /start понимает, что это конкретный лид из CRM, и сразу его идентифицирует.

Когда брать SaaS-конструктор (n8n, Albato), а когда писать кастом?

Конструктор подходит, если бизнес-логика умещается в DAG из 5–15 шагов, объём до 10 000 сделок в месяц и команда не хочет содержать инфраструктуру. n8n — open-source с self-hosted вариантом, Albato — российский SaaS с фокусом на РФ-сервисы (amoCRM, МойСклад, ЮKassa, Wildberries). Кастом нужен при нестандартных сценариях (AI-анализ диалога перед записью в CRM), высокой нагрузке (сотни тысяч сделок), жёстких требованиях по безопасности (изолированный контур) или двусторонней переписке с богатой UX. Часто оптимален гибрид: критичный путь — кастомом, вспомогательные сценарии — на n8n.

Как настроить сквозную аналитику от рекламы до выручки через бот и CRM?

Рекламная ссылка с UTM-метками (t.me/bot?start=utm_source-yandex_utm_campaign-promo2026), бот при /start парсит payload и сохраняет UTM в сессии. При создании сделки в CRM UTM кладутся в кастом-поля сделки (utm_source, utm_medium, utm_campaign). Когда сделка переходит в «Оплачено», в BI-систему (Метабаза, Tableau, DataLens) подтягивается выручка. Отчёт «выручка по utm_source» показывает реальный ROI каждого канала. Без последнего шага вся работа по UTM теряет смысл — лиды считают все, а выручку по источникам — единицы.