Розробка Telegram Mini App з інтеграцією Бітрікс24

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Послуги, які ми пропонуємо
Показано 1 з 1Усі 1626 послуг
Розробка Telegram Mini App з інтеграцією Бітрікс24
Середній
~1-2 тижні
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1273
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Розробка веб-сайту для компанії ФІКСПЕР
    865
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    602
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    762
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    667
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    1000

Розробка Telegram Mini App з інтеграцією Бітрікс24

Інтеграція Telegram Mini App з Бітрікс24 відрізняється від інтеграції з 1С-Бітрікс тим, що основний транспорт тут — REST API Бітрікс24, а не кастомні PHP-ендпоінти. Бітрікс24 надає повноцінний REST з OAuth, вебхуками та подіями. Типовий сценарій: корпоративний міні-портал або CRM-інструмент прямо в Telegram — співробітник може прийняти лід, змінити статус угоди, переглянути завдання, не відкриваючи браузер.

Сценарії використання

Найпопулярніші кейси:

  • Мобільний CRM-дашборд — перегляд лідів/угод, зміна статусу, додавання коментаря прямо з Telegram
  • Корпоративне замовлення — співробітники зовнішньої мережі (дилери, агенти) оформлюють заявки через Mini App, заявки потрапляють у Бітрікс24 CRM
  • Self-service портал — клієнт бачить статус своїх заявок, історію звернень
  • Таск-менеджер — список завдань співробітника, зміна статусу, додавання файлів

Авторизація: OAuth Бітрікс24 з Mini App

Бітрікс24 REST API вимагає OAuth 2.0 access_token. З Mini App прямий OAuth flow ускладнений (немає браузерних редиректів), тому авторизацію реалізуємо через посередника.

Схема:

Telegram → Mini App відкривається
  → Mini App передає initData на наш сервер-посередник
    → Сервер валідує initData, визначає Telegram user_id
      → Шукає прив'язаний access_token Бітрікс24 для цього user_id
        → Якщо є → повертає JWT для Mini App
        → Якщо немає → повертає посилання на OAuth-авторизацію в Бітрікс24

Первинне прив'язування Telegram ↔ Бітрікс24:

// Контролер OAuth callback
class Bx24OAuthController
{
    public function callback(Request $request): Response
    {
        $code     = $request->get('code');
        $tgUserId = $request->session()->get('pending_tg_user_id');

        // Обмінюємо code на токен
        $tokenData = $this->exchangeCode($code);

        // Зберігаємо токен із прив'язкою до Telegram user_id
        \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:

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: дашборд співробітника 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();
    }

    // ... рендер
}

Серверний проксі до Бітрікс24 REST:

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

Для сповіщень використовуємо вебхуки подій Бітрікс24. Наприклад, при зміні статусу ліда — надсилаємо повідомлення відповідальному:

// Обробник вхідної події від Бітрікс24
class EventHandler
{
    public function handleLeadUpdate(array $event): void
    {
        $leadId   = $event['data']['FIELDS_AFTER']['ID'];
        $assignee = $event['data']['FIELDS_AFTER']['ASSIGNED_BY_ID'];

        // Шукаємо tg_user_id за bx24 user_id
        $tgUserId = $this->findTelegramUser($assignee);
        if (!$tgUserId) return;

        $statusName = $this->getLeadStatusName($event['data']['FIELDS_AFTER']['STATUS_ID']);

        $this->bot->sendMessage($tgUserId,
            "Лід #{$leadId} змінено\nНовий статус: {$statusName}\n" .
            "[Відкрити в Mini App](https://t.me/" . BOT_USERNAME . "/crm?start=lead_{$leadId})",
            ['parse_mode' => 'Markdown']
        );
    }
}

Склад робіт

  • Реєстрація застосунку Бітрікс24 (OAuth), налаштування Mini App у @BotFather
  • Сервер-посередник: валідація Telegram initData, зберігання OAuth-токенів
  • React Mini App: обирається під конкретний сценарій (CRM / завдання / заявки)
  • REST-проксі до Бітрікс24 API з оновленням токенів
  • Вебхуки подій Бітрікс24 → сповіщення в Telegram
  • Первинне налаштування: онбординг користувача, прив'язка акаунту

Терміни: MVP під один сценарій (наприклад, дашборд угод) — 3–5 тижнів. Повнофункціональний інструмент із кількома розділами — 8–14 тижнів.