Как стать автором
Поиск
Написать публикацию
Обновить

Как мы за 5 дней собрали контакт-центр для фитнес-клуба на Chatwoot и подключили к WhatsApp, Telegram и VK

Уровень сложностиСредний
Время на прочтение10 мин
Количество просмотров924

В конце статьи - ссылка на GitHub-репозиторий с исходниками нашего Python-шлюза для Chatwoot, WhatsApp, Telegram и VK.

Зачем все это нужно?

Обычное утро администратора фитнес-клуба

WhatsApp пикает — клиент спрашивает про расписание. В Telegram — кто-то хочет заморозить абонемент. Во ВКонтакте прилетает новая заявка на пробное занятие, а в e-mail запрос от корпоративного клиента. Между этим нужно ещё принять звонок и не забыть всем вовремя ответить.

Итог предсказуем: кто-то ждет ответа полдня, часть обращений теряется, а кто-то просто уходит к тем, кто отвечает быстрее.

Мы проанализировали 38697 диалогов с клиентами клуба и выяснили: 83.9% нагрузки — это рутинные, повторяющиеся сценарии (поздравления с днем рождения, запись/подтверждение, вопросы по расписанию). А ведь это всё можно было бы автоматизировать — чтобы менеджеры/администраторы тратили время на продажи и действительно важные вопросы, а не однотипные “Добрый день! Подтверждаю запись”.

Вся эта рутина отлично видна на реальных данных:

Распределение тем по диалогам в %%
Распределение тем по диалогам в %%

Почти половина всех диалогов — просто поздравления с днём рождения. Следом — подтверждение записи, напоминания, вопросы по картам и акциям. Всё это можно автоматизировать.

Если разложить диалоги по месяцам и темам, становится ещё очевиднее, насколько много однотипных повторяющиеся сценариев:

Топ-К тем диалогов по месяцам
Топ-К тем диалогов по месяцам

Большинство обращений месяц за месяцем — одни и те же сценарии. Это явный сигнал для бизнеса заняться автоматизацией.

Чего мы хотели добиться:

  • Собрать все каналы в одно окно — чтобы у оператора всегда был полный контекст по клиенту: история, теги, SLA, кто, когда и по какому поводу обращался.

  • Ввести реальные метрики реакции (FRT/DRT, SLA): чтобы видеть, где «узкие места», и не терять лидов из‑за задержек.

  • Подготовить инфраструктуру под ИИ‑ассистентов: чтобы в будущем можно было подхватывать типовые вопросы без участия оператора.

Почему не выбрали SaaS‑решение «из коробки»:

  • Open‑source и независимость. Мы хотели не зависеть от очередного SaaS‑провайдера, а сделать платформу «под себя»: дорабатывать любые фичи, не ждать поддержки, не бояться внезапных изменений тарифов или политик.

  • У нас уже был основной номер WhatsApp, который сохранили себе несколько тысяч клиентов — и для нас было критично сохранить с ним связь. Наш подход (через Wasender) позволил работать именно с этим же номером, не теряя контакт с существующей аудиторией, и при этом мы можем писать клиенту первым, а не только отвечать на входящие — в отличие от большинства официальных бизнес‑интеграций.

    То же самое с Telegram: через Telethon мы подключили именно «живой» аккаунт, а не бота — это единственный способ вести диалог от лица реального человека, а не от «машины», и тоже писать первым, как в обычном мессенджере.

  • Гибкая интеграция под будущие задачи, в том числе с 1С. Мы заранее думали о «двусторонней» интеграции: чтобы диалоги клиентов из мессенджеров отображались прямо в карточке клиента в 1С. Для SaaS‑платформ это все равно нужно будет дописывать руками.

Что такое Chatwoot — в двух словах

Chatwoot — это open-source платформа для поддержки клиентов, где можно собирать обращения из разных каналов (мессенджеры, e-mail, сайт, соцсети) в одном окне.

Вот как выглядит интерфейс:

Интерфейс Chatwoot
Интерфейс Chatwoot

Почему это удобно для фитнес-клуба?

  • Все диалоги — WhatsApp, Telegram, VK, e-mail, webchat — видны в одном интерфейсе.

  • Легко отслеживать метрики реакции: SLA, кто когда ответил, сколько висит без ответа.

  • Можно хранить любые дополнительные атрибуты клиента (например, ID из 1С, дату рождения, custom-поля под маркетинг).

  • Есть мобильное приложение и поддержка русского языка.

  • Бесплатно, без жесткой привязки к провайдерам и тарифам за каждый канал.

  • У платформы есть события через webhook - удобно интегрировать с ИИ-агентами.

Пара слов про wasender и telethon

  • Wasender — это API для WhatsApp за $6 в месяц, который позволяет подключить обычный (не бизнес-аккаунт) номер телефона, а значит, мы можем писать клиентам первым, как из обычного приложения.

  • Telethon — python‑библиотека для работы с Telegram, с помощью которой можно «подключиться» как обычный пользователь, а не бот (как бот она тоже умеет). Это способ вести диалог от лица администратора клуба, а не бота, и тоже начинать общение первым.

Архитектура решения: как всё устроено

Мы разделили каналы на две группы: одни можно сразу подключить к Chatwoot «из коробки», другие — такие как Wasender, Telegram и VK — требуют самописного шлюза.

Схема такая:

Схема интеграции
Схема интеграции
  • Каналы, которые нельзя напрямую подключить в Chatwoot (обычный WhatsApp-номер, Telegram, VK-группа) — идут через наш шлюз на Python. Он нормализует сообщения, стыкует их с нужным inbox, прокидывает в Chatwoot через API и обратно.

  • Встроенные каналы (Telegram Bot, e-mail, webchat) — спокойно подключаются к Chatwoot напрямую, без костылей.

Почему так:

  • В Chatwoot нет поддержки обычного аккаунта WhatsApp (только WhatsApp Business API), а Telegram можно подключить лишь через Bot API, но не напрямую как пользовательский аккаунт.

  • Наш шлюз как «универсальный адаптер»: он позволяет обойти ограничения и подключать любые нестандартные каналы.

Как это работает на практике

Когда клиент пишет в WhatsApp, Telegram, VK (через шлюз) или напрямую подключённый канал (e-mail, webchat, Telegram Bot) — все сообщения в итоге попадают в Chatwoot. Оператор видит единую историю и работает в одном окне.

Для каналов, которые идут через наш шлюз:

  • Шлюз, используя Chatwoot API (API Reference), сам создаёт (или находит) контакт, беседу и сообщение в интерфейсе Chatwoot — для Chatwoot всё выглядит как обычная внешняя интеграция через API.

  • Когда оператор отвечает клиенту из Chatwoot, мы подписываемся на события через webhooks (пример — на скриншоте ниже). Как только приходит событие message.created, наш шлюз получает детали сообщения и отправляет его обратно в нужный мессенджер клиенту.

События веб-хуков доступные в Chatwoot
События веб-хуков доступные в Chatwoot


На скриншоте: список событий, которые можно получать через webhook для построения собственной интеграции — например, message.created для обработки и отправки ответа клиенту в WhatsApp, Telegram или VK.

Для стандартных (напрямую подключённых) каналов всё это Chatwoot делает сам, без участия нашего шлюза.

В чём профит такого подхода

  • Максимальный охват: часть каналов подключена «как есть», часть — через шлюз, поэтому не теряем ни одного клиента.

  • Гибкость: если завтра появится новый мессенджер (привет, MAX) или специфический канал — просто добавим новый адаптер к шлюзу, а Chatwoot останется центром коммуникации.

  • Простота автоматизации и ИИ: любые события (message.created, contact.updated и др.) легко передавать во внешние сервисы, ИИ-агентов, 1С и т.п.

Архитектура шлюза и компонентов

Шлюз написан на Python с использованием FastAPI. В качестве «имитации» event bus мы использовали библиотеку pyee — это быстрый способ организовать обработку событий между модулями, но не полноценная промышленная шина. В реальном проекте рекомендуется использовать что‑то серьёзнее, например RabbitMQ или Kafka.

Структура шлюза модульная, с элементами гексагональной архитектуры:

  • Каждый канал (WhatsApp, Telegram, VK) реализован отдельным адаптером, который занимается разбором входящих и отправкой исходящих сообщений.

  • Адаптеры обрабатывают события из своих каналов, нормализуют данные, пробрасывают их дальше через общие методы API.

  • Вся логика интеграции максимально вынесена за пределы ядра - можно легко добавить новый канал или связать шлюз с внешним сервисом (например, AI-агентом или CRM), не переписывая основную логику.

Почему так?
Модульность плюс гексагональная архитектура дают простую поддержку, быстрые изменения и удобную интеграцию новых сценариев — достаточно реализовать новый адаптер или endpoint, не ломая остальной код.

Краткие примеры интеграции: WhatsApp ↔ Chatwoot через Wasender

1. Получение сообщений из WhatsApp и создание их в Chatwoot

Когда клиент пишет в WhatsApp, Wasender отправляет webhook на наш шлюз, хендлер /wasender/webhook/{webhook_id} обрабатывает запрос так:

@router.post("/wasender/webhook/{webhook_id}", response_model=dict)
async def wasender_webhook(
    webhook_id: str,
    payload: WasenderWebhookPayload,
    x_webhook_signature: str | None = Header(default=None, alias="X-Webhook-Signature"),
):
    # Проверяем ID и секрет для безопасности
    if webhook_id != config.wasender.webhook_id:
        raise HTTPException(status_code=403, detail="Invalid webhook ID")
    if x_webhook_signature != config.wasender.webhook_secret:
        raise HTTPException(status_code=403, detail="Invalid X-Webhook-Signature")

    event = payload.event
    if event == "messages.upsert":
        raw = payload.data["messages"]
        key = raw["key"]
        from_me = key["fromMe"]
        # Рассылаем событие в “шину”: входящее или исходящее
        bus.emit("wasender.outgoing" if from_me else "wasender.incoming", payload.model_dump())
    return {"status": "ok"}

Что происходит:

  • Проверяются ключи и секреты (защита от лишних запросов).

  • Для события messages.upsert разбирается, кто отправитель (оператор или клиент).

  • Событие попадает в "шину", где дальше по коду создаётся контакт, диалог и сообщение в Chatwoot.

2. Отправка ответного сообщения из Chatwoot обратно в WhatsApp (через Wasender)

Когда оператор отвечает клиенту из Chatwoot, шлюз ловит webhook /chatwoot/webhook/{webhook_id}:

@router.post("/chatwoot/webhook/{webhook_id}", response_model=dict)
async def chatwoot_webhook(webhook_id: str, request: Request):
    channel = config.chatwoot.channel_by_webhook_id.get(webhook_id)
    if not channel and webhook_id != config.chatwoot.webhook_id:
        raise HTTPException(status_code=403, detail="Unknown webhook ID")

    payload = await request.json()
    event = payload.get("event")
    msg_type = payload.get("message_type")
    conv = payload.setdefault("conversation", {})
    meta = conv.setdefault("meta", {})
    if channel:
        meta["channel"] = channel

    if event == "message_created":
        if msg_type == "incoming":
            bus.emit("chatwoot.incoming", payload)
        elif msg_type == "outgoing":
            bus.emit("chatwoot.outgoing", payload)
    return {"status": "received"}

Что происходит:

  • Проверяется идентификатор webhook (много каналов — много хуков).

  • Информация о канале добавляется в payload.

  • Если это событие message_created и сообщение исходящее, оно попадает в "шину" как chatwoot.outgoing.

  • Далее роутер сообщений сам решает, через какой канал (адаптер) (Wasender, Telethon, VK) отправлять клиенту.

Все остальные интеграции (Telegram, VK и др.) реализованы по тому же принципу и доступны в исходниках — ссылка на репозиторий будет в конце статьи.

Грабли и подводные камни: что пошло не так

WhatsApp (Wasender):

  • Очень низкий порог входа (6$ в месяц, можно писать первым), но:

    • Нужна нероссийская карта для оплаты — для кого-то это возможно будет проблемой, но это сильно дешевле любой интеграции доступной в РФ.

    • Риск бана за спам — если слать много массовых рассылок, аккаунт быстро заблокируют. Но это общее место, конкретно к Wasender/WhatsApp отношения не имеет.

    • При большом объёме сообщений нужна очередь и контроль частоты отправки.

  • Отправка статуса сообщения API отдает не сразу - пришлось реализовать "бэкофф" (повтор с увеличивающейся задержкой).

Telegram (Telethon):

  • Реальная угроза банов: при первом запуске через Telethon разлогинило на всех устройствах, и чуть не схватили бан. Опытным путем выяснили, что надо заполнять device_model, system_version и делать паузы между действиями.

  • Интерактивная авторизация: сессия хранится в файле. Такой вариант, как в репозитории, не подходит для прода - при первом запуске всё равно нужно вводить логин и пароль. Для прода стоит реализовать отдельные ручки для авторизации.

VK (Callback API):

  • VK не отдаёт телефон пользователя по API, а многие клиенты зарегистрированы только на номер. Пришлось добавить custom-атрибуты (vk_user_id, vk_peer_id) для связи карточек клиентов.

  • В варианте с callback-api сервер должен быть доступен из интернета (локально можно отлаживать с ngrok).

  • Дополнительные атрибуты. Можно дообогащать данные клиентов (дата рождения, город, количество подписчиков), но заполнены не всегда.

Прочее:

  • Объединение контактов: если клиент сначала пишет в WhatsApp, а потом — в VK, Chatwoot по умолчанию создаёт две разные карточки. Помогает функция merge: можно объединить профили вручную, а custom-атрибуты позволяют автоматизировать этот процесс.

  • Event bus: pyee - не настоящая шина, в проде обязательно нужен брокер (Kafka, RabbitMQ), чтобы не терять события и масштабироваться.

  • Безопасность: все ключи, токены и файлы сессий вынесены в .env (в исходнике — пример .env_template). Для продакшена лучше хранить секреты в секрет-хранилищах (Vault, AWS Secrets Manager).

  • Rate limiting и anti-spam: обязательно следить за частотой отправки, не игнорируйте лимиты и не экспериментируйте с массовыми рассылками на боевых номерах.

Что получилось на выходе и метрики

Как изменилось после внедрения

После перехода на Chatwoot получили рост прозрачности процессов - теперь все обращения из WhatsApp, Telegram, VK и e-mail идут в одно окно, ничего не теряется, вся история общения с клиентом видна в одном месте. Проще контроллировать. Администраторы и менеджеры перестали путаться между окнами и мессенджерами: для каждого клиента - вся переписка, комментарии, теги, SLA - все в одном месте.

Ощутимые результаты (цифры — примерные, но на основе реального эффекта):

  • Скорость ответа (FRT) для входящих сообщений сократилась с 20–40 минут до 3-5 минут даже в часы пик.

  • Доля неотвеченных обращений стала чуть ниже: раньше часть диалогов могла теряться, теперь почти все обращения фиксируются и закрываются, пропусков практически нет.

  • До 80% всех диалогов — это типовые сценарии (ДР, запись, напоминание, вопросы по картам), и их теперь можно быстро автоматизировать либо закрывать полуавтоматически через заготовленные в Chatwoot шаблоны.

  • Заметно снизилась нагрузка на администраторов: вместо того, чтобы постоянно прыгать между приложениями, они работают в едином окне, быстро находят нужную переписку и могут фокусироваться на сложных вопросах и продажах.

Главный бизнес-эффект

  • Меньше потерь лидов: когда все обращения из каналов фиксируются и идут по единому процессу, меньше ситуаций “кто-то забыл перезвонить” или “забыли отправить подтверждение”.

Что дальше / Планы на развитие

Основной вектор развития — AI-автоматизация клиентских сценариев. Уже сейчас вся инфраструктура позволяет подключить LLM-агента - достаточно добавить логику автодействий на стороне шлюза.

В ближайшее время планируем:

  • Автоматизировать ответы на типовые вопросы (расписание, запись, акции, подтверждение, FAQ) полностью через AI‑агента.

  • Реализовать автоматические поздравления с днем рождения, напоминания о тренировках, простые upsell прямо через сценарии в шлюзе — без участия операторов.

  • Разработать «умные» фильтры, чтобы AI‑агент подключался только когда действительно может помочь.

  • Используя RAG (Retrieval‑Augmented Generation) отвечать на вопросы клиентов используя информацию из базы знаний.

Заключение и выводы

В нашем кейсе за 5 дней мы собрали полноценный омниканальный контакт‑центр для фитнес‑клуба, избавились от рутины и получили инфраструктуру, готовую к подключению AI‑агента и интеграции.

Главное преимущество такого подхода — гибкость: вы не привязаны к провайдерам, свободно добавляете новые каналы, быстро адаптируете сценарии и автоматизируете любые процессы «под себя».

Где ещё можно применить это решение:

  • Сервисные и b2c-компании с большим потоком чатов: медицинские центры, стоматологии, школы и детские кружки, салоны красоты.

  • Колл‑центры, где важно не терять ни одного клиента и нужен «живой» номер для коммуникации.

  • Компании, у которых часть клиентов привыкла писать в WhatsApp/Telegram на личный номер, а бизнесу нужно централизовать историю и аналитику.

Всё, что показано в статье, можно использовать как стартовую точку — дорабатывать под свои задачи и масштабировать под свои сценарии.

Исходники шлюза и готовых адаптеров выложены в открытый доступ — ссылка тут.

Спасибо, что дочитали до конца! Буду рад обратной связи, вопросам и комментариям.

Теги:
Хабы:
+4
Комментарии0

Публикации

Ближайшие события