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







