В конце статьи - ссылка на 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 на личный номер, а бизнесу нужно централизовать историю и аналитику.
Всё, что показано в статье, можно использовать как стартовую точку — дорабатывать под свои задачи и масштабировать под свои сценарии.
Исходники шлюза и готовых адаптеров выложены в открытый доступ — ссылка тут.
Спасибо, что дочитали до конца! Буду рад обратной связи, вопросам и комментариям.