Метод crm.deal.get принимает идентификатор сделки и возвращает её поля вместе с пользовательскими, которые в ответе лежат под ключами вида UF_CRM_1721134404. Работает он до сих пор, но в справке Битрикс24 у него стоит пометка «Развитие метода остановлено, используйте crm.item.get». Поэтому ниже я показываю оба варианта: старый вызов, чтобы вы понимали, что отдаёт уже написанный чужой код, и новый, на который я перевожу свои интеграции.
Статус crm.deal.get: что значит «развитие остановлено»
Пометка DEPRECATED в документации не означает, что метод завтра отключат. Это значит, что новые возможности в него добавляться не будут, а все новые сущности и поля появляются в универсальных методах crm.item.*. Для сделок это entityTypeId = 2. Я сталкивался с этим на практике: интеграция, написанная три года назад на crm.deal.get, продолжает отдавать данные, но часть связей в ответе помечена как устаревшая. Например, идентификатор контакта в старом ответе описан как «Устаревшее», а список контактов сделки предлагается брать через crm.deal.contact.items.get или универсальный crm.item.get.
Моё правило такое. Если интеграция уже работает и менять её нет повода, я не трогаю crm.deal.get. Новый код пишу сразу на crm.item.get, потому что переписывать потом придётся в любом случае.
| Параметр | crm.deal.get | crm.item.get |
|---|---|---|
| Статус в документации | Устаревший | Актуальный |
| Параметры запроса | id |
entityTypeId, id |
| Имена обычных полей | Верхний регистр: TITLE, STAGE_ID |
camelCase: title, stageId |
| Пользовательские поля | UF_CRM_... |
ufCrm_... |
| Где лежит результат | Прямо в result |
В result.item |
Вебхук и вызов: как получить данные сделки по ID
Для серверной интеграции проще всего входящий вебхук. Он создаётся в разделе «Разработчикам» портала, при создании выбираются права, и в нужны только «CRM». В итоге вы получаете URL вида https://ваш-портал.bitrix24.ru/rest/ID_ПОЛЬЗОВАТЕЛЯ/КОД_ВЕБХУКА/. К нему дописывается имя метода. Секретный код в URL равен паролю: не кладите его в репозиторий и в код страниц на Tilda, которые видит любой посетитель.
Самый простой запрос к старому методу:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"id": 123}' \
https://ваш-портал.bitrix24.ru/rest/1/КОД_ВЕБХУКА/crm.deal.get.json
В ответе придёт объект result с полями сделки и объект time со статистикой выполнения. Нужные мне ключи: TITLE, STAGE_ID, OPPORTUNITY, CURRENCY_ID, ASSIGNED_BY_ID, CONTACT_ID, COMPANY_ID. Список всех полей, включая пользовательские, отдаёт crm.deal.fields.
Если сделка не найдена, Битрикс24 вернёт ошибку в теле ответа, поэтому в коде я всегда проверяю наличие ключа error, а не только HTTP-статус.
PHP-обработчик на обычном хостинге
Для Tilda и WordPress такой запрос я делаю из PHP-скрипта на том же хостинге, где живёт сайт. Отдельный сервер не нужен: хватает расширения curl, которое на shared-хостинге включено почти всегда.
<?php
function b24_call(string $method, array $params): array
{
$url = 'https://ваш-портал.bitrix24.ru/rest/1/КОД_ВЕБХУКА/' . $method . '.json';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
]);
$raw = curl_exec($ch);
curl_close($ch);
$data = json_decode((string)$raw, true);
return is_array($data) ? $data : ['error' => 'bad_response'];
}
$res = b24_call('crm.deal.get', ['id' => 123]);
if (isset($res['error'])) {
exit('Ошибка: ' . $res['error']);
}
echo $res['result']['TITLE'];
Ту же функцию я использую и для других методов, меняется только имя метода и набор параметров.
Бесплатный материал
🎁 Полезный скрипт в подарок
Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.
Без спама. Отписка в 1 клик.
Пользовательские поля сделки в ответе REST
Главная причина, по которой читатели ищут именно этот запрос, пользовательские поля. Они создаются в интерфейсе CRM, и у каждого есть технический код. В старом методе он выглядит как UF_CRM_1721134404: префикс и число, которое портал присвоил при создании поля. Название поля из интерфейса в ответе не приходит, только код.
Есть тонкость, на которой теряют время: код поля в разных порталах разный. Поле «Источник заказа» на тестовом портале и на боевом получит два разных числа. Поэтому в коде я не зашиваю UF_CRM_1721134404 намертво, а вынимаю соответствие «название поля, код» из метода crm.deal.userfield.list и кладу в конфиг. Так перенос с тестового портала на боевой сводится к смене одного файла.
curl -X POST \
-H "Content-Type: application/json" \
-d '{"filter": {"FIELD_NAME": "UF_CRM_1721134404"}}' \
https://ваш-портал.bitrix24.ru/rest/1/КОД_ВЕБХУКА/crm.deal.userfield.list.json
В ответе будет описание поля: тип, подписи на языках портала и, для списков, перечень значений.
Какие значения приходят для разных типов
По моему опыту, больше всего вопросов вызывают три типа:
- Список. Приходит числовой идентификатор значения, а не текст. Расшифровку нужно брать из описания поля (
crm.deal.userfield.get, ключLIST) и кэшировать у себя. - Множественное поле. Приходит массив, даже если выбрано одно значение. Код, который ждёт строку, ломается на пустом массиве.
- Файл, привязка, деньги. Это структуры или строки специального формата. Например, денежное поле хранит сумму и валюту в одной строке через разделитель. Как именно эти значения выглядят на вашем портале, проверяйте тестовым вызовом, а не по памяти.
Пустое пользовательское поле приходит как пустая строка или null, и проверять нужно оба случая.
Замена: crm.item.get для получения элемента CRM
Универсальный метод принимает тип сущности и идентификатор. Для сделки тип равен 2. Результат лежит во вложенном объекте item.
curl -X POST \
-H "Content-Type: application/json" \
-d '{"entityTypeId": 2, "id": 123}' \
https://ваш-портал.bitrix24.ru/rest/1/КОД_ВЕБХУКА/crm.item.get.json
В ответе поля уже в camelCase: title, stageId, opportunity, assignedById. Пользовательские поля приходят в виде ufCrm_1721134404, то есть число то же, а запись другая. В документации метода есть параметр, который возвращает пользовательские поля в оригинальной записи UF_CRM_... (useOriginalUfNames). Перед использованием сверьтесь с актуальной справкой, потому что он нужен только при миграции со старого кода, а в новом я просто работаю с camelCase.
В PHP-функции выше для нового метода меняются только вызов и путь к данным:
$res = b24_call('crm.item.get', ['entityTypeId' => 2, 'id' => 123]);
if (isset($res['error'])) {
exit('Ошибка: ' . $res['error']);
}
$deal = $res['result']['item'];
echo $deal['title'];
echo $deal['ufCrm_1721134404'] ?? '';
Если вам нужны не все поля, список можно сузить. Для этого в универсальных методах есть выборка по нужным ключам, а для списков сделок аналогичную роль играет crm.item.list с фильтром и параметром select. Единственный запрос на сделку с десятком полей обходится дёшево, а вот массовая выгрузка всех полей по тысяче сделок упирается в лимиты, о которых дальше.
Сделка после события: вебхук плюс запрос
Чаще всего я получаю сделку не по расписанию, а в ответ на событие. В портале создаётся исходящий вебхук с событием OnCrmDealUpdate и адресом моего PHP-обработчика. В событии приходит только идентификатор сделки (в data[FIELDS][ID]), поэтому полные данные я всё равно забираю отдельным вызовом crm.item.get. Несколько фактов, на которых спотыкаются:
- Тело запроса приходит в формате
application/x-www-form-urlencoded, поэтому читать нужно$_POST, а неphp://inputкак JSON. - Событие срабатывает на любое обновление сделки, не только на смену стадии. Если нужна именно стадия, сравнивайте её с сохранённым значением у себя.
- Повторных отправок нет: если обработчик не ответил или упал, событие потеряно. Когда потери недопустимы, документация советует офлайн-события.
- У исходящего вебхука настраиваются только адрес и список событий, права на чтение выбираются у входящего вебхука, которым вы потом вызываете REST.
- В
authприходитapplication_token. Я сохраняю его при настройке и сверяю при каждом запросе, чтобы обработчик не принимал чужие POST.
Такая схема стоит у меня за рассылкой уведомлений менеджеру в Telegram и за передачей данных сделки в другие системы. В n8n то же самое собирается узлом Webhook и узлом HTTP Request с вызовом crm.item.get. Для бота на aiogram логика та же: событие приходит в обработчик, данные дозапрашиваются по ID.
Несколько сделок сразу: batch и лимиты запросов
Когда сделок много, по одному запросу на каждую не уложиться. Метод batch принимает до 50 вызовов в одном HTTP-запросе. Тело выглядит так:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"halt": 0, "cmd": {"d1": "crm.item.get?entityTypeId=2&id=123", "d2": "crm.item.get?entityTypeId=2&id=124"}}' \
https://ваш-портал.bitrix24.ru/rest/1/КОД_ВЕБХУКА/batch.json
Batch сокращает число HTTP-запросов, но не отменяет ограничения на ресурсоёмкость самих методов. Здесь работают два независимых лимита, и про второй пишут редко.
| Лимит | Как проявляется | Код ошибки |
|---|---|---|
| Интенсивность запросов | Счётчик превышает порог, следующий запрос блокируется со статусом 503 | QUERY_LIMIT_EXCEEDED |
| Ресурсоёмкость метода | Накопленное время выполнения превышает лимит, метод блокируется для вебхука, статус 429 | OPERATION_TIME_LIMIT |
По справке, интенсивность считается по алгоритму Leaky Bucket: на тарифе «Энтерпрайз» порог 250 при скорости 5 запросов в секунду, на остальных порог 50 при 2 запросах в секунду. Тарифы и цифры меняются, поэтому актуальные значения сверяйте на странице лимитов в документации. Лимит считается по IP, значит несколько скриптов с одного хостинга делят одну квоту.
Второй лимит можно отслеживать: в каждом ответе есть time.operating, накопленное время выполнения метода. Если оно растёт, я увеличиваю паузы между пачками. Списочные методы отдают по 50 записей за страницу, дальше нужно идти по start и смотреть ключ next в ответе.
Типичные ошибки при получении сделки через REST
Из того, что реально приходилось разбирать на проектах:
- Пустой ответ при верном ID. Вебхук создан под пользователем без доступа к этой сделке. REST работает с правами того, от чьего имени выпущен вебхук.
- Нет пользовательского поля в ответе. Поле создано для другой сущности (лида, контакта) или код взят с другого портала. Сверяйте через
crm.deal.userfield.list. - Поля «потерялись» после перехода на crm.item.get. Ключи сменили регистр:
TITLEсталоtitle,UF_CRM_...сталоufCrm_.... Код, который ждёт старые имена, получаетnull. - JSON не разбирается. На ошибке лимита вместо данных приходит тело с описанием ошибки. Проверяйте HTTP-статус и ключ
errorдо обращения кresult. - Секрет вебхука утёк. URL вставили в клиентский скрипт страницы. Выпустите новый вебхук, а запросы переносите на сервер.
Лицензия и тариф портала тоже влияют: набор доступных функций CRM и лимиты зависят от тарифа. Если вы только выбираете условия под интеграцию, лицензии Битрикс24 я подбираю под задачу, а цену называю после обсуждения.
Условия и возможности Битрикс24 меняются, поэтому перед запуском интеграции я сверяюсь с актуальной документацией REST и страницей лимитов.
Частые вопросы
Можно ли ещё использовать crm.deal.get в новых проектах?
Технически метод отвечает, но развитие его остановлено, и в справке рекомендован crm.item.get. Для нового кода я беру универсальный метод, чтобы не переписывать интеграцию при очередном изменении старых методов.
Как узнать код пользовательского поля сделки?
Вызовите crm.deal.userfield.list и найдите поле по подписи, код лежит в FIELD_NAME. Для универсальных методов к нему применяется запись ufCrm_... с тем же числом. Коды различаются между порталами, поэтому храните соответствие в конфиге.
Почему в списке пришло число вместо текста значения?
Поле типа «Список» хранит идентификатор значения. Тексты значений берутся из описания поля через crm.deal.userfield.get, их удобно закэшировать и подставлять у себя.
Что делать, если приходит QUERY_LIMIT_EXCEEDED?
Уменьшите частоту запросов, соберите вызовы в batch и добавьте паузу с повтором после ошибки. Помните, что лимит общий для всех скриптов с одного IP, а при массовых обновлениях событий приходит много сразу, поэтому тяжёлую обработку лучше выносить из обработчика.