Как встроить виджет во вкладку карточки CRM

Scope: placement, crm

Кто может выполнять методы:

  • placement.bind — администратор
  • crm.item.get — любой пользователь с правом чтения сделки

Выберите инструмент для разработки с AI-агентом:

  • используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
  • используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации

Вкладка в карточке CRM позволяет показать интерфейс приложения рядом с основными данными элемента. В этом сценарии добавим вкладку в карточку сделки, получим идентификатор открытой сделки и запросим ее данные.

Для сценария последовательно выполним методы:

  1. placement.bind — зарегистрируем обработчик для вкладки CRM_DEAL_DETAIL_TAB
  2. crm.item.get — получим данные сделки по идентификатору из PLACEMENT_OPTIONS

Исходный пример и дополнительные материалы доступны в уроке Встройка в карточку CRM.

Как работает сценарий

Приложение регистрирует URL обработчика методом placement.bind и указывает код CRM_DEAL_DETAIL_TAB. После завершения установки приложения в карточке сделки появляется новая вкладка.

Когда пользователь открывает вкладку, Битрикс24 загружает обработчик в iframe и передает ему контекст вызова. В PLACEMENT_OPTIONS.ID приходит идентификатор текущей сделки. Обработчик передает этот идентификатор в crm.item.get и показывает полученные данные.

1. Подготовьте приложение

Создайте приложение с интерфейсом и добавьте ему права:

  • placement — для регистрации обработчика виджета
  • crm — для получения данных сделки

Код регистрации и обработчик вкладки можно разместить в отдельных файлах или объединить в одном файле с разными ветками выполнения.

Разместите страницу обработчика по публичному HTTPS-адресу. В примерах используется адрес:

https://your-domain.example/deal-tab.php

Сервер должен разрешать открытие страницы в iframe. Проверьте заголовок X-Frame-Options и директиву frame-ancestors заголовка Content-Security-Policy: они не должны запрещать встраивание страницы в Битрикс24.

URL обработчика должен быть доступен из внешней сети. Не используйте localhost, адреса локальной сети и самоподписанные SSL-сертификаты.

Метод placement.bind работает только в контексте приложения. Входящий вебхук для регистрации вкладки не подходит.

2. Зарегистрируйте вкладку

Зарегистрируем обработчик методом placement.bind. Передадим параметры:

  • PLACEMENT — код места встраивания CRM_DEAL_DETAIL_TAB
  • HANDLER — публичный URL страницы, которая откроется во вкладке
  • TITLE — название вкладки
  • LANG_ALL — локализованные названия вкладки

Как использовать примеры в документации

// npm install @bitrix24/b24jssdk
// Страница настроек приложения, открытая в iframe Битрикс24
import { initializeB24Frame } from '@bitrix24/b24jssdk'

const $b24 = await initializeB24Frame()

const response = await $b24.actions.v2.call.make({
    method: 'placement.bind',
    params: {
        PLACEMENT: 'CRM_DEAL_DETAIL_TAB',
        HANDLER: 'https://your-domain.example/deal-tab.php',
        TITLE: 'Deal data',
        LANG_ALL: {
            ru: {
                TITLE: 'Данные сделки',
            },
            en: {
                TITLE: 'Deal data',
            },
        },
    },
    requestId: 'placement-bind',
})

if (!response.isSuccess) {
    throw new Error(response.getErrorMessages().join('; '))
}

console.info('Вкладка зарегистрирована')
# pip install b24pysdk
# client построен на токене приложения — см. сценарий
# «Как встроить виджет в лид в виде пользовательского поля»
from b24pysdk.errors import BitrixAPIError

try:
    bitrix_response = client.placement.bind(
        placement="CRM_DEAL_DETAIL_TAB",
        handler="https://your-domain.example/deal-tab.php",
        title="Deal data",
        lang_all={
            "ru": {"TITLE": "Данные сделки"},
            "en": {"TITLE": "Deal data"},
        },
    ).response
    print("Вкладка зарегистрирована:", bitrix_response.result)
except BitrixAPIError as error:
    print(error)
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';

use Bitrix24\SDK\Core\Exceptions\BaseException;

// $b24 построен на токене приложения — см. сценарий
// «Как встроить виджет в лид в виде пользовательского поля»
try
{
    $b24->getPlacementScope()->placement()->bind(
        'CRM_DEAL_DETAIL_TAB',
        'https://your-domain.example/deal-tab.php',
        [
            'ru' => ['TITLE' => 'Данные сделки'],
            'en' => ['TITLE' => 'Deal data'],
        ]
    );

    echo 'Вкладка зарегистрирована';
}
catch (BaseException $exception)
{
    echo $exception->getMessage();
}

Если обработчик успешно зарегистрирован, метод вернет true.

{
    "result": true
}

После регистрации завершите установку приложения. Пока установка не завершена, вкладка недоступна обычным пользователям.

3. Обработайте открытие вкладки

При открытии вкладки Битрикс24 передает обработчику данные POST-запросом. Для карточки сделки основные параметры выглядят так:

PLACEMENT=CRM_DEAL_DETAIL_TAB
PLACEMENT_OPTIONS={"ID":"3473"}

PLACEMENT_OPTIONS передается как JSON-строка. В PHP и Python преобразуйте ее в массив или словарь — например, функцией json_decode или json.loads. В B24JsSDK свойство $b24.placement.options возвращает готовый объект, а $b24.placement.placement — код места встраивания.

Параметр
тип

Описание

PLACEMENT
string

Код места встраивания. Для вкладки сделки приходит CRM_DEAL_DETAIL_TAB

PLACEMENT_OPTIONS
string

JSON-строка с контекстом открытой карточки

ID
string

Идентификатор сделки внутри PLACEMENT_OPTIONS

DOMAIN
string

Адрес Битрикс24, в котором пользователь открыл вкладку

PROTOCOL
string

Протокол для обращения к Битрикс24: 0 — HTTP, 1 — HTTPS

AUTH_ID
string

OAuth-токен пользователя, который открыл вкладку. PHP-обработчик использует токен для вызова crm.item.get с правами этого пользователя

Полный набор служебных параметров запроса описан на странице вкладки в карточке CRM.

4. Получите данные сделки

Вызовем crm.item.get из обработчика. Для сделки передадим:

  • entityTypeId: 2 — идентификатор типа объекта CRM «Сделка»
  • id — идентификатор из PLACEMENT_OPTIONS.ID

Метод выполняется с авторизацией пользователя, который открыл вкладку:

  • JS работает внутри iframe — initializeB24Frame берет авторизацию из контекста вкладки
  • PHP и Python строят клиент на данных запроса, которые Битрикс24 передает обработчику, включая токен AUTH_ID
<!DOCTYPE html>
<html lang="ru">
    <head>
        <meta charset="UTF-8">
        <title>Данные сделки</title>
    </head>
    <body>
        <h2 id="deal-title">Загрузка данных сделки</h2>
        <div id="deal-stage"></div>

        <script type="module">
            // npm install @bitrix24/b24jssdk
            import { initializeB24Frame } from '@bitrix24/b24jssdk'

            const $b24 = await initializeB24Frame()

            const dealId = Number($b24.placement.options.ID)

            if (
                $b24.placement.placement !== 'CRM_DEAL_DETAIL_TAB'
                || !Number.isInteger(dealId)
                || dealId <= 0
            ) {
                document.getElementById('deal-title').textContent =
                    'Не удалось определить сделку'
            } else {
                const response = await $b24.actions.v2.call.make({
                    method: 'crm.item.get',
                    params: {
                        entityTypeId: 2,
                        id: dealId,
                    },
                    requestId: 'deal-get',
                })

                if (!response.isSuccess) {
                    document.getElementById('deal-title').textContent =
                        response.getErrorMessages().join('; ')
                } else {
                    const deal = response.getData().result.item

                    document.getElementById('deal-title').textContent =
                        deal.title || 'Сделка без названия'
                    document.getElementById('deal-stage').textContent =
                        'Стадия: ' + deal.stageId
                }
            }
        </script>
    </body>
</html>
# pip install b24pysdk flask
from flask import Flask, request
from b24pysdk import BitrixApp, BitrixToken, Client
from b24pysdk.errors import BitrixAPIError
import json

app = Flask(__name__)

bitrix_app = BitrixApp(
    client_id="local.xxxxxxxx.xxxxxxxx",
    client_secret="yyyyyyyy",
)


@app.post("/deal-tab")
def deal_tab():
    placement = request.form.get("PLACEMENT", "")
    options = json.loads(request.form.get("PLACEMENT_OPTIONS", "{}") or "{}")
    deal_id = int(options.get("ID", 0))

    if placement != "CRM_DEAL_DETAIL_TAB" or deal_id <= 0:
        return "Не удалось получить контекст вызова"

    # Битрикс24 передает обработчику домен и токен пользователя
    client = Client(
        BitrixToken(
            domain=request.args.get("DOMAIN", ""),
            auth_token=request.form.get("AUTH_ID", ""),
            bitrix_app=bitrix_app,
        )
    )

    try:
        deal = client.crm.item.get(
            entity_type_id=2,
            bitrix_id=deal_id,
        ).response.result["item"]
    except BitrixAPIError as error:
        return str(error)

    return f"{deal.get('title', 'Сделка без названия')} — стадия: {deal.get('stageId', '')}"
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';

use Bitrix24\SDK\Core\Credentials\ApplicationProfile;
use Bitrix24\SDK\Core\Exceptions\BaseException;
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();

$placement = (string)$request->request->get('PLACEMENT', '');
$placementOptions = json_decode(
    (string)$request->request->get('PLACEMENT_OPTIONS', '[]'),
    true
) ?: [];
$dealId = (int)($placementOptions['ID'] ?? 0);

$error = '';
$deal = null;

if ($placement !== 'CRM_DEAL_DETAIL_TAB' || $dealId <= 0)
{
    $error = 'Не удалось получить контекст вызова';
}
else
{
    $appProfile = ApplicationProfile::initFromArray([
        'BITRIX24_PHP_SDK_APPLICATION_CLIENT_ID' => 'local.xxxxxxxx.xxxxxxxx',
        'BITRIX24_PHP_SDK_APPLICATION_CLIENT_SECRET' => 'yyyyyyyy',
        'BITRIX24_PHP_SDK_APPLICATION_SCOPE' => 'crm,placement',
    ]);

    try
    {
        // SDK сам возьмет DOMAIN и AUTH_ID из запроса встройки
        $b24 = ServiceBuilderFactory::createServiceBuilderFromPlacementRequest(
            $request,
            $appProfile
        );

        $deal = $b24->getCRMScope()->item()->get(2, $dealId)->item();
    }
    catch (BaseException $exception)
    {
        $error = $exception->getMessage();
    }
}
?>
<!DOCTYPE html>
<html lang="ru">
    <head>
        <meta charset="UTF-8">
        <title>Данные сделки</title>
    </head>
    <body>
        <?php if ($error !== ''): ?>
            <p><?=htmlspecialchars($error)?></p>
        <?php else: ?>
            <h2><?=htmlspecialchars($deal->title ?? 'Сделка без названия')?></h2>
            <p>Стадия: <?=htmlspecialchars($deal->stageId ?? '')?></p>
        <?php endif; ?>
    </body>
</html>

Метод вернет объект item с данными сделки, доступными пользователю, чья авторизация используется в запросе.

{
    "result": {
        "item": {
            "id": 3473,
            "title": "Подготовка предложения",
            "stageId": "NEW"
        }
    }
}

Идентификатор из PLACEMENT_OPTIONS можно использовать и для других действий: получить связанные контакты и компанию, запросить данные во внешней системе или показать собственный интерфейс работы со сделкой.

5. Проверьте виджет

  1. Установите приложение в тестовый Битрикс24
  2. Убедитесь, что установка приложения завершена
  3. Откройте раздел CRM
  4. Откройте любую сделку
  5. Найдите вкладку Данные сделки
  6. Проверьте, что обработчик показывает название и стадию открытой сделки

Если вкладка не появилась, проверьте регистрацию обработчика методом placement.get. В ответе должны быть код CRM_DEAL_DETAIL_TAB и URL страницы обработчика.

Другие карточки CRM

По тому же сценарию можно добавить вкладку в карточки других объектов. Замените код в PLACEMENT и укажите соответствующий entityTypeId в crm.item.get.

Объект CRM

PLACEMENT

entityTypeId

Лид

CRM_LEAD_DETAIL_TAB

1

Сделка

CRM_DEAL_DETAIL_TAB

2

Контакт

CRM_CONTACT_DETAIL_TAB

3

Компания

CRM_COMPANY_DETAIL_TAB

4

Счет

CRM_SMART_INVOICE_DETAIL_TAB

31

Коды для коммерческих предложений и смарт-процессов смотрите в описании точки CRM_XXX_DETAIL_TAB.

Продолжите изучение