Стандартных сделок и лидов в Битрикс24 хватает для продаж, но как только у бизнеса появляется процесс вроде «заявки на ремонт», «аренда оборудования» или «договоры на согласовании» — стандартные сущности начинают трещать по швам: либо приходится впихивать чужой процесс в воронку сделок, либо заводить кучу пользовательских полей, в которых никто не разбирается. Смарт-процессы (Smart Process Automation, SPA) решают именно это: позволяют создать собственный тип объекта со своими полями, стадиями и правами доступа, и управлять им через API.
В статье разберём, как создавать и работать с объектами смарт-процессов через API Битрикс24: от создания самого типа процесса до CRUD-операций (create, read, update, delete — создание, чтение, обновление, удаление) с объектами через REST. Материал для разработчиков, которые уже работают с REST API Битрикс24 и которым нужно завести собственный тип объекта, а затем управлять им программно.
Что понадобится перед началом
- Доступ к порталу Битрикс24 с правами администратора (создание типов смарт-процессов требует прав на CRM)
- Тариф Битрикс24, поддерживающий смарт-процессы (доступны начиная с определённых платных тарифов, на бесплатном тарифе функция может быть недоступна или ограничена)
- Входящий webhook с правами
crmили OAuth-приложение - Понимание базовой работы с REST API Битрикс24 (структура запросов, формат ответа)
- Тестовый портал для отладки, чтобы не создавать мусорные типы процессов в продакшене

Основная часть: создаём и работаем со смарт-процессами
Шаг 1. Создаём тип смарт-процесса через API
Тип процесса (структура — какие поля, стадии, связи с другими сущностями) можно настроить через интерфейс (CRM → Настройки → «Смарт-процессы»), но раз статья про API — создадим его методом crm.type.add.
$webhookUrl = getenv('BITRIX_WEBHOOK_URL');
$payload = [
'fields' => [
'title' => 'Аренда оборудования',
'isStagesEnabled' => 'Y', // включает работу со стадиями
'isAutomationEnabled' => 'Y', // разрешает роботов и триггеры
],
];
$ch = curl_init($webhookUrl . 'crm.type.add.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
$entityTypeId = $response['result']['type']['entityTypeId'];
Поле title — единственное обязательное. entityTypeId можно не указывать вообще — Битрикс24 присвоит его автоматически; если нужен конкретный номер, его можно передать явно — он должен попадать в диапазон, отведённый под динамические типы, и быть свободным на портале.
Полученный entityTypeId дальше нужен во всех запросах к этому процессу — сохраните его, а не подбирайте вручную.
Частая ошибка: создают тип процесса прямо в продакшн-портале «на пробу», а потом не могут его удалить без последствий — если в нём уже есть объекты, тип процесса с данными удаляется с потерей информации. Тестируйте структуру на тестовом портале.

Шаг 2. Получаем список типов смарт-процессов через API
Перед тем как создавать объекты, нужно знать точный entityTypeId нужного типа процесса.
// Получаем список всех типов смарт-процессов на портале
$webhookUrl = getenv('BITRIX_WEBHOOK_URL');
$response = file_get_contents($webhookUrl . 'crm.type.list.json');
$types = json_decode($response, true);
foreach ($types['result']['types'] as $type) {
echo $type['entityTypeId'] . ' — ' . $type['title'] . PHP_EOL;
}
Шаг 3. Создаём объект смарт-процесса через API
Зная entityTypeId, создаём объект методом crm.item.add. Структура запроса похожа на создание лида или сделки, но требует обязательного указания entityTypeId.
function addSmartProcessItem(string $webhookUrl, int $entityTypeId, array $fields): array
{
$url = $webhookUrl . 'crm.item.add.json';
$payload = [
'entityTypeId' => $entityTypeId,
'fields' => $fields,
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
$fields = [
'title' => 'Аренда экскаватора на 3 дня',
'opportunity' => 45000, // сумма, если есть денежное поле
'ufCrm5_equipmentType' => 'Экскаватор', // пользовательское поле, имя зависит от настройки
];
$result = addSmartProcessItem($webhookUrl, $entityTypeId, $fields);
$newItemId = $result['result']['item']['id']; // ID лежит не в result напрямую, а в result.item.id
Частая ошибка: путают имена пользовательских полей. Поля, добавленные через интерфейс к смарт-процессу, получают сгенерированные технические имена вида ufCrm{N}_xxx (или UF_CRM_{N}_xxx, если передать параметр useOriginalUfNames: true), и угадать их нельзя — нужно смотреть точное имя через метод crm.item.fields с указанием entityTypeId.
Вторая частая ошибка — берут код из примеров для crm.lead.add (там ID лида возвращается прямо в result) и пытаются так же читать ID из ответа crm.item.add. У универсальных crm.item.* методов структура ответа другая — объект целиком лежит в result.item, а не в result.

Шаг 4. Получаем список полей объекта
Чтобы не угадывать технические имена полей, всегда сначала запрашиваем структуру.
$response = file_get_contents($webhookUrl . 'crm.item.fields.json?entityTypeId=' . $entityTypeId);
$fieldsInfo = json_decode($response, true);
foreach ($fieldsInfo['result']['fields'] as $name => $info) {
echo $name . ' — ' . ($info['title'] ?? '') . PHP_EOL;
}
Шаг 5. Читаем и обновляем объекты
Получить объект по ID — метод crm.item.get, обновить — crm.item.update. Оба требуют entityTypeId и id объекта.
Перед обновлением стадии нужно знать её точный код — получаем его через crm.status.list, а не придумываем по шаблону.
$statusResponse = file_get_contents($webhookUrl . "crm.status.list.json?filter[ENTITY_ID]=DYNAMIC_{$entityTypeId}_STAGE");
$stages = json_decode($statusResponse, true)['result'];
$stageId = $stages[0]['STATUS_ID']; // берём конкретный нужный код из списка, а не первый попавшийся
// Чтение объекта
$response = file_get_contents($webhookUrl . "crm.item.get.json?entityTypeId={$entityTypeId}&id=42");
$item = json_decode($response, true)['result']['item']; // объект снова лежит в result.item
// Обновление стадии объекта
$updatePayload = [
'entityTypeId' => $entityTypeId,
'id' => 42,
'fields' => ['stageId' => $stageId], // код стадии, полученный на предыдущем шаге
];
$ch = curl_init($webhookUrl . 'crm.item.update.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($updatePayload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$updated = json_decode(curl_exec($ch), true);
curl_close($ch);
if (isset($updated['error'])) {
// ошибку возвращает не HTTP-код, а тело ответа — проверять нужно именно его
throw new RuntimeException($updated['error_description'] ?? $updated['error']);
}
Частая ошибка: при обновлении стадии передают просто название стадии («Завершено»), а не её технический код. Код стадии для конкретного смарт-процесса нельзя угадать по шаблону — его нужно получить через метод crm.status.list (или crm.dealcategory.stage.list для процессов со стадиями в стиле сделок) с фильтром по entityId, соответствующему вашему типу процесса, и использовать ровно ту строку, которую вернул API.
Шаг 6. Удаляем объекты и обрабатываем связанные данные
Удаление — метод crm.item.delete. Перед удалением стоит учесть, что у объекта могут быть связанные сущности (например, привязанные контакты или товары) — они не удаляются автоматически и могут остаться «осиротевшими» записями.
$deletePayload = [
'entityTypeId' => $entityTypeId,
'id' => 42,
];
$ch = curl_init($webhookUrl . 'crm.item.delete.json');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($deletePayload));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$deleted = json_decode(curl_exec($ch), true);
curl_close($ch);
Шаг 7. Настраиваем обработку событий смарт-процесса через webhook
Как и для стандартных CRM-сущностей, для смарт-процессов можно настроить исходящие webhook на события (создание, изменение стадии). Имя события строится из общего префикса для динамических объектов и номера типа процесса — то есть у каждого смарт-процесса оно своё, и подписываться нужно именно на «своё» имя, а не на общее. Как устроен обработчик такого события, разбирали в статье про настройку вебхуков.
Частые ошибки и как их избежать
Ошибка: жёстко прописывают entityTypeId в коде как магическое число без комментария, вместо того чтобы получить его через crm.type.add или crm.type.list и сохранить. Через полгода никто не помнит, что означает конкретное число, особенно если на портале несколько типов смарт-процессов. Решение: хранить соответствие entityTypeId → название процесса в конфиге или константах с понятными именами, а не вписывать число напрямую в вызовы API.
Ошибка: не проверяют права доступа при создании объекта от имени пользователя (не через входящий webhook с административными правами). Если у пользователя, от имени которого выполняется запрос, нет прав на этот смарт-процесс, API вернёт ошибку доступа, которую легко спутать с ошибкой в данных. Решение: при отладке сверять права через интерфейс CRM, прежде чем искать ошибку в коде.
Ошибка: считают смарт-процессы полной заменой кастомной таблицы в базе данных. Смарт-процессы хороши для CRM-логики (воронки, стадии, права доступа), но для больших объёмов данных без отношения к продажам (например, логи или служебные таблицы) использовать D7 ORM или собственную БД эффективнее.
Из практики А2
Смарт-процессы чаще всего заводят не там, где надо. Если у сущности нет своей воронки и стадий — это не смарт-процесс, а справочник, и жить ему лучше в отдельной таблице: карточка со стадиями, по которым объект никогда не движется, только мешает пользователям.
Технические имена пользовательских полей — главный источник потерянного времени. Они генерируются при создании поля, отличаются между порталами, и код, написанный на тестовом портале, на боевом просто не находит поля. Единственный надёжный путь — на старте запросить crm.item.fields для нужного типа и держать соответствие «понятное имя → техническое» в конфиге проекта.
Ещё одна ловушка — ответ универсальных методов. Разработчик, привыкший к crm.lead.add, читает result и получает null, потому что у crm.item.* объект лежит на уровень глубже. Ошибка выглядит как «API не работает», хотя объект создан.
И про удаление: типы смарт-процессов удаляются вместе с данными, а восстановить их из интерфейса нельзя. Экспериментировать со структурой стоит на тестовом портале, даже когда кажется, что «просто попробуем и удалим».
Итог
После этой инструкции у вас есть рабочий подход к созданию собственного типа процесса в Битрикс24 и управлению его объектами через API — без искусственной подгонки под стандартные лиды и сделки. Если на каком-то шаге застряли — опишите ситуацию в комментарии или напишите нам напрямую.