В конце статьи — ссылка на 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, сайт, соцсети) в одном окне.
Вот как выглядит интерфейс:
Почему это удобно для фитнес-клуба?
-
Все диалоги — 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, наш шлюз получает детали сообщения и отправляет его обратно в нужный мессенджер клиенту.
На скриншоте: список событий, которые можно получать через 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 на личный номер, а бизнесу нужно централизовать историю и аналитику.
Всё, что показано в статье, можно использовать как стартовую точку — дорабатывать под свои задачи и масштабировать под свои сценарии.
Исходники шлюза и готовых адаптеров выложены в открытый доступ — ссылка тут.
Спасибо, что дочитали до конца! Буду рад обратной связи, вопросам и комментариям.
ссылка на оригинал статьи https://habr.com/ru/articles/940264/
Добавить комментарий