SatoshiEX — Telegram-бот для офлайн-обменника криптовалют
Интеграция Telegram-бота с RetailCRM, партнёрской программой, Telegram Mini App и виджетом на сайте — полный цикл сопровождения клиента от первого контакта до завершения обмена.
⚡ Проблема
Обменник работает офлайн в Москве. Менеджеры вручную фиксировали заявки, не было единого канала связи с клиентами, партнёрская программа не велась, а заявки с сайта и Mini App не попадали в CRM автоматически.
✅ Решение
Telegram-бот @SmanagerEX_bot автоматически создаёт заявки в RetailCRM, ведёт двустороннюю переписку с клиентом через MessageGateway, управляет партнёрской программой и принимает заявки из трёх каналов одновременно.
⚙️ Что реализовано
📈
Актуальные курсы в реальном времени
USDT/RUB, USD green/RUB, USD blue/RUB с комиссией. Данные из биржи Grinex через Laravel API. Кнопка перехода прямо в Telegram Mini App.
🔄
FSM-диалоги оформления заявки
Пошаговый диалог обмена: валюта отдаёшь → валюта получаешь → сумма. Поддержка ₽, $, €, USDT. Inline-кнопка отмены заявки переводит в статус cancel-other в CRM.
💬
Двусторонняя переписка с CRM
Текст, фото и документы клиента пересылаются менеджеру через RetailCRM MessageGateway. Ответы менеджера доставляются клиенту: text, фото, видео, аудио, документы.
🤝
Партнёрская программа /partner
Регистрация в SQLite, генерация двух реферальных ссылок (бот + сайт), автоматическое накопление вознаграждений. Уведомление при завершении каждого реферального заказа.
📱
Telegram Mini App
Эндпоинты POST /api/miniapp/order и /api/miniapp/contact. Полная цепочка: клиент → заказ в CRM → системное сообщение менеджеру → активация контекста переписки.
🌐
Виджет-калькулятор на сайте
Эндпоинт POST /api/widget/order. Создаёт клиента и заказ в CRM без участия бота. Принимает дату визита, контакты и реферальный код партнёра.
🔍
UTM-трекинг и deep link
Сохранение UTM-меток при переходах по реферальным ссылкам. Laravel API возвращает HTTP 201 Created. Даже при заблокированном боте данные аналитики не теряются.
🖥️
Веб-админка партнёрской программы
admin.satoshi-ex.com — таблица партнёров, статистика рефералов и выплат, страница детализации, выплата с уведомлением в Telegram. Отдельный aiohttp-сервис.
🔗 Ключевые интеграции
🔵 RetailCRM
API v5 + MessageGateway
- Поиск/создание клиента при каждой заявке
- Запись кастомных полей:
rid, tg_id, data_vizita
- Цепочка MG-привязки:
message_id → mg_customer_id
- Кнопка «Перейти в диалог» в карточке заказа CRM
- Webhook — приём сообщений менеджера → Telegram
🟣 Партнёры
SQLite + фоновая задача
- Batch-запрос к CRM раз в 60 сек для всех рефералов
- Статус
complete → начисление вознаграждения
- Автоматическое уведомление в Telegram партнёру
- Привязка заказов с сайта по
ref_code из cookie
- История выплат в таблице
payouts
🟢 Mini App
multipart/form-data API
- Создание заявки на обмен USDT с датой визита
- Активация FSM-диалога «Связаться с нами» из браузера
- CORS-заголовки для кросс-доменных запросов
- Возврат номера заявки:
{"order_id": "№12345"}
- nginx proxy_pass → aiohttp :8081
🔄 Жизненный цикл заявки из бота
Команда /start или кнопка меню
Пользователь открывает бот. Если есть deep link параметр — UTM сохраняется, клиент привязывается к партнёру. TelegramForbiddenError обёрнут в try/except — аналитика сохраняется даже при заблокированном боте.
FSM-диалог обмена или «Связаться с нами»
Пошаговый диалог с Inline-кнопками. На каждом шаге доступна отмена. Состояния хранятся в MemoryStorage (планируется Redis).
Создание клиента и заказа в RetailCRM
Поиск клиента по tg_id или tg_username. При отсутствии — создание. Заказ записывается со статусом, методом, полями валют, курса и ID партнёра в customFields.rid.
Системное сообщение в чат менеджера (MG)
MessageGateway Transport API (JSON + X-Transport-Token). Из ответа извлекается message_id → получается mg_customer_id → обновляется клиент CRM. Появляется кнопка «Перейти в диалог» в карточке заказа.
Активация контекста переписки (TTL 5 мин)
Следующие 5 минут текст, фото и документы пользователя автоматически пересылаются менеджеру через MG. Фото: file_id → URL → upload_by_url → message.items.
Отслеживание и уведомление партнёра
Если клиент пришёл по реф-ссылке — заказ в SQLite. Фоновая задача раз в 60 сек batch-запросом проверяет статусы. При complete — начисление и уведомление партнёра в Telegram.
📡 Приём сообщений из CRM (Webhook)
01
Менеджер пишет клиенту в RetailCRM
MessageGateway отправляет POST-запрос на api.satoshi-ex.com по webhook-URL
CRM → nginx
02
nginx rewrite + proxy_pass
Rewrite пути → proxy_pass на 127.0.0.1:8081/webhook/mg. Параллельно с polling-режимом бота.
nginx → aiohttp
03
Парсинг WebhookMessage и определение типа
text / image / file / audio. Файлы делятся на видео (mp4, mov, avi) и документы (PDF, DOCX и др.) по расширению.
WebhookService
04
Скачивание файла из MG в память
URL файлов из MG требует авторизации X-Transport-Token. Прямая отправка в Telegram невозможна — скачиваем байты и передаём через Bot API.
Transport API
05
Доставка клиенту в Telegram
sendMessage / sendPhoto / sendVideo / sendVoice / sendDocument. Группы фото/видео — sendMediaGroup. Клиент видит сообщение менеджера прямо в Telegram.
Bot API
⚡
PHP-модуль выведен из эксплуатации 13.04.2026. Весь webhook-транспорт переписан на Python. Бэкап PHP-модуля сохранён в /root/backups/2026-04-13/. Теперь вся обработка — один Python-сервис без внешних зависимостей.
📊 Результаты
3
Канала приёма заявок: бот, Mini App, сайт
60 сек
Интервал проверки статусов рефералов
5 мин
TTL контекста переписки клиента с менеджером
8
Репозиториев по принципу Repository Pattern
9
Роутеров aiogram (handlers)
SOLID
Архитектурные принципы + DI через конструкторы
⚙️ Архитектурные особенности
🧱
SOLID + слоёная архитектура
Handlers → Services → Repositories → External API. Зависимости внедряются через конструкторы. Фабрика bot/factory.py — единственное место сборки конкретных реализаций. Обработчики работают с ABC-интерфейсами.
⚡
Полностью асинхронный стек
aiogram 3.x + aiohttp + aiosqlite. Webhook-сервер и бот работают параллельно в одном event loop. BaseHttpRepository предоставляет retry-логику с таймаутами для всех HTTP-репозиториев.
🗄️
Централизованный реестр CRM-констант
Все статусы заказов, имена кастомных полей, коды методов и эндпоинты собраны в config/crm_constants.py. При изменении параметра в RetailCRM — редактируется один файл.
🔍
Структурированное логирование с trace_id
Консоль — human-readable формат. Файл — полный JSON с trace_id, прослеживаемым через все слои: middleware → handler → service → repository. Ротация логов: 10 МБ, 5 копий.
🔐
Graceful shutdown и корректная остановка
Фоновая задача отслеживания рефералов корректно останавливается при shutdown бота. Все активные HTTP-соединения закрываются. Запущенные проверки CRM завершаются до выхода.
🏗️
6 паттернов проектирования
Repository, Template Method (BaseHttpRepository), Service Layer, Factory, Strategy (FSM-диалоги как взаимозаменяемые стратегии), Observer (периодический опрос статусов с batch-запросом filter[ids][]).
🔗
Автоматическая MG-привязка клиента: После отправки системного сообщения в MessageGateway извлекается message_id → по нему получается mg_customer_id → через update_mg_customer_id привязывается к CRM-клиенту. Это обеспечивает появление кнопки «Перейти в диалог» прямо в карточке заказа RetailCRM.
📦
Batch-оптимизация партнёрских проверок: Вместо N отдельных запросов к CRM — один GET /api/v5/orders с множественным filter[ids][] по всем ожидающим заказам. Внутренний числовой ID заказа, а не номер — id=10538 при number='10538A'.
🛠️ Технологии
Python 3.12
aiogram 3.x
aiohttp
aiosqlite
SQLite
RetailCRM API v5
MessageGateway
nginx
systemd
aiohttp-jinja2
ruff
mypy strict
pre-commit
dataclasses
asyncio
FSM
Let's Encrypt
✅ Подойдёт вам, если
- У вас офлайн-обменник или сервис с физическими визитами — нужен удобный канал приёма заявок и автоматическая передача данных в CRM
- Хотите двустороннюю переписку с клиентом прямо из Telegram, при этом менеджер работает в привычном интерфейсе RetailCRM
- Нужна партнёрская программа с реферальными ссылками, автоматическим отслеживанием заказов и начислением вознаграждений
- Требуется принимать заявки сразу из нескольких точек: Telegram-бот, Mini App, виджет на сайте — всё в одну CRM
- Важна надёжность: обработка ошибок на каждом слое, retry-логика для HTTP, graceful shutdown, структурированные логи с trace_id
Раньше менеджеры вручную переносили заявки из Telegram в таблицы. Теперь всё автоматически — клиент написал боту, заявка сразу в CRM, менеджер видит полный диалог прямо в карточке заказа. Партнёры сами видят свои начисления и не задают лишних вопросов.
— Команда SatoshiEX, Москва
Нужна интеграция Telegram-бота с вашей CRM?
Разработаю систему автоматического приёма заявок, двусторонней переписки и партнёрской программы под ваш бизнес
Обсудить проект →