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

CRM-бот в MAX: автоматизация заявок и сделок

Как бот в MAX превращается в полноценный CRM-инструмент: квалификация заявок, передача в amoCRM/Bitrix24, уведомления менеджерам, аналитика.

  • MAX
  • CRM
  • интеграции
  • продажи

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

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

Польза от связки бот-в-MAX + CRM сводится к пяти вещам, и каждая из них напрямую конвертируется в деньги.

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

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

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

Минимальный набор сценариев, ради которых это всё затевается. Каждый по отдельности экономит 1–3 минуты на лиде; на потоке в 200 лидов в месяц это 5–10 часов рабочего времени и существенно меньшая просадка по конверсии.

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

Всё это — обычные, проверенные сценарии. Никакой магии, только аккуратная автоматизация рутинных шагов.

Архитектура

Минимально жизнеспособный CRM-бот в MAX выглядит так:

  • Frontend (бот в MAX). Сценарий диалога, FSM (finite state machine), валидация ввода, инлайн-клавиатуры с быстрыми ответами.
  • Backend. Сервис заявок, очередь интеграций (брокер сообщений), обработчик webhook от CRM, сервис уведомлений.
  • CRM-адаптер. Тонкий слой, инкапсулирующий API конкретной CRM (amoCRM, Битрикс24, Мегаплан, RetailCRM). Интерфейс с методами createDeal, updateDeal, addNote, findContact. Реализация под конкретную CRM скрыта за интерфейсом.
  • Уведомления. Отдельный воркер для рассылки менеджерам и клиентам, чтобы основной поток обработки не блокировался отправкой сообщений.

Адаптер — обязательно отдельный модуль, потому что CRM могут меняться. Сегодня amoCRM, завтра Битрикс24 — основной код не должен переписываться. При смене CRM меняется только реализация адаптера, и это занимает 1–2 недели против 4–6 недель полной переработки, если интеграция была «зашита» в обработчики бота напрямую.

Поток данных в системе:

MAX-бот  →  очередь (RabbitMQ)  →  CRM-адаптер  →  amoCRM / Битрикс24
                  ↑                       ↓
                  └──────  retry  ────────┘
                  ↓
                Dead Letter Queue  (раз в день дежурный)

CRM-webhook  →  обработчик webhook  →  MAX-бот (уведомление клиенту/менеджеру)

Сценарий квалификации

Хороший CRM-бот не задаёт 20 вопросов подряд. Логика обычно такая:

  • 2–3 ключевых вопроса для отсева нецелевых лидов (бюджет, регион, цель обращения).
  • Если лид нецелевой — мягкий отказ с переадресацией в FAQ или базу знаний.
  • Если целевой — детальные вопросы и фиксация полной заявки в БД.
  • Параллельно бот собирает «технические» данные: UTM-метки, referrer, время суток, устройство.

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

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

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

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

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

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

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

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

CRMAuthRate limitsWebhooksСтоимость интеграции
amoCRMOAuth 2.07 RPSВходящие + исходящие50–150 тыс ₽
Битрикс24OAuth 2.0 / вебхук-токен2 RPS на методВходящие + исходящие80–250 тыс ₽
МегапланAPI key10 RPSТолько входящие в МП60–180 тыс ₽
RetailCRMAPI key300 запросов/минТриггеры + webhooks80–200 тыс ₽

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

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

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

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"Заявка из MAX: {lead['name']}",
        "price": lead.get("budget", 0),
        "pipeline_id": 1234567,
        "status_id": 7654321,            # «Первичный контакт»
        "responsible_user_id": 111,      # Авто-распределение по правилу
        "_embedded": {
            "contacts": [{"id": contact_id}],
            "tags": [{"name": "max_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["max_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 против field_id: код используется для системных полей (PHONE, EMAIL), а ID — для кастомных. ID берутся из настроек аккаунта /api/v4/leads/custom_fields. Поле max_user_id критично — по нему мы потом найдём клиента при повторном обращении без необходимости снова просить телефон.

Битрикс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": "MAX_MESSENGER",
            },
        })
        contact_id = r.json()["result"]

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

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

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

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

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

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

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

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

  • По верифицированному телефону. MAX-бот просит поделиться контактом — мессенджер возвращает номер, привязанный к аккаунту. Этому номеру можно доверять.
  • По email. Менее надёжно — клиент может ввести чужой. Полезно, если CRM первична для email-маркетинга.
  • По кастом-полю max_user_id. Сохраняем ID MAX-пользователя в отдельное поле контакта при первом обращении. На повторных обращениях находим клиента за один запрос.
  • По deeplink с параметром. В рассылке менеджер шлёт ссылку с payload — бот при /start понимает, что это лид из CRM, и сразу его идентифицирует.

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

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

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

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

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

CRM может упасть, провести регламентные работы, получить таймаут на 30 секунд — а лиды поступать продолжают. Если MAX-бот пишет в 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 в MAX-бот

Обратное направление: 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)
        max_user_id = deal.get("UF_CRM_MAX_USER_ID")
        new_stage = deal["STAGE_ID"]

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

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

Сценарии «менеджеру в личный MAX» особенно ценят руководители — не нужно держать вкладку с 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 — отдельный топик/очередь, которую раз в день просматривает дежурный.

# Dead Letter Queue: сохраняем "сломанные" сообщения для разбора
async def retry_or_dlq(msg, exc: Exception):
    retries = int(msg.headers.get("x-retry-count", 0))
    if retries < MAX_RETRIES and is_retryable(exc):
        await rabbitmq.publish(
            exchange="crm",
            routing_key="lead.new",
            body=msg.body,
            headers={"x-retry-count": str(retries + 1)},
            delay_ms=backoff_delay(retries),
        )
        await msg.ack()
    else:
        # В DLQ кладём оригинал + причину + traceback
        await rabbitmq.publish(
            exchange="crm.dlq",
            routing_key="lead.failed",
            body=msg.body,
            headers={
                "x-original-error": str(exc)[:500],
                "x-failed-at": datetime.utcnow().isoformat(),
                "x-retries": str(retries),
            },
        )
        await msg.ack()
        await alert_devops(f"Лид в DLQ: {exc}")

Дежурный раз в день открывает DLQ, разбирает по причинам (недоступная CRM, кривое поле, удалённая воронка), руками или скриптом перекладывает обратно. Лиды не теряются.

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

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

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

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

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

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

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

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

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

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

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

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

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

Уведомления и SLA

MAX-бот без уведомлений — это просто форма. Нужны четыре типа алертов:

  • Менеджеру — мгновенный пинг при новой целевой заявке (в личный MAX через служебного бота, по email, или в Битрикс24-чат).
  • Клиенту — подтверждение приёма заявки и срок ответа («с вами свяжутся в течение 30 минут»).
  • Руководителю — ежедневный или еженедельный дайджест по воронке (сколько лидов, конверсия, средний чек, источники).
  • Алерт об эскалации — если заявка не была взята в работу за N минут, уведомление руководителю или резервному менеджеру.

Это превращает бота из «канала входа» в «инструмент дисциплины» по обработке лидов.

Итого

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

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

Что такое CRM-бот в MAX и чем он отличается от обычного лид-бота?

CRM-бот в MAX живёт с клиентом дольше, чем форма-лидогенератор. Он принимает заявку с уточняющими вопросами, квалифицирует лида (горячий/тёплый/холодный), отсеивает нецелевых, передаёт в amoCRM/Битрикс24/RetailCRM с правильными полями и UTM, шлёт уведомления менеджеру и клиенту, ставит напоминания, поддерживает двустороннюю переписку через OpenLine или Chat API и собирает аналитику воронки до выручки. Обычный лид-бот делает только первый шаг — отправить заявку. CRM-бот закрывает весь цикл от первого касания до сделки.

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

Простая интеграция «заявка из бота → сделка в CRM с UTM-метками» — 50 000–120 000 ₽, срок 1–2 недели. Двусторонняя синхронизация статусов с уведомлениями пользователю — 100 000–250 000 ₽, 2–3 недели. Полноценный диалог из карточки CRM (менеджер пишет в CRM, клиент видит в MAX) через OpenLine-коннектор — от 250 000 ₽, 3–6 недель. Глубокая интеграция с многоступенчатой воронкой, очередью, DLQ, мониторингом и аналитикой — 250 000–600 000 ₽. Простой переход на новую CRM, если бот уже есть и адаптер выделен — 1–2 недели.

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

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

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

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

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

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

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

Самый надёжный способ — попросить телефон через запрос контакта: MAX возвращает номер, привязанный к аккаунту, и этому номеру можно доверять. По нему ищем контакт в CRM или создаём новый. Дополнительно при первом обращении сохраняем max_user_id в кастом-поле контакта — на повторных обращениях находим клиента за один запрос без необходимости снова спрашивать телефон. Для рассылок менеджеры используют deeplink с параметром (payload в стартовой ссылке) — бот при /start понимает, что это конкретный лид из CRM, и сразу его идентифицирует.

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

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