Розробка Telegram Mini App з інтеграцією Бітрікс24
Менеджер у полі відкриває Telegram, бачить лід — і переводить його в наступний статус за 30 секунд. Замість 5 хвилин пошуку в браузері. Це типовий сценарій, який ми закриваємо зв'язкою Telegram Mini App + REST API Бітрікс24. Mini App працює як CRM-дашборд прямо в чаті: список угод, етапи, контактна інформація, можливість прокоментувати. Розробляємо під ключ з повною маршрутизацією OAuth, зберіганням токенів та налаштуванням вебхуків.
Проблеми, які вирішує інтеграція
Авторизація без браузера. Бітрікс24 REST API вимагає OAuth access_token, але Mini App — веб-сторінка в WebView Telegram, де редирект неможливий. Рішення — сервер-посередник, який валідує Telegram initData і видає OAuth-посилання або готовий токен. Цей підхід застосували в 15+ проєктах.
Затримки в опрацюванні лідів. Менеджери витрачають до 5 хвилин на відкриття браузера, вхід у CRM та пошук картки. Mini App скорочує це до 30 секунд: співробітник бачить лід одразу і змінює статус одним тапом. За нашими вимірами, швидкість реакції на вхідний лід зростає на 60–70% — Telegram Mini App обробляє ліди в 3 рази швидше, ніж через веб-інтерфейс.
Сповіщення в реальному часі. Без інтеграції менеджер дізнається про нову угоду через email-розсилки із затримкою в хвилини. Вебхуки подій Бітрікс24 надсилають POST-запит на сервер, а той — повідомлення в Telegram. Сповіщення приходить за 1–2 секунди.
Сценарії використання
| Сценарій | Опис | Цільова аудиторія |
|---|---|---|
| Мобільний CRM-дашборд | Перегляд лідів та угод, зміна статусу, коментарі | Менеджери в полі, відділи продажів |
| Корпоративне замовлення | Оформлення заявок дилерами/агентами через Mini App | Мережеві компанії, дистриб'ютори |
| Self-service портал | Клієнт бачить статус заявок та історію звернень | B2C-сервіси, техпідтримка |
| Таск-менеджер | Список завдань, зміна статусу, прикріплення файлів | Команди, що використовують Бітрікс24 |
Архітектура: OAuth та серверний проксі
Процес авторизації:
- Користувач відкриває Mini App. Фронтенд передає initData на сервер.
- Сервер звіряє hash initData, витягує user_id та шукає запис у таблиці
tg_bx24_tokens. - Якщо токен знайдено і не прострочений — повертає JWT для Mini App. Якщо ні — видає посилання на OAuth-авторизацію в Бітрікс24.
- Після підтвердження сервер обмінює
codeнаaccess_tokenі зберігає його з прив'язкою до Telegram user_id.
| Крок | Дія | Учасник |
|---|---|---|
| 1 | Відкриття Mini App, передача initData | Користувач -> Mini App |
| 2 | Валідація initData, пошук токена | Сервер |
| 3 | Повернення JWT або OAuth-посилання | Сервер -> Mini App |
| 4 | Підтвердження OAuth (якщо потрібно) | Користувач -> Бітрікс24 |
| 5 | Обмін code на токен, збереження | Сервер |
Код обробки OAuth-колбеку вже стандартний для всіх наших інтеграцій:
class Bx24OAuthController { public function callback(Request $request): Response { $code = $request->get('code'); $tgUserId = $request->session()->get('pending_tg_user_id'); $tokenData = $this->exchangeCode($code); \Local\TgBx24\TokenStorage::save($tgUserId, [ 'access_token' => $tokenData['access_token'], 'refresh_token' => $tokenData['refresh_token'], 'expires_at' => time() + $tokenData['expires_in'], 'domain' => $tokenData['domain'], 'user_id' => $tokenData['user_id'], ]); $this->bot->sendMessage($tgUserId, 'Авторизація в Бітрікс24 пройшла успішно.'); return redirect('/auth/success'); } private function exchangeCode(string $code): array { $response = Http::post('https://oauth.bitrix.info/oauth/token/', [ 'grant_type' => 'authorization_code', 'client_id' => config('bx24.client_id'), 'client_secret' => config('bx24.client_secret'), 'code' => $code, ]); return $response->json(); } } Токени зберігаються в окремій таблиці або Redis. Ми використовуємо автоматичний refresh за 5 хвилин до закінчення терміну, щоб користувач не втрачав доступ. Усі секрети шифруються.
class TokenStorage { private const TABLE = 'tg_bx24_tokens'; public static function save(int $tgUserId, array $tokenData): void { $encrypted = \Local\Crypto::encrypt(json_encode($tokenData)); \Bitrix\Main\Application::getConnection()->queryExecute( "INSERT INTO " . self::TABLE . " (tg_user_id, token_data, updated_at) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE token_data = ?, updated_at = NOW()", [$tgUserId, $encrypted, $encrypted] ); } public static function getValidToken(int $tgUserId): ?array { $result = \Bitrix\Main\Application::getConnection()->query( "SELECT token_data FROM " . self::TABLE . " WHERE tg_user_id = ?", [$tgUserId] ); $row = $result->fetch(); if (!$row) return null; $data = json_decode(\Local\Crypto::decrypt($row['token_data']), true); if ($data['expires_at'] < time() + 300) { $data = self::refreshToken($data); } return $data; } private static function refreshToken(array $data): array { $response = \Bitrix\Main\Web\HttpClient::post( 'https://oauth.bitrix.info/oauth/token/', [ 'grant_type' => 'refresh_token', 'client_id' => \Bitrix\Main\Config\Option::get('local.tg_bx24', 'client_id'), 'client_secret' => \Bitrix\Main\Config\Option::get('local.tg_bx24', 'client_secret'), 'refresh_token' => $data['refresh_token'], ] ); return $newData; } } Чому потрібен сервер-посередник?
Прямий запит з Mini App до API Бітрікс24 неможливий через CORS та відсутність безпечного зберігання токена на клієнті. Сервер-посередник працює як шифрувальний рубильник: усі запити до REST API йдуть через нього, токени не покидають сервер. Це стандарт безпеки для OAuth у мобільних додатках.
Як влаштовано обмін даними в реальному часі?
Бітрікс24 дозволяє налаштувати вебхуки на події — наприклад, ONCRMDEALUPDATE. Коли подія спрацьовує, Бітрікс24 шле POST на наш сервер. Сервер визначає відповідального (ASSIGNED_BY_ID), знаходить його Telegram user_id через таблицю токенів і надсилає повідомлення через sendMessage. Затримка — не більше 2 секунд.
Як працює автоматичний refresh токенів
Ми зберігаємо токени в таблиці `tg_bx24_tokens` з полем `expires_at`. За 5 хвилин до закінчення терміну сервер автоматично запитує новий токен через refresh_token. Якщо refresh_token теж прострочений, користувачеві пропонується пройти OAuth заново. Усі секрети шифруються.React Mini App: дашборд співробітника CRM
Фронтенд написаний на React з використанням Telegram WebApp SDK. Це дозволяє вбудувати інтерфейс у кнопку бота та використовувати нативні елементи керування (наприклад, гаптик-фідбек).
import { useEffect, useState } from 'react'; const tg = window.Telegram.WebApp; interface Deal { ID: string; TITLE: string; OPPORTUNITY: string; STAGE_ID: string; CONTACT_NAME: string; } function CrmDashboard() { const [deals, setDeals] = useState<Deal[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { tg.ready(); tg.expand(); loadDeals(); }, []); async function loadDeals() { const res = await fetch('/tg-api/crm/deals', { headers: { 'X-Tg-Init-Data': tg.initData }, }); const data = await res.json(); setDeals(data.deals); setLoading(false); } async function updateStage(dealId: string, stageId: string) { await fetch(`/tg-api/crm/deals/${dealId}/stage`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-Tg-Init-Data': tg.initData, }, body: JSON.stringify({ stage_id: stageId }), }); tg.HapticFeedback.notificationOccurred('success'); loadDeals(); } // ... рендер } На сервері — проксі-клас, який інкапсулює виклики до REST API. Він автоматично підставляє токен зі сховища та обробляє помилки авторизації:
class CrmDealsProxy { public function getDeals(int $tgUserId): array { $tokenData = TokenStorage::getValidToken($tgUserId); if (!$tokenData) { throw new \RuntimeException('Not authorized', 401); } $bx24 = new \Local\TgBx24\Bx24Client($tokenData['access_token'], $tokenData['domain']); $result = $bx24->call('crm.deal.list', [ 'filter' => ['ASSIGNED_BY_ID' => $tokenData['user_id'], 'CLOSED' => 'N'], 'select' => ['ID', 'TITLE', 'OPPORTUNITY', 'STAGE_ID', 'CONTACT_ID'], 'order' => ['DATE_MODIFY' => 'DESC'], 'start' => 0, ]); return $result['result'] ?? []; } public function updateDealStage(int $tgUserId, int $dealId, string $stageId): bool { $tokenData = TokenStorage::getValidToken($tgUserId); $bx24 = new \Local\TgBx24\Bx24Client($tokenData['access_token'], $tokenData['domain']); $result = $bx24->call('crm.deal.update', [ 'id' => $dealId, 'fields' => ['STAGE_ID' => $stageId], ]); return !empty($result['result']); } } Сповіщення через вебхуки подій
(вже описано вище)
Що входить у розробку
- Реєстрація додатку Бітрікс24 (OAuth), налаштування Mini App у @BotFather
- Сервер-посередник: валідація initData, зберігання та оновлення OAuth-токенів (PHP 8.1, MariaDB)
- React Mini App для обраного сценарію (дашборд угод, заявки, завдання)
- REST-проксі до Бітрікс24 API з автопродовженням токенів
- Вебхуки подій Бітрікс24 для сповіщень у Telegram
- Онбординг користувача: прив'язка облікового запису та тестовий запуск
- Документація з встановлення та підтримки
Терміни та вартість
- MVP для одного сценарію — від 3 до 5 тижнів
- Повнофункціональний додаток з кількома розділами — від 8 до 14 тижнів
Вартість розраховується індивідуально після аналізу технічного завдання. Надаємо гарантію 30 днів на працездатність інтеграції. Досвід — 10+ років, понад 50 інтеграцій із зовнішніми сервісами. Сертифіковані Бітрікс-розробники.
Зв'яжіться з нами для консультації — ми проведемо безкоштовний аудит вашої CRM та запропонуємо архітектуру, яка скоротить час реакції відділу продажів.







