Bitrix24-Яндекс.Трекер integration: we bridge the gap between developers and managers
Typical situation: developers live in Yandex Tracker, while managers handle client deals in Bitrix24. A task is created in Tracker — the manager doesn't see its current status. A status changes in Bitrix24 — the developer learns about it through third parties. Manual transfer eats up hours daily and invites errors. Consider a typical IT company: the development team uses Yandex Tracker for task management, while the sales department works in Bitrix24. When aligning tasks, a disconnect occurs — statuses are not synchronized, information becomes stale within an hour. Our integration eliminates this gap automatically, reducing error probability and speeding up task completion. We've already implemented such solutions for clients across various industries, including companies with hundreds of employees. We offer a turnkey integration — from design to post-launch support. Get in touch to pinpoint your case.
What problems does the integration solve?
Manual task transfer. Employees spend 30–60 minutes daily copying titles and statuses between systems. Our script automates this completely.
Loss of timeliness. Information becomes stale within an hour — the manager sees "In progress" while the task is already closed. Real-time synchronization eliminates the delay.
Status conflict. Bitrix24 has one status model, Tracker has another. A clear mapping is needed, otherwise synchronization causes confusion.
How we do it: stack and architecture
Yandex Tracker API: key methods
Tracker provides a REST API with OAuth 2.0 authentication. The organization token is passed in the header of each request. Base URL: https://api.tracker.yandex.net/v3/. Main endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /issues/ |
Create issue |
| PATCH | /issues/{issueKey} |
Update issue |
| GET | /issues/{issueKey} |
Get issue |
| POST | /issues/{issueKey}/transitions/{id}/_execute |
Change status |
| GET | /issues/{issueKey}/comments |
Task comments |
| POST | /issues/{issueKey}/comments |
Add comment |
For webhooks, triggers are used — configured in the Tracker interface at the queue level.
Integration architecture
The integration is bidirectional, so loops must be avoided. The solution: an "update from integration" flag (lock mechanism).
Task mapping table:
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 текущей операции
];
}
}
Synchronization Bitrix24 → Yandex Tracker
We use the OnTaskUpdate event from the tasks module:
// /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());
}
}
}
Registering the handler:
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'tasks', 'OnTaskUpdate', [\Local\TrackerIntegration\Handlers\TaskHandler::class, 'onTaskUpdate']
);
Webhook from Yandex Tracker → Bitrix24
The webhook handler is a controller accessible via a public URL. In Tracker, a trigger is configured: "When status changes → POST to 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]);
Status mapping
Statuses in the two systems don't match — a correspondence table is needed:
| Bitrix24 (STATUS) | Yandex Tracker (key) |
|---|---|
| 1 (New) | open |
| 2 (Accepted) | inProgress |
| 3 (In progress) | inProgress |
| 4 (Awaiting control) | needInfo |
| 5 (Completed) | closed |
| 7 (Deferred) | onHold |
The mapping is stored in a configuration file or in b_option.
How to avoid loops in bidirectional synchronization?
In bidirectional sync, a lock mechanism is critical to prevent endless loops. When the OnTaskUpdate handler receives an event, it checks the SYNC_LOCK field in the mapping table. If SYNC_LOCK is not null, it means the change is already being processed by the other side — the handler exits without execution. This approach works faster and more reliably than timestamp checks because it eliminates race conditions during parallel requests. According to the official Bitrix24 documentation, the OnTaskUpdate event is triggered on any task change, so without a lock mechanism, synchronization would quickly loop. Our implementation guarantees that each update is processed exactly once.
Creating a task in Tracker from a Bitrix24 deal
An additional scenario: when a deal of a certain type is created, automatically create a task in Tracker. Implemented via a business process or through the onCrmDealAdd event handler:
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'],
]);
// Save mapping
TrackerBitrix24TaskTable::add([
'BITRIX_TASK_ID' => 0, // No task, only deal
'TRACKER_ISSUE_KEY' => $issue['key'],
'SYNC_DIRECTION' => 'BIDIRECTIONAL',
]);
// Write the task key to the deal custom field
\CCrmDeal::Update($dealId, ['UF_TRACKER_ISSUE_KEY' => $issue['key']], false);
}
Process of work
- Analysis — we study current business processes, identify entities to synchronize.
- Design — we design architecture, mapping table, lock mechanism.
- Implementation — we write code in PHP 8.1+, using Bitrix24 ORM and Tracker REST API.
- Testing — we check synchronization on test tasks, simulate conflicts.
- Deployment — we deploy to production, set up monitoring.
- Support — after launch, we provide warranty support and documentation.
Estimated timelines
| Option | Scope | Timeline |
|---|---|---|
| One-way synchronization | Bitrix24 → Tracker or vice versa | from 4 to 6 days |
| Two-way synchronization | Tasks, statuses, comments | from 8 to 12 days |
| Full integration | + Auto-creation from deals, user mapping | from 12 to 16 days |
Cost is calculated individually — depends on complexity and volume of work. To get a precise estimate, contact us.
Why choose our integration?
Integration via REST API and webhooks works stably without loading the server. We use tagged cache and agents for background tasks. Our engineers have over 8 years of experience in Bitrix24 development. Automatic synchronization completes in seconds, whereas manual transfer takes up to 30–60 minutes daily — our integration speeds up work by 50 times. We guarantee correct operation after launch and provide documented solutions.
What's included in the work
- Documentation for setup and operation.
- Access to the code repository.
- Employee training (1 hour online).
- Support for 30 days after launch.
- Option for modifications under new scenarios.
Order integration — our engineers will analyze your processes and offer the optimal solution. Get a consultation right now by describing your task.







