Клиентская форма на сайте, заявка улетела, менеджер её увидел. Звучит как что-то, что работает само собой, но каждый раз, когда я прихожу на новый проект, картина одна: лиды падают в почту, менеджер раз в пару часов просматривает ящик, часть писем попадает в спам, а «мы вам перезвоним» до клиента так и не доезжает.
Раньше я решал это плагинами. Для WordPress есть с полдюжины плагинов интеграции с Битрикс24, и они работают. Пока не начинает хотеться странного: передать в CRM свои поля, пометить лид источником, создать не лид, а сделку сразу с контактом, или вообще завести задачу в другом портале. Тут начинается изучение настроек плагина через лупу, и обычно выясняется, что «так нельзя, только так как задумал разработчик».
Где-то три года назад я для таких задач перестал тянуть плагины и просто пишу 20–40 строк PHP. Сайт дергает REST API Битрикс24 напрямую, я контролирую каждое поле, а обновления плагинов перестали быть статьей риска. Ниже — как это устроено в 2026 году, какие лимиты надо знать заранее и где люди обычно наступают на грабли.
Вебхук или приложение
В Битрикс24 есть два способа работать с REST без маркетплейса: входящий и исходящий вебхуки. Официальная документация (apidocs.bitrix24.ru) позиционирует их как инструмент локальных интеграций, то есть для связки одного конкретного портала с вашими сервисами.
Выбор на самом деле простой:
- Входящий вебхук — ваш сайт или скрипт вызывает методы REST API Битрикс24 по готовому URL. Это 90% задач типа «передать лид из формы».
- Исходящий вебхук — Битрикс24 сам сообщает вашему сервису о событии: сделка сменила стадию, пришло письмо, создан контакт. Ваш обработчик получает POST с данными события.
- Полноценное приложение с OAuth нужно, когда интеграция едет на десятки чужих порталов или попадает в Маркет маркетплейса. Для своего сайта оно избыточно: вместо него вы получаете регистрацию, токены с протуханием и URL обратного вызова.
Я исхожу из правила: если интеграция живет внутри одной компании и её пользователь — вы сами, хватит вебхуков. Ошибиться с этим выбором почти невозможно, а переделать входящий вебхук в приложение потом недолго.
Входящий вебхук: пять минут до рабочего лида
Создается он в разделе Разработчикам → Другое → Входящий вебхук. На шаге настройки вы выбираете права (scope): для лидов достаточно crm, для задач добавится tasks и так далее. Важная деталь, о которой часто забывают: вебхук выполняет запросы от имени сотрудника, который его создал. Если создать его под администратором с полными правами, а утекёт он в логи сайта, отдавать кому-то всю CRM целиком.
После создания вы получаете URL вида:
https://company.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/crm.lead.add.json
Разбор по частям: /rest — вход в API, 1 — ID пользователя, от имени которого идут вызовы, xxxxxxxx — сам токен, дальше имя метода и формат. Подставьте вместо метода profile — и можно проверить связку прямо в браузере, без единой строки кода. Документация прямо рекомендует так делать: GET-запросы годятся для быстрой проверки методов, у которых нет сложных параметров.
Про права скажу отдельно, потому что сам когда-то на этом обжёгся. При создании вебхука можно выбрать и права (scope), и это не формальность: если оставить только crm, то при утечке URL злоумышленник получит доступ к CRM, но не сможет, скажем, стереть задачи или пользовательские поля в других разделах. Ещё лучше завести отдельного пользователя-«бота» с минимальными правами и создавать вебхук под ним. Тогда в истории изменений CRM будет видно, что лид пришёл именно от интеграции, а не от живого менеджера, и при необходимости интеграцию можно заморозить, не трогая людей.
Для боевых вызовов используйте POST. Это не прихоть: параметры с кириллицей, вложенные массивы и длинные значения в GET-строке рано или поздно ломаются, а POST принимает JSON как есть.
Лид из формы WordPress: рабочий пример
Вот минимальный обработчик, который я ставлю почти на каждый лендинг. В functions.php темы или, лучше, в mu-plugin:
add_action( 'admin_post_nopriv_lead2crm', 'wpt_lead_to_crm' );
add_action( 'admin_post_lead2crm', 'wpt_lead_to_crm' );
function wpt_lead_to_crm() {
// honeypot: боты заполняют скрытое поле, люди нет
if ( ! empty( $_POST['website'] ) ) {
wp_safe_redirect( home_url( '/thanks/' ) );
exit;
}
$name = sanitize_text_field( wp_unslash( $_POST['name'] ?? '' ) );
$phone = preg_replace( '/[^0-9+]/', '', wp_unslash( $_POST['phone'] ?? '' ) );
if ( strlen( $phone ) < 10 ) {
wp_die( 'Проверьте номер телефона', '', 400 );
}
$hook = 'https://company.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/crm.lead.add.json';
$response = wp_remote_post( $hook, array(
'timeout' => 5,
'body' => wp_json_encode( array(
'fields' => array(
'TITLE' => 'Заявка с сайта: ' . ( $name ?: 'без имени' ),
'NAME' => $name,
'PHONE' => array( array( 'VALUE' => $phone, 'VALUE_TYPE' => 'WORK' ) ),
'SOURCE_DESCRIPTION' => 'Лендинг ремонт + ' . ( $_POST['page'] ?? '' ),
'UTM_SOURCE' => sanitize_key( wp_unslash( $_POST['utm_source'] ?? '' ) ),
),
) ),
'headers' => array( 'Content-Type' => 'application/json' ),
) );
// пользователь не должен ждать и не должен видеть ошибку CRM
wp_safe_redirect( home_url( '/thanks/' ) );
exit;
}
На что тут стоит обратить внимание, потому что на этом спотыкаются все:
Телефон — отдельная песня. В Битрикс24 телефон и email это многозначные поля, то есть массивы объектов с VALUE и VALUE_TYPE. Передать строкой нельзя, получите ошибку валидации, причем текст её малоинформативный.
Пользователь важнее CRM. Таймаут 5 секунд и редирект на «спасибо» независимо от ответа API. Если Битрикс24 притормозил, человек всё равно должен увидеть подтверждение. Потерю запроса лечат по-другому: очередь, повторные отправки, лог недоставленных лидов. Худший вариант — показать посетителю ошибку 504, потому что CRM лежит.
Honeypot дешевый и работает. Скрытое поле «website», которое заполняют только боты, отрезает большинство спама еще до запроса в CRM. Плюс нормальная валидация телефона до отправки.
Идентифицируйте источник. UTM-метки в лид стоят копейки, а потом в отчетах CRM видно, откуда заявки. SOURCE_DESCRIPTION я использую как свободное поле «откуда пришло», чтобы менеджер видел контекст.
Проверку на дубли (чтобы один телефон не плодил десять лидов) в простом случае можно оставить CRM: у Битрикс24 есть собственный контроль дубликатов при настройке CRM. Если нужно жестче, есть методы поиска по телефону, но это уже следующий уровень сложности.
Куда класть этот код? В functions.php темы его жить не должно: обновление темы сотрёт правки, а дочерняя тема ради одного обработчика — лишний слой. Я складываю такие вещи в mu-plugin, файл в wp-content/mu-plugins/lead-to-crm.php. Must-use плагины грузятся всегда, в списке плагинов они помечены как обязательные и их нельзя случайно деактивировать мышкой из админки.
И честный дисклеймер про форму: если сайт работает на Contact Form 7, Gravity Forms или Fluent Forms, у многих из них есть собственные вебхуки и точки расширения. В CF7 есть хук wpcf7_before_send_mail, через который можно отправить данные в Битрикс24 из той же формы. Разница с моим примером в контроле: собственный обработчик работает с любой формой одинаково и не зависит от внутренностей конкретного плагина. Но если проект уже завязан на форму с хуками, проще дописать отправку в CRM туда, где уже обрабатывается сабмит.
А если задача шире, чем «создать лид», тем же входящим вебхуком создаются контакты, сделки и элементы смарт-процессов. Отличие только в методе и наборе полей: crm.contact.add, crm.deal.add, crm.item.add. Для интернет-магазина я обычно создаю сразу связку контакт плюс сделка, а лид пропускаю: менеджеру не нужна лишняя стадия квалификации там, где товар и сумма известны.
Исходящий вебхук: CRM сообщает сайту
Обратная ситуация: что-то произошло в CRM, и сайт должен это узнать. Классика — смена стадии сделки запускает письмо клиенту, генерит документ или двигает статус заказа в интернет-магазине.
Создается аналогично, в том же разделе, только выбирается «Исходящий вебхук» и указывается URL вашего обработчика. Требования жесткие, и это правильно: URL должен быть публичным и по HTTPS, localhost документация отвергает сразу. На этапе разработки выручает ngrok или его аналоги.
Когда событие срабатывает, Битрикс24 отправляет на ваш URL POST примерно такого вида:
Array
(
[event] => ONCRMDEALUPDATE
[data] => Array
(
[FIELDS] => Array
(
[ID] => 662
)
)
[ts] => 1724140800
[auth] => Array
(
[domain] => company.bitrix24.ru
[member_id] => ...
[application_token] => ...
)
)
Первая ловушка тут в том, что в payload приходит только ID сущности, а не все её поля. Это осознанное решение: события летают часто, таскать за собой полные объекты было бы расточительно. Ваш обработчик должен взять ID и догрузить данные методом crm.item.get (для сделок entityTypeId = 2).
Вторая ловушка: Битрикс24 ждет быстрого ответа 200. Если ваш обработчик перед ответом успевает сгенерировать PDF, сходить в соцсети и написать письмо, портал посчитает вебхук неисправным и со временем перестанет его слать. Правильная схема: принять событие, проверить application_token, положить задачу в очередь, ответить 200, обработать в фоне.
И проверяйте application_token по-настоящему, а не для галочки. Ваш URL публичный, любой может послать на него поддельное событие. Токен приходит в каждом запросе и сверяется с тем, что показан в настройках вебхука.
Из полезных событий чаще всего я встречаю в работе ONCRMLEADADD, ONCRMLEADUPDATE, ONCRMDEALADD и ONCRMDEALUPDATE. Список не исчерпывающий: события есть практически на каждую сущность, от задач до чатов. Но не увлекайтесь подпиской на всё подряд: каждое событие это HTTP-запрос к вашему серверу, и на живом портале их сотни в день даже без особой активности менеджеров. Начните с одного события, отладьте цепочку до конца, потом добавляйте следующие.
Батч и очереди: когда запросов становится много
Один лид из формы — это один запрос, о лимитах думать рано. Но как только интеграция обрастает логикой: подтянуть историю, проставить реквизиты, обновить товары, — одиночные вызовы перестают влезать в 2 запроса в секунду.
Первый инструмент — batch-метод. В один HTTP-запрос упаковывается до 50 вызовов REST, и это считается как один запрос к лимиту:
POST https://company.bitrix24.ru/rest/1/xxxxxxxxxxxxxxxx/batch.json
Content-Type: application/json
{
"halt": 0,
"cmd": {
"lead1": "crm.lead.add.json?fields[TITLE]=Заявка с лендинга А&fields[PHONE][0][VALUE]=+79001234567",
"lead2": "crm.lead.add.json?fields[TITLE]=Заявка с лендинга Б&fields[PHONE][0][VALUE]=+79009876543"
}
}
Ключи в cmd произвольные, к ним потом можно обращаться в последующих командах через $result[lead1][ID] — так собираются цепочки «создай контакт, потом сделку с этим контактом». Один нюанс из документации, который легко пропустить: batch уменьшает число HTTP-запросов, но не отменяет ресурсоемкость вложенных методов. Пятьдесят тяжелых вызовов в батче нагружают портал так же, как пятьдесят одиночных, просто их удобнее ждать.
Второй инструмент — очередь на вашей стороне. Всё, что пишет в CRM и не требует мгновенного ответа пользователю, я отправляю в фоновую обработку: в WordPress для этого хватает Action Scheduler (он уже есть, если стоит WooCommerce) или WP Cron для некритичных задач. Форма кладёт данные в очередь и показывает «спасибо», воркер спокойно отправляет лиды с паузой и ретраями. Такая схема переживает и таймауты, и недоступность портала на пять минут.
Отладка: где искать ошибку
У вебхуков нет консоли с логами, поэтому логи делаете себе вы. Что выручает на практике:
- Проверка руками через GET. Замените в URL метод на
profileилиdepartment.getи откройте в браузере. Если видите JSON с данными — токен и права живы, проблема в коде; если ошибку — проблема в URL или правах. - Чтение ответа. Битрикс24 на любую ошибку отвечает JSON с ключами
errorиerror_description. Код QUERY_LIMIT_EXCEEDED означает упор в лимит интенсивности, OPERATION_TIME_LIMIT — в ресурсоемкость, а текст вроде INVALID_CREDENTIALS — что токен протух или вебхук удалили. - Логирование у себя. Логируйте каждый запрос и ответ (хотя бы в файл на сутки). Без этого спор «кто виноват: сайт или CRM» длится втрое дольше.
Отдельно про time в ответе: там возвращается служебная информация о времени выполнения метода, и поле operating показывает накопленное время именно вашего приложения или вебхука. Когда скрипт начал ловить 429, это первое место, куда смотреть.

Лимиты: то, что всплывает через месяц
Пока лидов пять в день, о лимитах можно не думать. Они всплывают позже, когда вы начинаете гонять через API синхронизацию каталогов или отчеты. Экономия часа на прочтении документации потом оборачивается дебагом загадочных 503.
Механизм называется leaky bucket, «дырявое ведро». Каждый ваш запрос увеличивает счетчик, и когда он превышает порог, следующий запрос получает 503 с кодом QUERY_LIMIT_EXCEEDED. Раз в секунду счетчик уменьшается на фиксированную величину. По данным официальной документации лимитов (apidocs.bitrix24.com), пороги зависят от тарифа: на большинстве планов это 2 запроса в секунду устойчивой интенсивности и 50 до блокировки, на Enterprise — 5 и 250 соответственно.
Два практических следствия, о которых редко пишут в туториалах:
- Лимит общий на IP-адрес источника. Если на одном сервере живут сайт и еще два скрипта, которые дергают тот же портал Битрикс24, они делят один лимит. Отладили скрипт в одиночку, поставили в прод рядом с соседом — и словили 503 непонятно от чего.
- Лимит общий на портал, а не на ваше приложение. Интенсивность считается по каждому Битрикс24 отдельно, но внутри портала ваши вебхуки и интеграции складываются в общую корзину нагрузки.
Для больших объемов у документации есть готовые цифры: при устойчивых 2 запросах в секунду это порядка 172 800 HTTP-запросов в сутки, а методами списков с страницей в 50 записей можно вытащить миллионы записей в день. Чтобы не молотить сотнями одиночных запросов, есть batch: до 50 REST-вызовов упаковывается в один HTTP-запрос. Батч из 50 обращений к спискам по 50 записей вернет до 2500 записей за один запрос.
Отдельно существует лимит ресурсоемкости: время выполнения методов копится в десяти минутных корзинах, и при превышении следующий вызов блокируется уже с кодом OPERATION_TIME_LIMIT (HTTP 429). В ответе API есть массив time с полем operating — если ваш скрипт ловит 429, посмотрите на него, там видно, сколько времени вы уже сожгли. Лечится это не хитростями, а тем же, чем лечится 503: снижением частоты и повторами с нарастающей задержкой.
Правило, которое я вывел для себя: любой скрипт, который пишет в Битрикс24 больше пяти запросов за раз, обязан уметь ретраить 503 и 429 с паузой. Пять строк кода, а экономят ночь дебага.
Безопасность: вебхук это пароль
Строка xxxxxxxxxxxxxxxx в URL входящего вебхука является единственным секретом. Кто получил URL, тот может делать с CRM всё, что разрешено его scope, от имени того сотрудника, под которым вебхук создан.
Поэтому минимум, который я соблюдаю:
- Отдельный пользователь-бот с минимальными правами, под которым создается вебхук. Не администратор.
- Минимальный scope: только crm, если работаете с CRM. Не «на всякий случай всё».
- URL вебхука не попадает в код, который уходит в публичный репозиторий. В WordPress он должен лежать в константе из wp-config.php или в переменной окружения, а не в functions.php.
- HTTPS на стороне сайта для исходящих вебхуков, валидация application_token, быстрые ответы 200.
Ничего экзотического тут нет, это гигиена. Но гигиена, которую пропускают, потому что «вебхук же внутренний».
Что изменилось к 2026
За последний год в документации Битрикс24 появились вещи, которые делают жизнь разработчика заметно проще, и на них стоит обратить внимание, если вы писали интеграции раньше и отложили тему.
Первая — официальный MCP-сервер. Документация теперь прямо предлагает подключать к нему AI-ассистентов (Codex, Claude Code, Cursor), чтобы те писали код интеграций по актуальной документации REST, а не по своим догадкам из обучающих данных. Это не маркетинговая приписка: REST у Битрикс24 большой, методы обновляются, и ассистент, который уверенно генерит устаревший вызов, хуже того, который честно говорит «не знаю». Я пробовал: с подключенной докой количество выдуманных параметров в сгенерированном коде падает в разы.
Вторая — для массовых выгрузок документация честно говорит: REST не предназначен для интенсивного обмена большими объемами данных, для этого существует отдельный BI-коннектор со своим механизмом. Если задача звучит как «выгрузить все сделки за год в DWH», это уже не про вебхуки.
Вместо итога
Вебхуки закрывают большую часть задач связки сайта с Битрикс24, и не требуют ничего, кроме встроенного раздела «Разработчикам» и пары десятков строк на вашей стороне. Входящий вебхук плюс форма с грамотным обработчиком решает проблему потерянных лидов за вечер. Исходящий позволяет сайту реагировать на события CRM без опроса API по расписанию. Лимиты при здоровом подходе не мешают, а структура событий заставляет сразу проектировать обработчики правильно.
А вы как связываете сайт и Битрикс24? Через плагины, готовые коннекторы или своим кодом? И что чаще всего ломается в интеграциях у вас? Расскажите в комментариях, интересен другой опыт.