Для AI-агентов: markdown этой страницы — /docs-content/entity-api.md индекс документации — /llms.txt
Обзор API
Вайбкод предоставляет единый REST-интерфейс для работы с сущностями Битрикс24: CRM, задачи, пользователи, календарь, диск, каталог, документооборот и другие. Формат запроса, ответа и ошибок у всех сущностей одинаковый.
Базовый URL:
https://vibecode.bitrix24.techАвторизация: заголовокX-Api-Key: ваш_ключКлючиvibe_app_…дополнительно требуют заголовокAuthorization: Bearerс токеном сессии на каждый запрос к сущностям. Для фоновых задач по расписанию без пользователя у экрана берите ключvibe_api_…. Подробнее — Создание и использование ключа.
Доступные операции
Ниже описан стандартный набор операций. Путь строится по шаблону /v1/{entity}.
Набор операций у каждой сущности свой: у части сущностей отдельные операции недоступны. Какие операции доступны сущности, показывают её страница в Справочнике API и поле operations в ответе GET /v1/guide. Запрос к операции, которой у сущности нет, отвечает 404 ROUTE_NOT_FOUND — Коды ошибок.
Список — `GET /v1/{entity}`
Получить записи с пагинацией, сортировкой и выборкой полей.
curl -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/deals?limit=100&offset=0"
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
limit |
number | Количество записей (по умолчанию 50, максимум 5000). Значение 0 размером страницы не является: параметр отбрасывается, применяется значение по умолчанию, а в ответ добавляется предупреждение LIMIT_ZERO_IGNORED в meta.warnings |
offset |
number | Пропустить N записей |
select |
string[] | Выборка полей: ?select=id,title,amount. Принимаются канонические имена из GET /v1/{entity}/fields, исходные имена Битрикс24 у объявленных полей и взаимозаменяемые имена дат updatedAt / updatedTime, createdAt / createdTime. Незнакомое имя отклоняется ошибкой 400 UNKNOWN_SELECT_FIELD на сущностях, чей набор полей выверен по Битрикс24 — сделки, контакты, компании, лиды, предложения, дела, адреса, смарт-процессы, товары и разделы товаров, каталоги и их товары и разделы, заказы и статусы заказов, статусы, валюты, события и разделы календаря, файлы, папки, хранилища, подразделения, рабочие группы, шаблоны документов. На остальных оно даёт предупреждение UNKNOWN_SELECT_FIELD в meta.warnings. Пользовательские поля (UF_*, ufCrm*) не отклоняются нигде, а свойства товаров принимаются каждое на СВОЕЙ сущности: PROPERTY_295 — на товарах, property295 — на товарах каталога, где их номера назначает портал. Чужое написание метод не понимает, и его гейт отклоняет. На списке и поиске реквизитов и банковских реквизитов имя уходит дальше в Битрикс24, и там аккаунт, не знающий такого поля, отклоняет весь вызов с 422 BITRIX_ERROR. Значение * (и UF_*, в любом регистре) означает «вернуть все поля» — отбор не применяется, а незнакомое имя рядом с ним даёт предупреждение вместо ошибки |
order |
object | Сортировка: ?order[createdAt]=desc |
withTotal |
string | Нужно ли количество: true или false, ровно эти два значения. false — единственный способ гарантированно убрать meta.total из ответа. При limit не больше 50 он заодно отменяет подсчёт, при limit больше 50 — убирает число, а не подсчёт. Без параметра значение берётся из настройки ключа, затем из платформенного умолчания, и тогда на короткой странице точное количество приходит и без заказа — см. Листание и количество записей |
Авто-пагинация: при limit > 50 Вайбкод автоматически запрашивает несколько страниц у Битрикс24 и возвращает все записи в одном ответе.
Получить по ID — `GET /v1/{entity}/{id}`
curl -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/deals/123"
Ответ: { success: true, data: { id: 123, title: "...", ... } }
Параметр select работает и при получении записи по id — ответ содержит только перечисленные поля. Поддерживаются три формы: список через запятую ?select=id,title,stageId, повторяющийся ключ ?select[]=id&select[]=title и индексируемый ?select[0]=id&select[1]=title. Поле id возвращается всегда. Незнакомое имя поля отвечает ошибкой 400 UNKNOWN_SELECT_FIELD на сущностях со сверенным набором полей (список — в таблице параметров выше), а на остальных дополняет ответ предупреждением UNKNOWN_SELECT_FIELD в meta.warnings. Пользовательское поле указывается именем из схемы — Пользовательские поля (UF). Значение * (и UF_*) — привычная для Битрикс24 запись «вернуть все поля»: отбор не применяется, приходит полная запись. Параметр совместим с include — связанные данные подгружаются до отбора полей.
Создать — `POST /v1/{entity}`
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
"https://vibecode.bitrix24.tech/v1/deals" \
-d '{"title": "Новая сделка", "stageId": "NEW", "amount": 150000}'
Ответ: { success: true, data: { id: 456, ... } } (HTTP 201)
Тело без единого поля возвращает 400 EMPTY_CREATE_BODY, а у сущностей с обязательными полями создания — 400 MISSING_REQUIRED_FIELDS с именем первого недостающего поля. Оба кода — Коды ошибок.
Обновить — `PATCH /v1/{entity}/{id}`
curl -X PATCH -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
"https://vibecode.bitrix24.tech/v1/deals/123" \
-d '{"stageId": "WON", "amount": 200000}'
Тело без единого поля возвращает 400 EMPTY_UPDATE_BODY — Коды ошибок.
Удалить — `DELETE /v1/{entity}/{id}`
curl -X DELETE -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/deals/123"
Поиск — `POST /v1/{entity}/search`
Поиск с фильтрацией. Подробнее о синтаксисе фильтров: Фильтрация
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
"https://vibecode.bitrix24.tech/v1/deals/search" \
-d '{"filter": {"stageId": "NEW", "amount": {"$gte": 100000}}, "sort": {"createdAt": "desc"}, "limit": 200}'
Параметры:
| Параметр | Тип | Описание |
|---|---|---|
filter |
object | Условия фильтрации (три синтаксиса) |
sort |
string | object | array | Сортировка. Поддерживаются: "id" / "-amount" / "id,-createdAt" (string), { id: "asc", amount: "desc" } или { id: 1, amount: -1 } (object), ["id", "-amount"] (array). Некорректный тип → 400 INVALID_SORT_TYPE. Подробнее про пагинацию — см. filtering.md. |
limit |
number | Количество записей (по умолчанию 50, максимум 5000, авто-пагинация при > 50). Значение 0 отбрасывается — см. предупреждение LIMIT_ZERO_IGNORED |
offset |
number | Пропустить N записей |
autoWindow |
boolean | false — отключить разбивку по дате для больших выборок |
withTotal |
boolean | Нужно ли количество. false — единственный способ гарантированно убрать meta.total из ответа. При limit не больше 50 он заодно отменяет подсчёт, при limit больше 50 — убирает число, а не подсчёт. Без поля значение берётся из настройки ключа, затем из платформенного умолчания, и тогда на короткой странице точное количество приходит и без заказа — см. Листание и количество записей |
Поиск по временным окнам: для больших наборов данных поиск автоматически разбивает запрос на окна по дате. Если это вызывает таймауты — отключите через autoWindow: false.
Агрегация — `POST /v1/{entity}/aggregate`
Подсчёт количества и числовые агрегации (sum, avg, min, max) с фильтрацией. Набор операций каждой сущности перечислен на её странице в Справочнике API. У сущностей без агрегации количество записей приходит в meta.total ответа списка.
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{
"aggregate": [
{ "field": "amount", "function": "sum" },
{ "field": "amount", "function": "avg" }
],
"filter": { "stageId": "WON" }
}' \
"https://vibecode.bitrix24.tech/v1/deals/aggregate"
Параметры (body):
| Параметр | Тип | Описание |
|---|---|---|
aggregate |
array | Массив агрегаций: { "field": "amount", "function": "sum" }. Функции: count, sum, avg, min, max. Без массива — только count |
filter |
object | Фильтрация по полям сущности |
groupBy |
string | string[] | Поле или массив полей для группировки (максимум 5). Допустимые значения — из списка aggregatable конкретной сущности. У сущностей без этого списка (например, statuses, currencies, deal-categories) группировка не поддерживается, доступен count с фильтром |
Как это работает:
countсчитается одним быстрым вызовом в Битрикс24. Дляsum/avg/min/maxплатформа подгружает записи под фильтр, максимум 5000, и считает на стороне Вайбкод. Прочитано меньше, чем обещалdata.count, — ответ помечаетсяmeta.truncated: true, и потолок лишь одна из причин такой пометки, а размер нехватки приходит вdata.meta.recordsShortfall. Полный разбор — Агрегация POST — потолок 5000 записей. При некорректном поле ответ содержит список доступных.
Пользовательские поля (UF) поддерживаются в
sum/avg/min/maxдля UF-типовinteger,double,money.groupByпринимает UF-поля любого типа. Подробно — в разделе Агрегация POST — UF-поля ниже.
Смарт-процессы (
items) передают тип в пути:POST /v1/items/:entityTypeId/aggregate. ЗарезервированныеentityTypeId(1, 2, 3, 4, 7, 31) обслуживаются специализированными API сделок, лидов, контактов, компаний, предложений, счетов.
Агрегация POST — потолок 5000 записей
Потолок действует на запросе, которому для ответа нужны сами записи: это числовые функции и группировка. Простой count без groupBy под него не подпадает — он считается на стороне Битрикс24 и отвечает на выборке любого размера.
Поведение на выборке шире 5000 записей сейчас раскатывается по аккаунтам, поэтому вариантов два:
- Пока возможность не включена на аккаунте — приходит
200, в ответеmeta.truncated: true, результат посчитан по первым 5000 записям. Ту же пометку ставит и нехватка ниже потолка: прочитано меньше, чем обещалdata.count, а её размер лежит вdata.meta.recordsShortfall. - После включения — приходит
422 AGGREGATION_LIMIT_EXCEEDED, и ни одна запись не выгружается. В тексте ошибки перечислено, что делать дальше. Смысл замены: на крупной выборке выгрузка первых 5000 всё равно не успевала, запрос обрывался по таймауту, и усечённый ответ до вызывающего чаще всего не доходил вовсе.
Действие в обоих случаях одно: сузить фильтр либо взять count без группировки. Клиент, который сегодня ветвится по meta.truncated, после включения возможности на его аккаунте начнёт получать 422 — предусмотрите обе ветки.
meta.truncated теперь поднимается ещё в одном случае — и это касается ВСЕХ сущностей, не только дел. Если записей обработано меньше, чем ответ обещал, он ставит truncated: true и добавляет meta.recordsShortfall — сколько записей не хватило. Обещанное — это data.count, а в режиме счётчиков по стадиям (meta.aggregatePath: "fanout") большее из data.count и суммы счётчиков стадий: пробы стадий могут в пределах допуска дать больше воронки, и тогда нехватка меряется от них. Поэтому предикат «неполно, если recordsProcessed < totalRecords» верен не всегда — читайте сам truncated. Раньше в этом случае приходило truncated: false, то есть группы и числовые агрегации считались по части записей, а ответ этого не сообщал. count и meta.totalRecords остаются полными.
Признак усечения приходит рядом с самим числом. Пока он лежал только в meta, клиент, который читает data.aggregates.amount.sum и больше ничего, получал уверенное число без единого намёка на неполноту. Поэтому при усечении каждый объект поля в data.aggregates и в groups[].aggregates дополнительно несёт truncated: true:
{
"data": {
"count": 20000,
"aggregates": {
"amount": { "sum": 1234567, "truncated": true }
},
"meta": {
"totalRecords": 20000,
"recordsProcessed": 5000,
"truncated": true,
"warnings": [{ "code": "AGGREGATE_TRUNCATED", "message": "…" }]
}
}
}
Значения sum / avg / min / max остаются числами — в объект их никто не оборачивает. Ключ truncated внутри объекта поля появляется ТОЛЬКО при усечении: на полной выборке его нет вовсе, а не false. Это касается условных пометок — data.aggregates.<поле>.truncated, того же ключа внутри groups[].aggregates и groups[].truncated. На data.meta.truncated правило не распространяется: он присутствует всегда и на полной выборке равен false, поэтому проверять там нужно значение, а не наличие ключа.
Признак стоит в том объекте, из которого читается число: при усечении сам объект группы несёт groups[].truncated рядом со своим count. На группировке с одним только count это единственная пометка у числа — у count-выражения объекта поля не возникает вовсе, и оба бэга aggregates приходят пустыми.
Пометка говорит, что ответ — образец. Точен ли при этом сам счётчик группы, зависит от пути, и путь называет meta.aggregatePath: на обычном обходе (поля нет) groups[].count — это размер прочитанного среза, а не всей группы, и как итог по группе его использовать нельзя. В режиме счётчиков по стадиям (meta.aggregatePath: "fanout") счётчик берётся отдельной пробой и точен — образцом там остаются только aggregates рядом с ним. Точные числа его не несут никогда: data.count и meta.totalRecords берутся отдельным быстрым подсчётом и верны на выборке любого размера. Тем же условием добавляется предупреждение AGGREGATE_TRUNCATED в meta.warnings — второй канал для клиента, который проверяет meta.warnings перед тем, как считать выдачу полной.
Что с этим делать — способа ровно два: сузить фильтр так, чтобы выборка уложилась в потолок, либо взять один count — без groupBy и без числовых функций. count точен на выборке любого размера, потому что записи для него не выгружаются вовсе.
Добавление groupBy к числовой агрегации потолок не снимает ни на одном аккаунте: группировка заставляет запрос выгружать записи, поэтому такая агрегация считается по той же обрезанной странице и приходит ровно такой же неполной. Повторять ту же сумму, дописав groupBy, — единственное, чего делать не стоит: это ровно тот дорогой вызов, ради ограничения которого потолок и существует.
У сделок есть отдельный режим счётчиков по стадиям, который отвечает точными числами, не читая строк, — но он включается по аккаунтам, и по усечённому ответу нельзя понять, включён ли он у вас. Не угадывайте, а проверьте одним запросом: { "aggregate": [{ "field": "*", "function": "count" }], "groupBy": "stageId" } со скалярным categoryId в фильтре. Сработал режим — в ответе будет meta.aggregatePath: "fanout" и meta.recordsProcessed: 0, а счётчики точны. Не сработал — придёт обычный усечённый ответ, и вы потеряете только этот один вызов.
Само число суммы при усечении — образец по части записей, а не итог, и как итог его использовать нельзя.
У сделок есть отдельный режим счётчиков по стадиям, который отвечает без выгрузки записей, но обходом потолка в общем случае он не является и по умолчанию выключен: его включает администратор платформы по аккаунтам, он работает только для groupBy по stageId или stageSemanticId со скалярным categoryId и только без числовых функций. Пока он выключен — а это состояние по умолчанию, — такой запрос идёт обычным путём и выше потолка приходит усечённым. Условия целиком — Агрегация сделок.
Агрегация POST — сужающий фильтр у дел
У дел ограничение другого рода, и оно касается даже простого count: Битрикс24 не успевает посчитать все дела аккаунта за отведённое на вызов время. Поэтому агрегация дел требует одного сужения — пара ownerTypeId + ownerId, либо responsibleId, либо граница по дате на createdAt / updatedAt / deadline. Без сужения приходит 400 MISSING_REQUIRED_FILTER с перечнем допустимых сужений, а если требование на аккаунте ещё не включено — 422 AGGREGATION_LIMIT_EXCEEDED в тот момент, когда Битрикс24 действительно не ответил. Ни то, ни другое повторять бессмысленно. Подробно — Агрегация дел.
Агрегация POST — UF-поля
Канонический POST-вариант агрегации принимает массив выражений и поддерживает пользовательские поля. Имя поля — то же, что в схеме сущности: на другое написание приходит 400 INVALID_PARAMS со списком доступных полей.
curl -X POST https://vibecode.bitrix24.tech/v1/deals/aggregate \
-H "X-Api-Key: $KEY" \
-H "Content-Type: application/json" \
-d '{
"aggregate": [
{ "function": "sum", "field": "amount" },
{ "function": "sum", "field": "ufCrmBudget" },
{ "function": "avg", "field": "ufCrmScore" }
],
"groupBy": "ufCrmPriority"
}'
Правила UF-поддержки:
| Функция | Принимает UF-типы |
|---|---|
sum, avg, min, max |
только integer, double, money |
groupBy |
любой UF-тип — string, enumeration, date, integer и другие |
Поля типа money хранятся в Битрикс24 как строка "сумма|валюта" (например "1500.50|RUB"). Агрегат извлекает числовую часть до | — все арифметические операции корректны.
Ошибки:
| HTTP | Код | Когда |
|---|---|---|
| 400 | INVALID_PARAMS |
UF-тип не из списка integer/double/money для sum/avg/min/max — в message указан фактический тип |
| 400 | INVALID_PARAMS |
Поле не найдено ни в схеме, ни в UF-кэше — в message перечислены доступные стандартные и UF-поля |
Кэш UF-полей: одно обращение к crm.{entity}.fields на комбинацию портал+сущность (плюс entityTypeId для items). TTL 5 минут — повторные агрегаты в пределах окна не вызывают дополнительных запросов.
Схема полей — `GET /v1/{entity}/fields`
Получить описание всех полей сущности с типами.
curl -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/deals/fields"
Метаданные каждого поля в ответе содержат отображаемое название label и пояснение назначения description, где они заданы для поля. Названия полей не нужно искать в отдельном справочнике — они приходят вместе со схемой.
Названия и пояснения приходят на русском языке. Заголовками запроса язык не переключается. Названия полей, которые платформа берёт напрямую с портала, включая пользовательские, приходят на языке портала.
Пакетные операции — `POST /v1/{entity}/batch`
Массовое создание, обновление или удаление записей одной сущности.
{ "action": "create", "items": [{ "title": "Сделка 1" }, { "title": "Сделка 2" }] }
Действие list принимает filter, select и limit, как и одиночный список, и отбор применяется к ответу: в записях остаются только перечисленные поля плюс id. Незнакомое имя приезжает предупреждением UNKNOWN_SELECT_FIELD в meta этого подвызова — соседние подвызовы своё meta не получают. У сущностей, чей набор полей выверен по Битрикс24, такое имя вместо предупреждения отклоняет подвызов ошибкой UNKNOWN_SELECT_FIELD: отказывает только он, соседи по пакету выполняются. Значение * (и UF_*, в любом регистре) означает «вернуть все поля» — отбор не применяется, и незнакомое имя рядом с ним ничего не отклоняет. Важно: order эта дверь НЕ читает — порядок задаёт сама платформа, и переданный в подвызове order не применяется. Нужна сортировка — берите глобальный POST /v1/batch и передавайте её под именем sort: order он тоже не переводит в имена полей Битрикс24.
Для работы с разными сущностями в одном запросе используйте Batch API.
Формат ответа
Все эндпоинты возвращают единый формат:
{
"success": true,
"data": [ ... ],
"meta": { "total": 150, "hasMore": true }
}
| Поле | Описание |
|---|---|
success |
true при успешном выполнении |
data |
Массив записей у list и search, объект у get и create |
meta.total |
Общее количество записей под фильтр у list и search. Необязательное поле: если количество не заказывалось, его в ответе нет — см. Листание и количество записей |
meta.hasMore |
Есть ли ещё записи для загрузки |
meta.nextAfterId |
Идентификатор последней отданной записи, строкой. Приходит у списка и у поиска при сортировке строго по id по возрастанию, пока meta.hasMore равен true. Передаётся обратно как filter[>id]. Сущности с курсором перечислены в Листании и количестве записей |
meta.pageErrorSample |
Приходит у списка и у поиска, когда часть страниц не загрузилась: code и message первой ошибки. Ответ при этом содержит непрерывное начало выборки, а не все записи. code — либо код ошибки Битрикс24, либо код самого Вайбкод. Последних три. KEYSET_DISCONTINUITY означает, что обход прервал сам Вайбкод, обнаружив разрыв в последовательности страниц, и вернул непрерывное начало вместо возможных дублей. PAGE2_COUNT_FAILED — не удался подсчёт записей (тайм-аут, лимит запросов, ошибка портала). LAZY_COUNT_NO_PROGRESS — метод вернул те же записи вместо следующих. meta.total отсутствует только у двух последних: там подсчёт не состоялся. При остальных обрывах количество уже сосчитано, и meta.total приходит рядом |
meta.windowErrorSample |
То же для поиска по окнам: code и message первого сорвавшегося окна. Приходит вместе с meta.windowErrors — числом неудачных окон. При полном отказе поиск возвращает ошибку, а не частичный ответ |
meta.warnings |
Массив предупреждений о выдаче: у списка, поиска, получения записи по id, запроса схемы полей, у товарных позиций сущности и у агрегации. У каждого есть code и message, а field — только когда предупреждение привязано к конкретному полю. Коды LIMIT_ZERO_IGNORED и UNKNOWN_SELECT_FIELD описаны в параметрах выше. WINDOW_TRUNCATED — оконный поиск отдал не всё, разбор в неполной выдаче. OFFSET_BEYOND_FETCHED_PAGE — страница вышла пустой на постраничном обходе, разбор в обходе по страницам вручную. AGGREGATE_TRUNCATED — числовая агрегация посчитана по части записей, разбор в потолке 5000 записей |
Форма выше — про сущности этого справочника. Другие семейства маршрутов кладут служебные поля иначе:
- Глобальный POST /v1/batch —
results,errors,summary,totalsиmetaлежат внутриdata, с разбивкой поidкаждого вызова. - Выделенные маршруты — чаты, почта, лента, база знаний, звонки, рабочий день — несут свою форму
data, она описана на страницах этих разделов.
Листание и количество записей
Листайте по meta.hasMore, а не по арифметике от meta.total. Признак «есть ещё» выводится из полноты страницы: пришла полная — возможно, есть ещё, пришла неполная — список закончился. Цикл «читай, пока hasMore» доходит до конца всегда. Если коллекция ровно кратна limit, последний шаг вернёт пустой список — это штатный признак конца, а не ошибка.
При сортировке строго по id по возрастанию ответ дополнительно несёт meta.nextAfterId — идентификатор последней отданной записи. Передайте его обратно как filter[>id], и следующая страница начнётся ровно за ней. Такое листание не зависит от смещения и не дорожает к концу коллекции, поэтому для обходов в десятки тысяч записей оно предпочтительнее растущего offset. Готовый цикл обхода — Постраничный вывод.
Курсор доступен у сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов. У остальных сущностей meta.nextAfterId в ответе нет: страницы там берутся offset, а размер выборки сокращается фильтром.
Количество записей — отдельный вопрос, и стоит он у Битрикс24 несоразмерно дорого: посчитать коллекцию заметно дороже, чем отдать из неё страницу. Поэтому:
- Нужна цифра — спросите её прямо:
POST /v1/{entity}/aggregateс функциейcountвозвращает количество одним вызовом, без выгрузки записей. - Цифра не нужна — уберите её из ответа:
withTotal=falseв запросе списка или настройкаtotalDefaultна API-ключе, если так работает вся интеграция. Про то, в каких случаяхmeta.totalпри этом всё же приходит, — ниже в этом разделе. Важно: Нагрузку это снимает только на одностраничном вызове (limitне больше 50): там подсчёт действительно не заказывается. На многостраничном (limitбольше 50) подсчёт платформе нужен, чтобы спланировать обход, поэтому параметр убирает число, а не стоимость. Ставить его ради экономии там незачем: дешевле вызов не станет, а точное количество, которое короткая первая страница отдаёт бесплатно, будет отброшено. - Не эмулируйте счётчик обходом. Пролистать коллекцию, чтобы посчитать строки, — это десятки и сотни вызовов вместо одного и самый дорогой способ узнать одну цифру. Для этого есть
aggregateсcount.
Когда подсчёт не заказан, meta.total в ответе чаще всего отсутствует — но не всегда. Если страница пришла короче запрошенного limit, количество известно из самой страницы, и точное число всё равно приходит. Полная картина:
| Что было в запросе | meta.total в ответе |
|---|---|
Подсчёт заказан — умолчание или withTotal=true |
приходит |
Передан withTotal=false |
не приходит никогда |
Подсчёт отключён настройкой ключа или платформенным умолчанием, offset = 0, страница короче limit |
приходит, точное число — в том числе 0 |
Подсчёт отключён настройкой ключа или платформенным умолчанием, страница полная либо offset больше нуля |
не приходит |
Таблица описывает вызов, на котором подсчёт можно пропустить. Там, где пропустить его нельзя, withTotal=false просто игнорируется и meta.total приходит как раньше. Поэтому проверяйте наличие поля в конкретном ответе, а не выводите его из настроек.
Короче: если подсчёт не заказан, total приходит только на вызове с offset = 0 и только если страница пришла короче запрошенного. Если подсчёт заказан — умолчанием или явным withTotal=true — он приходит всегда. Обратите внимание на разницу между параметром и настройкой: явный withTotal=false в запросе убирает и точное число из короткой страницы, а настройка totalDefault на ключе — нет. Поэтому два одинаковых запроса от двух разных ключей могут вернуть ответы разной формы.
Из «подсчёт заказан — приходит всегда» есть одно исключение — частичный ответ, у которого сорвался сам подсчёт. Если в ответе есть meta.pageErrorSample с кодом PAGE2_COUNT_FAILED или LAZY_COUNT_NO_PROGRESS, meta.total отсутствует: количество не сосчитано, а число отданных строк его не заменяет. При остальных обрывах — KEYSET_DISCONTINUITY и любой код Битрикс24 — подсчёт состоялся до обрыва, и meta.total приходит рядом с meta.pageErrorSample. И тот и другой ответ приходит с кодом 200, содержит непрерывное начало выборки и meta.hasMore, равный true.
Сам подсчёт платформа выполняет, только когда без него не обойтись. На форме ответа это не сказывается: на многостраничном вызове (limit больше 50) meta.total приходит так же, как приходил, — просто иногда количество оказывается известно бесплатно.
meta.total — информативное поле. Оно может отставать от текущего состояния коллекции до минуты, поэтому число отданных строк иногда оказывается больше него. Полнота данных от meta.total не зависит: за неё отвечают meta.hasMore и meta.nextAfterId.
Действующее для вашего ключа умолчание по meta.total показывает блок totalDefault в GET /v1/me: key — настройка ключа, platform — платформенное умолчание, effective — что получится, если запрос не передаст withTotal.
Преобразование полей
Вайбкод автоматически преобразует имена полей при отправке запроса. В запросах всегда используйте camelCase:
{ "title": "Сделка", "stageId": "NEW", "assignedById": 1 }
В ответах объявленные поля сущностей приходят в camelCase — id, title, stageId, responsibleId.
Пользовательские поля портала — отдельный случай. Их состав зависит от портала, заранее они не описаны, а часть полей носит имя, сгенерированное самим Битрикс24. Имя, под которым такое поле принимается в запросе и приходит в ответе, берите из схемы GET /v1/{entity}/fields — написание различается по сущностям. Имена и форматы значений собраны в разделе Пользовательские поля (UF).
Отличается не только регистр — у части полей отличается само имя. Например, сумма сделки в Вайбкод называется amount, а исходное имя этого поля в Битрикс24 — opportunity. Имя Вайбкод стоит в колонке «Поле» схемы GET /v1/{entity}/fields, исходное имя Битрикс24 — в колонке «Битрикс24». В запросах и при чтении ответа используйте имя из колонки «Поле» — под ним поле и приходит в ответе, исходное имя Битрикс24 не возвращается. Список соответствий для каждой сущности — на её странице полей, например Поля сделки.
Часовой пояс на записи
Дата-время, записанное без пояса (2026-07-15T13:00:00), Битрикс24 читает в поясе того аккаунта, через который платформа пишет на портал, — а не в вашем. Клиент из Берлина, отправивший 13:00, получал сохранённые 10:00 по Гринвичу вместо 11:00: разница в час летом и в два зимой.
Чтобы этого не было, объявите свой пояс заголовком запроса:
X-Vibe-Timezone: Europe/Berlin
Значение — имя пояса из базы IANA. В браузере оно берётся из Intl.DateTimeFormat().resolvedOptions().timeZone, серверная интеграция подставляет пояс, в котором ведёт свои данные.
Заголовок необязателен и ничего не ломает. Без него, с неизвестным именем пояса или с мусором вместо имени поведение остаётся прежним — значение уходит на портал как есть. Отказа не будет: заголовок добавлен так, чтобы ни один существующий вызов не изменил поведения молча.
Смещение получает только запись вида ГГГГ-ММ-ДДTЧЧ:ММ, где пояс не указан, и только в тех полях, где заголовок действует. Секунды и доли секунды не обязательны и на подстановку не влияют, а перечень полей — ниже. Остальные формы даты-времени уходят на портал без изменений, и заголовок на них не действует:
| Что отправлено | Что уходит на портал |
|---|---|
2026-09-15T13:00:00 |
2026-09-15T13:00:00+02:00 — смещение подставлено |
2026-09-15T13:00, 2026-09-15T13:00:00.500 |
смещение подставлено так же — без секунд и с долями секунды |
2026-09-15T13:00:00Z или со смещением |
как есть — пояс объявлен вами, платформа его не переписывает |
2026-09-15 13:00:00 через пробел |
как есть — читается в поясе портального аккаунта |
15.09.2026 13:00 в местной форме |
как есть — читается в поясе портального аккаунта |
Две последние формы отказа не вызывают: ответ приходит успешным, а сохранённое время отличается на разницу между вашим поясом и поясом портала. Для заголовка Europe/Berlin и портала в поясе UTC+3 запись 2026-09-15T13:00:00 сохраняется как 2026-09-15T11:00:00Z, а те же 13:00 через пробел — как 2026-09-15T10:00:00Z.
Переход на летнее время учитывается по каждому значению отдельно. Смещение берётся то, которое действовало в поясе на саму дату из значения, а не на момент запроса. Одна и та же интеграция, записывающая июльскую и январскую даты в одном запросе, получит корректные обе.
Пояс подставляется не всем полям подряд, а только проверенным. Битрикс24 объявляет частью полей тип «дата и время», а хранит в них голую дату — подставленное смещение сдвинуло бы у такого поля день. Поэтому список полей открывается по мере живой проверки каждого. Сегодня в нём поля задачи: deadline, startDatePlan, endDatePlan, а также служебные createdDate, changedDate, closedDate — значение вида 2019-05-15T13:47:00 получает у них смещение вашего пояса, а не читается в поясе владельца ключа. Где заголовок действует, видно по машинному описанию API — у операции он объявлен в списке параметров.
Отдельно стоят события календаря: у них пояс задаётся собственными параметрами запроса (timezoneFrom / timezoneTo), поэтому заголовок для них игнорируется — иначе событие сдвинулось бы дважды.
Заголовок влияет только на запись. На фильтр он не действует — значения фильтра читаются в поясе портального аккаунта независимо от заголовка. Что из этого следует для поиска по датам и как пересчитать границы — Часовой пояс в значении фильтра.
Мультиполя (email, телефон, сайт)
Контактные поля email, phone и web хранят несколько значений с типами. Набор зависит от сущности — email и phone есть у контактов, компаний и лидов, web только у компаний. Формат отличается на запись и на чтение.
На запись — массив объектов [{ "value": "petrov@example.com", "typeId": "WORK" }]. Также принимается одиночная строка "petrov@example.com" и массив строк. Значение typeId зависит от поля — WORK / HOME / MOBILE / OTHER для телефона, WORK / HOME / MAILING / OTHER для email. По умолчанию WORK.
{ "email": [{ "value": "petrov@example.com", "typeId": "WORK" }] }
Форма с ключами VALUE и VALUE_TYPE в верхнем регистре не принимается — 400 INVALID_MULTIFIELD_SHAPE. Используйте camelCase value и typeId.
На чтение — первичное значение приходит строкой ("email": "petrov@example.com"), а полный набор значений с типами лежит в массиве fm. Значения по типам доступны в отдельных полях (emailWork, phoneMobile).
Точный набор typeId и полей чтения для каждой сущности — на её странице, например Контакты и Компании.
Пользовательские поля (UF)
Пользовательские поля портала читаются и записываются наравне с объявленными полями сущности — отдельного эндпоинта для значений нет. Создание, изменение и удаление самих полей — в разделе Пользовательские поля.
Имя поля
Рабочее имя одно — то, под которым поле стоит в схеме GET /v1/{entity}/fields. Под этим именем поле принимается в теле запроса, в filter и в select, под ним же оно приходит в ответе. Написание различается по сущностям, и вывести его из имени, заданного при создании, нельзя:
| Сущность | Примеры имён в схеме |
|---|---|
| Сделки, лиды, контакты, компании, предложения | ufCrmProjectCode, ufCrm_1729594209 |
| Элементы смарт-процессов | ufCrm3_1628508847 |
| Реквизиты | UF_CRM_1698325419 |
| Сотрудники | UF_USR_1619099890455, UF_PHONE_INNER |
Список определений полей и схема сущности называют одно и то же поле по-разному. Поле, созданное на сделках как fieldName: "PROJECT_CODE", стоит в ответе GET /v1/userfields/deals под именем UF_CRM_PROJECT_CODE, а в схеме сделки и во всех запросах — под именем ufCrmProjectCode.
Имя, которого нет в схеме, не даёт ошибки при записи. У сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов значение, отправленное под именем UF_CRM_PROJECT_CODE вместо ufCrmProjectCode, не сохраняется: ответ приходит с кодом 200 или 201, а поле остаётся пустым. В select такое имя не добавляет поле в ответ, в агрегации — на него приходит 400 INVALID_PARAMS со списком доступных полей. Поведение отбора — Неизвестное имя поля в фильтре.
Формат значения по типам
Тип поля задаётся при создании параметром userTypeId и приходит в схеме сущности в поле type.
Примеры ниже сняты на портале в поясе UTC+3.
| Тип | Что отправлять | Что приходит в ответе |
|---|---|---|
string |
"Договор №17" |
Та же строка |
integer |
42 или "15" |
Число. Дробное значение обрезается до целого — 3.7 сохраняется как 3 |
double |
3.14 или "7.25" |
Число, округлённое до числа знаков после запятой, заданного настройкой PRECISION этого поля. При PRECISION равном 2 значение 3.14159 приходит как 3.14. Поле, созданное без settings, получает PRECISION равный 0 и хранит целые: 3.14 приходит как 3, а 3.99 — как 4 |
boolean |
true, false, "Y", "N". Значения 1, 0, "1" и "0" сохраняются как отрицательное значение — false у сделок, "N" у остальных |
У сделок — true или false. У контактов, лидов, компаний, предложений и элементов смарт-процессов — строки "Y" и "N" |
enumeration |
Идентификатор варианта — "3821". Варианты поля перечислены в массиве items схемы сущности |
Идентификатор числом — 3821. Текст варианта вместо идентификатора сохраняется как 0 |
datetime |
"2026-08-10T12:30:00" — время читается в поясе портала. Смещение можно указать явно |
У сделок — момент времени по Гринвичу, "2026-08-10T09:30:00.000Z". У контактов, лидов, компаний, предложений и элементов смарт-процессов — то же время со смещением портала, "2026-08-10T12:30:00+03:00" |
date |
"2026-08-10" |
Полный момент времени со смещением портала — "2026-08-10T03:00:00+03:00" |
money |
"100|USD" — сумма и код валюты через вертикальную черту. Значение без кода валюты сохраняется в базовой валюте портала |
"100|USD". Отправленное 100 приходит как "100|RUB", "250.50|RUB" — как "250.5|RUB" |
url |
"https://example.com/contract" |
Та же строка |
address |
"Москва, Тверская 1|55.7601;37.6055" — адрес и координаты разделяет вертикальная черта, широту и долготу — знак ; |
Та же строка. Широта и долгота, разделённые вертикальной чертой вместо ;, не сохраняются |
employee |
1 — идентификатор сотрудника, список: GET /v1/users |
1 |
crm |
"L_1000739" — буквенный префикс типа и идентификатор записи: L_ лид, C_ контакт |
Та же строка |
crm_status |
"NEW" — значение statusId, список: GET /v1/statuses |
Та же строка |
file |
["contract.pdf", "BASE64_CONTENT"] — имя файла и содержимое в Base64 |
У поля с одним значением — объект с полями id, url, urlMachine, у множественного — массив таких объектов. Подробнее — Файлы в CRM |
Настройка PRECISION задаётся при создании поля — "settings": { "PRECISION": 2 }, см. Создать поле.
Заголовок X-Vibe-Timezone из раздела Часовой пояс на записи на пользовательские поля не действует: значение без смещения читается в поясе портала.
Значения типов employee, crm и crm_status сохраняются без сверки со справочником портала: идентификатор несуществующего сотрудника или значение вне справочника принимаются и возвращаются как есть. Проверяйте их на своей стороне.
Несколько значений в одном поле
Признак множественности приходит в списке определений полей — поле multiple со значением Y или N. Для сделок, лидов, контактов, компаний, предложений и реквизитов это GET /v1/userfields/:entity, для смарт-процессов — GET /v1/items/:entityTypeId/userfields. У пользовательского поля в схеме GET /v1/{entity}/fields этого признака нет.
Значение множественного поля передаётся массивом и заменяет прежний набор целиком:
{ "ufCrmProjectTags": ["первое", "второе"] }
Одиночное значение вместо массива не сохраняется. Пустой массив и null оставляют прежние значения — очистить множественное поле пустым массивом или null нельзя.
Очистка значения
Поле с одним значением очищается значением null или пустой строкой, а файловое поле с одним значением — пустым массивом. В ответе очищенное поле приходит как null. Множественное поле ничем из перечисленного не очищается.
Особые сущности
Смарт-процессы (`items`)
Смарт-процессы используют entityTypeId в URL: GET /v1/items/{entityTypeId}.
# Список записей смарт-процесса с entityTypeId = 1058
curl -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/items/1058?limit=10"
Список доступных смарт-процессов: GET /v1/smart-processes.
События календаря
Требуют обязательные параметры: type со значением user, group или company, и ownerId.
curl -H "X-Api-Key: $KEY" \
"https://vibecode.bitrix24.tech/v1/calendar-events?type=user&ownerId=1"
Файлы
Требуют folderId. Получите его из GET /v1/storages → поле rootFolderId.
Лимиты
10 запросов/секунду — лимит Битрикс24 на уровне портала, общий для всех ключей.
Как укладываться в лимит:
- Batch API — 50 вызовов за 1 единицу лимита
POST /v1/{entity}/batch— до 500 записей CRUD за 10 единиц (а не за 500)POST /v1/{entity}/aggregate—countидёт одним быстрым вызовом, аsum/avg/min/maxподгружают до 5000 записей и считаются на стороне Вайбкод- Параметр
select— загрузка только нужных полей сокращает объём ответа
Подробнее: Оптимизация — паттерны для дашбордов, массовых операций, сканирования больших объёмов
Запись ключом в режиме «только чтение»
Ключ с режимом доступа «только чтение» выполняет чтение и получает 403 WRITE_BLOCKED_READONLY_KEY на любой вызов записи — создание, обновление, удаление, действие над сущностью. Полное описание кода и полей details — Коды ошибок. Как переключить режим и как работает политика портала — Режим доступа.
Паттерны использования
| Задача | Подход |
|---|---|
| Дашборд / аналитика | POST /v1/{entity}/aggregate — счётчики и суммы по фильтру |
| Массовое обновление | POST /v1/{entity}/batch с action=update |
| Данные из нескольких сущностей | POST /v1/batch — deals, tasks и contacts в одном запросе |
| Запись + связанные данные | ?include=company,contact — связанные данные в одном ответе |
| Сканирование десятков тысяч записей | Курсор по id — order[id]=asc плюс filter[>id] из meta.nextAfterId, см. Листание и количество записей. Где курсора нет — POST /v1/{entity}/search с limit до 5000 и сужением фильтра |
Смотрите также
- Связанные данные (include) — загрузка связанных сущностей в одном запросе
- Фильтрация — три синтаксиса фильтров, даты, фильтры отрицания
- Batch API — до 50 вызовов в одном запросе
- Справочник API — полный список сущностей со ссылками
- Оптимизация — ограничения частоты, паттерны производительности
- Коды ошибок — справочник ошибок платформы