Розробка 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 та запропонуємо архітектуру, яка скоротить час реакції відділу продажів.







