Разработка интеграции Битрикс24 через вебхуки
Самая частая жалоба на вебхук-интеграции с Битрикс24: «всё работало, а потом перестало». Причина почти всегда одна — обработчик стал отвечать медленнее 5 секунд, Битрикс24 перестал его вызывать, и никто этого не заметил, потому что логов не было. Построение надёжной интеграции на вебхуках требует понимания того, как Битрикс24 доставляет события и что происходит при сбоях.
Архитектура вебхук-интеграции
Вебхуки в Битрикс24 работают в двух направлениях:
Исходящий вебхук — Битрикс24 вызывает ваш URL при событии. Подписка настраивается в «Разработчикам → Исходящий вебхук» или через event.bind в REST API. Битрикс24 делает POST-запрос с Content-Type: application/x-www-form-urlencoded.
Входящий вебхук — ваша система вызывает Битрикс24 через фиксированный URL с токеном. Удобно для простых односторонних интеграций без OAuth.
Для двусторонней интеграции обычно используют оба типа: входящий — для отправки данных в Битрикс24, исходящий — для получения событий.
Подписка на события через API
Программная подписка надёжнее ручной настройки в интерфейсе — не зависит от действий администратора:
// Подписка через REST API (от имени OAuth-приложения)
$b24->call('event.bind', [
'event' => 'ONCRMDEALUPDATE',
'handler' => 'https://your-system.com/webhooks/bitrix24',
'auth_type' => 0, // 0 = текущий пользователь
]);
// Получить список активных подписок
$bindings = $b24->call('event.get');
// Отписаться
$b24->call('event.unbind', [
'event' => 'ONCRMDEALUPDATE',
'handler' => 'https://your-system.com/webhooks/bitrix24',
]);
Структура входящего запроса
Тело POST-запроса от Битрикс24:
event=ONCRMDEALUPDATE
&event_handler_id=42
&auth[access_token]=abc123
&auth[expires]=1700000000
&auth[member_id]=a1b2c3
&auth[domain]=company.bitrix24.ru
&auth[application_token]=xyz789
&data[FIELDS][ID]=456
&data[FIELDS][STAGE_ID]=EXECUTING
&data[FIELDS][OPPORTUNITY]=150000
Важно: data[FIELDS] содержит только изменённые поля, а не полный объект. Для получения актуального состояния сделки нужен отдельный вызов crm.deal.get.
auth[application_token] — токен для верификации источника запроса. Для коробочного Битрикс24 проверяем его совпадение с токеном приложения.
Обязательный паттерн: немедленный ответ + очередь
Ключевое требование: обработчик должен вернуть HTTP 200 в течение 5 секунд. Всё, что дольше — таймаут, событие считается недоставленным.
// routes/api.php (Laravel)
Route::post('/webhooks/bitrix24', function (Request $request) {
// Валидация токена — быстро
if (!validateBitrixToken($request->input('auth.application_token'))) {
return response('Forbidden', 403);
}
// Кладём в очередь — быстро
ProcessBitrixEvent::dispatch($request->all());
// Немедленно отвечаем
return response('OK', 200);
});
// app/Jobs/ProcessBitrixEvent.php
class ProcessBitrixEvent implements ShouldQueue
{
public $tries = 3;
public $backoff = [60, 300, 900]; // 1 мин, 5 мин, 15 мин
public function handle(): void
{
$event = $this->payload['event'];
$dealId = $this->payload['data']['FIELDS']['ID'];
// Теперь получаем полный объект
$deal = $this->b24->call('crm.deal.get', ['id' => $dealId]);
// ... обработка
}
}
Идемпотентность обработчика
Одно событие может прийти дважды: Битрикс24 повторяет вызов при сетевых проблемах, а массовые операции генерируют ONCRMDEALUPDATE на каждое поле. Обработчик должен быть идемпотентным:
// Дедупликация через event_handler_id + временная метка
$eventKey = md5($event . $dealId . $request->input('ts'));
if ($redis->set("processed:{$eventKey}", 1, ['NX', 'EX' => 3600])) {
ProcessBitrixEvent::dispatch($payload);
// Если ключ уже есть — дубль, игнорируем
}
Цепочки событий и петли синхронизации
Классическая проблема: внешняя система получает событие ONCRMDEALUPDATE, обновляет данные в своей БД, затем отправляет обновление обратно в Битрикс24 — это снова генерирует ONCRMDEALUPDATE, и цикл повторяется бесконечно.
Решения:
- Флаг в сделке: устанавливаем кастомное поле
UF_CRM_SYNC_LOCK=Yперед записью из внешней системы, проверяем его в обработчике — еслиY, пропускаем и сбрасываем флаг - Хэш данных: сравниваем хэш входящих данных с последним обработанным — если совпадает, пропускаем
- Временная метка: если событие о нашем же обновлении (время ≤ 2 сек с момента нашей записи) — игнорируем
Мониторинг доставки
Битрикс24 не ведёт журнал доставки вебхуков для внешних получателей. Нужно вести его самостоятельно:
CREATE TABLE webhook_events (
id SERIAL PRIMARY KEY,
event_type VARCHAR(64),
entity_id INTEGER,
received_at TIMESTAMP DEFAULT NOW(),
processed_at TIMESTAMP,
status VARCHAR(16) DEFAULT 'pending', -- pending/done/error
error_message TEXT
);
Алерт: если за 10 минут нет ни одного события ONCRMDEALUPDATE в рабочее время — скорее всего, Битрикс24 перестал вызывать обработчик.
Ограничения по событиям
| Событие | Особенности |
|---|---|
ONCRMDEALUPDATE |
Вызывается при каждом изменении любого поля |
ONCRMDEALADD |
Не срабатывает при импорте через API с DISABLE_PORTAL_ACTIVITY=Y |
ONVOXIMPLANTCALLEND |
Данные записи звонка доступны с задержкой 5–30 сек |
ONTASKUPDATE |
Не включает изменения чеклистов |
ONIMBOTMESSAGEADD |
Только для ботов, зарегистрированных через imbot.register |
Коробочный Битрикс24: расширение событий
На коробке доступны события PHP-уровня, которых нет в REST API:
// Событие до сохранения сделки — можно изменить данные
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'crm', 'OnBeforeCrmDealAdd',
[MyHandler::class, 'onBeforeDealAdd']
);
// Своё событие из модуля
$event = new \Bitrix\Main\Event('my_module', 'OnSomethingHappened', ['data' => $data]);
$event->send();
Этапы разработки
| Этап | Содержание | Срок |
|---|---|---|
| Проектирование | Список событий, схема данных, архитектура обработчика | 2–3 дня |
| Endpoint и очередь | HTTP-обработчик, Job, дедупликация | 3–5 дней |
| Бизнес-логика | Обработка каждого типа события, вызов внешних систем | 1–3 недели |
| Защита от петель | Флаги синхронизации, idempotency | 2–3 дня |
| Мониторинг | Журнал событий, алерты, дашборд | 2–3 дня |
| Тестирование | Эмуляция событий, нагрузочные тесты | 3–5 дней |
Суммарно: 3–7 недель в зависимости от количества событий и сложности бизнес-логики.







