Разработка интеграции Битрикс24 с Яндекс.Трекер
Типичная боль: разработчики живут в Яндекс.Трекере, менеджеры ведут задачи в Битрикс24, и между системами — ручной перенос. Задача создана в Трекере, но менеджер не видит её статус в Битрикс24. Статус поменялся в Битрикс24 — разработчик не знает. Интеграция устраняет этот разрыв: изменения в одной системе автоматически отражаются в другой.
Яндекс.Трекер API: ключевые методы
Трекер предоставляет REST API с OAuth 2.0-аутентификацией. Токен организации (X-Cloud-Org-ID или X-Org-ID) передаётся в заголовке каждого запроса.
Базовый URL: https://api.tracker.yandex.net/v3/.
Основные эндпоинты:
| Метод | Эндпоинт | Назначение |
|---|---|---|
| POST | /issues/ |
Создать задачу |
| PATCH | /issues/{issueKey} |
Обновить задачу |
| GET | /issues/{issueKey} |
Получить задачу |
| POST | /issues/{issueKey}/transitions/{id}/_execute |
Сменить статус |
| GET | /issues/{issueKey}/comments |
Комментарии к задаче |
| POST | /issues/{issueKey}/comments |
Добавить комментарий |
Для webhook'ов Трекер использует триггеры — настраиваются в интерфейсе Трекера на уровне очереди. Триггер срабатывает при изменении задачи и делает POST-запрос на указанный URL.
Архитектура интеграции
Интеграция двусторонняя, поэтому нужно избегать петель: изменение в Битрикс24 → Трекер → webhook → снова Битрикс24. Решение — флаг «обновление из интеграции» (lock-механизм).
Таблица маппинга задач:
class TrackerBitrix24TaskTable extends \Bitrix\Main\ORM\Data\DataManager
{
public static function getTableName(): string
{
return 'b_local_tracker_task_map';
}
public static function getMap(): array
{
return [
new IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new IntegerField('BITRIX_TASK_ID'), // ID задачи в Битрикс24
new StringField('TRACKER_ISSUE_KEY'), // Например, "DEV-123"
new StringField('SYNC_DIRECTION'), // B24_TO_TRACKER | TRACKER_TO_B24 | BIDIRECTIONAL
new DatetimeField('LAST_SYNC_AT'),
new StringField('SYNC_LOCK'), // NULL или UUID текущей операции
];
}
}
Синхронизация Битрикс24 → Яндекс.Трекер
Используем событие OnTaskUpdate модуля tasks:
// /local/modules/local.trackerintegration/lib/handlers/taskhandler.php
namespace Local\TrackerIntegration\Handlers;
class TaskHandler
{
public static function onTaskUpdate(int $taskId, array $arFields): void
{
$map = TrackerBitrix24TaskTable::getByBitrixId($taskId);
if (!$map || $map['SYNC_LOCK'] !== null) {
return; // Нет маппинга или уже синхронизируем
}
// Ставим лок
TrackerBitrix24TaskTable::update($map['ID'], ['SYNC_LOCK' => uniqid()]);
try {
$client = new TrackerApiClient();
$payload = [];
if (isset($arFields['TITLE'])) {
$payload['summary'] = $arFields['TITLE'];
}
if (isset($arFields['DESCRIPTION'])) {
$payload['description'] = $arFields['DESCRIPTION'];
}
if (isset($arFields['STATUS'])) {
// Маппинг статусов Битрикс24 → Трекер
$trackerStatus = StatusMapper::b24ToTracker($arFields['STATUS']);
$client->executeTransition($map['TRACKER_ISSUE_KEY'], $trackerStatus);
}
if (!empty($payload)) {
$client->updateIssue($map['TRACKER_ISSUE_KEY'], $payload);
}
TrackerBitrix24TaskTable::update($map['ID'], [
'SYNC_LOCK' => null,
'LAST_SYNC_AT' => new \Bitrix\Main\Type\DateTime(),
]);
} catch (\Exception $e) {
TrackerBitrix24TaskTable::update($map['ID'], ['SYNC_LOCK' => null]);
\Bitrix\Main\Diag\Debug::addToLog('TrackerSync error: ' . $e->getMessage());
}
}
}
Регистрация обработчика в RegisterModuleDependences:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'tasks', 'OnTaskUpdate', [\Local\TrackerIntegration\Handlers\TaskHandler::class, 'onTaskUpdate']
);
Webhook из Яндекс.Трекера → Битрикс24
Обработчик webhook'а — контроллер, доступный по публичному URL. В Трекере настраивается триггер: «При изменении статуса → POST на https://company.bitrix24.ru/local/tracker/webhook/`.
// /local/tracker/webhook/index.php
$rawBody = file_get_contents('php://input');
$event = json_decode($rawBody, true);
// Проверяем secret-заголовок (задаётся в настройках триггера Трекера)
$secret = $_SERVER['HTTP_X_TRACKER_SECRET'] ?? '';
if ($secret !== TRACKER_WEBHOOK_SECRET) {
http_response_code(403);
exit;
}
$issueKey = $event['issue']['key'] ?? null;
$newStatus = $event['updatedAttributes']['status']['to']['key'] ?? null;
if (!$issueKey || !$newStatus) {
http_response_code(200);
exit;
}
$map = TrackerBitrix24TaskTable::getByTrackerKey($issueKey);
if (!$map || $map['SYNC_LOCK'] !== null) {
http_response_code(200);
exit;
}
TrackerBitrix24TaskTable::update($map['ID'], ['SYNC_LOCK' => uniqid()]);
$b24Status = StatusMapper::trackerToB24($newStatus);
$task = new \CTasks();
$task->Update($map['BITRIX_TASK_ID'], ['STATUS' => $b24Status], false);
TrackerBitrix24TaskTable::update($map['ID'], ['SYNC_LOCK' => null, 'LAST_SYNC_AT' => new \Bitrix\Main\Type\DateTime()]);
http_response_code(200);
echo json_encode(['ok' => true]);
Маппинг статусов
Статусы в двух системах не совпадают — нужна таблица соответствий:
| Битрикс24 (STATUS) | Яндекс.Трекер (key) |
|---|---|
| 1 (Новая) | open |
| 2 (Принята) | inProgress |
| 3 (В работе) | inProgress |
| 4 (Ждёт контроля) | needInfo |
| 5 (Завершена) | closed |
| 7 (Отложена) | onHold |
Маппинг — конфигурационный файл или запись в таблице b_option через \COption::SetOptionString('local.trackerintegration', 'status_map', json_encode($map)).
Создание задачи в Трекере из сделки Битрикс24
Дополнительный сценарий — при создании сделки определённого типа автоматически создавать задачу в Трекере. Реализуется через бизнес-процесс в CRM или через обработчик события onCrmDealAdd.
public static function onCrmDealAdd(int $dealId, array $arFields): void
{
if ($arFields['TYPE_ID'] !== 'DEVELOPMENT') {
return;
}
$client = new TrackerApiClient();
$issue = $client->createIssue([
'queue' => 'DEV',
'summary' => 'CRM Deal #' . $dealId . ': ' . $arFields['TITLE'],
'type' => 'task',
'assignee' => UserMapper::b24ToTracker($arFields['ASSIGNED_BY_ID']),
'tags' => ['crm', 'auto-created'],
]);
// Сохранить маппинг
TrackerBitrix24TaskTable::add([
'BITRIX_TASK_ID' => 0, // Нет задачи, только сделка
'TRACKER_ISSUE_KEY' => $issue['key'],
'SYNC_DIRECTION' => 'BIDIRECTIONAL',
]);
// Записать ключ задачи в поле сделки
\CCrmDeal::Update($dealId, ['UF_TRACKER_ISSUE_KEY' => $issue['key']], false);
}
Сроки разработки
| Вариант | Состав | Срок |
|---|---|---|
| Односторонняя синхронизация | Битрикс24 → Трекер или наоборот | 4–6 дней |
| Двусторонняя синхронизация | Задачи, статусы, комментарии | 8–12 дней |
| Полная интеграция | + Автосоздание из сделок, маппинг пользователей | 12–16 дней |







