Для AI-агентов: markdown этой страницы — /docs-content/batch.md индекс документации — /llms.txt

Пакетные вызовы

Один HTTP-запрос объединяет до 50 операций над разными сущностями. Каждый вызов идентифицируется собственным id и обрабатывается независимо: ошибка одного вызова не отменяет остальные.

POST /v1/batch

Скоуп: проверяется индивидуально по сущности (crm, task, im, disk и др.) | Базовый URL: https://vibecode.bitrix24.tech/v1 | Авторизация: X-Api-Key (APP-ключ)

Поля запроса (body)

Поле Тип Обяз. Описание
calls array ★ Массив вызовов (от 1 до 50). Каждый элемент — объект, формат описан в таблице ниже.

Поля одного вызова

Поле Тип Обяз. Описание
id string нет Идентификатор вызова в ответе. Если не передан — присваивается порядковый индекс ("0", "1", ...). Длина до 64 символов.
entity string ★ Имя сущности во множественном числе: deals, contacts, companies, tasks, users, files, folders и другие. Полный список сущностей, доступных вашему ключу, возвращает GET /v1/me — см. Ключи и авторизация.
action string ★ Операция: list, get, create, update, delete, fields, search.
entityId number / string для get / update / delete Идентификатор записи.
params object нет Параметры операции в едином entity-формате (имена полей в camelCase, фильтры в синтаксисе фильтрации).

Параметры внутри params совпадают с параметрами одиночного эндпоинта Entity API:

  • list и search — filter, select, sort, order, limit. Имя принятого поля в sort переводится всегда, пример краткой формы — "-id". Объект order переводится в имена полей Битрикс24 у сущностей с sortKeysCaseSensitive, sortFlatParams или enforceUnknownSortFields — в том числе users, requisites и requisite-presets. У users единственное поддержанное обычное поле сортировки — id, а UF_* сохраняет сквозную передачу только при limit ≤ 50 и offset = 0. Несколько распознанных полей users, а также UF_* при limit > 50 или offset > 0 заменяются целиком на id по возрастанию. Подвызов выполняется, а в data.meta[<id>].warnings приходит одно предупреждение SORT_FALLBACK_TO_ID с полем sort. Одиночное обычное поле не по id по-прежнему возвращает UNKNOWN_SORT_FIELD для своего подвызова, соседние выполняются. У остальных сущностей, включая deals, order сохраняет прежнее поведение: передаётся дословно и может быть молча проигнорирован Битрикс24. Если переданы оба параметра, итоговый порядок задаёт sort, но order всё равно валидируется. Ошибка остаётся внутри подвызова, соседние вызовы выполняются. Отдельно withTotal: он действует только у list и только при нулевом offset (см. ниже). Переданный select применяется и к ответу: в записях остаются только перечисленные поля плюс id. Незнакомые имена перечисляются в meta этого вызова как предупреждения UNKNOWN_SELECT_FIELD, а у сущностей со сверенным набором полей отклоняют этот подвызов ошибкой UNKNOWN_SELECT_FIELD — соседние подвызовы при этом выполняются. У реквизитов и банковских реквизитов такое имя вместо предупреждения валит сам подвызов: отказ Битрикс24 приезжает в data.errors под идентификатором подвызова с кодом 100, соседи по пакету выполняются. Значение * (и UF_*, в любом регистре) означает «вернуть все поля» — отбор не применяется
  • get — поле include, если сущность его поддерживает
  • create и update — поля сущности (имена в camelCase), плоско внутри params. Если схема не объявляет fields, объект params.fields отклоняется ошибкой NESTED_FIELDS_ENVELOPE для этого вызова; передавайте поля непосредственно в params
  • delete и fields — параметры не нужны
  • смарт-процессы (entity: "items") — внутри params обязательно entityTypeId

Количество записей в списочном вызове. withTotal: false в params означает «количество не нужно»: data.totals.<id> и meta.<id>.total в ответе не приходят. Границы применимости стоит знать: параметр действует на вызовах action: "list" — и при limit не больше 50 с нулевым offset, и при limit больше 50. У action: "search" и у пакета одной сущности POST /v1/{entity}/batch он инертен — подсчёт заказывается как раньше. Инертен он и на list сущностей mail-mailboxes и humanresources-nodes: там количество приходит всегда. Важно: Подсчёт у Битрикс24 параметр отменяет только при limit не больше 50. При limit больше 50 подсчёт нужен платформе, чтобы спланировать обход подзапроса, поэтому там параметр убирает число, а не нагрузку. Правило присутствия total то же, что у одиночных эндпоинтов: на короткой странице точное количество приходит и без заказа, а у вызова с отключённым подсчётом его не будет при offset больше нуля — см. Листание и количество записей. Границей листания в любом случае остаётся meta.<id>.hasMore.

Отмена подсчёта со стороны Битрикс24 — params.start: -1. Помимо withTotal у подкоманды есть второй, более низкоуровневый способ отказаться от счёта: значение -1 в params.start — это прямая инструкция Битрикс24 «коллекцию не считать». Тогда счёта нет и в ответе портала, поэтому платформа его не публикует: ключа total не будет ни в meta.<id>, ни в data.totals.<id>. Числа взяться неоткуда, и withTotal: true его не вернёт — подсчёт отменил сам клиент. Исключение — события календаря: их набор платформа получает целиком одним ответом и считает количество сама, поэтому total придёт и в этом режиме.

Границу выборки в этом режиме определяет meta.<id>.hasMore, и считается она по полноте страницы, которую вернул Битрикс24: заполнена до его размера страницы — 50 записей — → true, короче → false. У action: "list" клиентский limit до Битрикс24 не доезжает, поэтому потолком остаются те же 50. Свой limit уходит на портал только у action: "search", и там полная страница ровно на лимите ({"action":"search","params":{"limit":10,"start":-1}} при десяти записях) — это hasMore: true, а не «всё найдено».

Значение читается так же, как его читает Битрикс24 — дробное усекается, строка разбирается по числовому префиксу, — поэтому -1, "-1", -1.5 и "-1abc" означают одно и то же. Положительное смещение (start: 100) остаётся обычным счётным курсором, total по нему приходит как раньше. Значение, которое числом не является вовсе ("abc", пустая строка, null, объект, массив, true), читается как непереданное: страница будет та же, что и без start, но подкоманда возвращается под общее правило подсчёта записей и может прийти без total.

Важно: start: -1 — не курсор, а отказ от счёта: он всегда отдаёт начало коллекции, и повторный вызов с тем же значением вернёт ту же страницу. Чтобы двигаться дальше, переходите на положительное смещение (start: 100) — по нему total приходит.

Проверяйте наличие ключа (meta.<id>.total !== undefined), а признаком непрочитанного остатка считайте hasMore — так код одинаково работает в обоих режимах.

Идентификатор записи для get / update / delete передаётся в поле entityId на уровне вызова, не в params.id. Вызов { "entity": "users", "action": "get", "params": { "id": 1 } } без entityId отклоняется как MISSING_ENTITY_ID, и вся пачка возвращает 400 с ошибкой валидации. Правильно: { "entity": "users", "action": "get", "entityId": 1 }. Поле params у get служит только для include. Так же строятся update и delete — идентификатор в entityId, изменяемые поля для update в params: { "entity": "deals", "action": "update", "entityId": 575, "params": { "title": "Новое название" } } и { "entity": "contacts", "action": "delete", "entityId": 42 }. Успех update и delete определяется по data.summary.succeeded и отсутствию id в data.errors.

Примеры

curl — личный ключ

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/batch \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      {
        "id": "deals",
        "entity": "deals",
        "action": "list",
        "params": {
          "filter": { "stageId": "NEW" },
          "select": ["id", "title", "amount"],
          "limit": 50,
          "withTotal": true
        }
      },
      {
        "id": "contacts",
        "entity": "contacts",
        "action": "list",
        "params": {
          "select": ["id", "name", "lastName"],
          "limit": 20,
          "withTotal": true
        }
      },
      {
        "id": "user1",
        "entity": "users",
        "action": "get",
        "entityId": 1
      }
    ]
  }'

curl — OAuth-приложение

Terminal
curl -X POST https://vibecode.bitrix24.tech/v1/batch \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      {
        "id": "deals",
        "entity": "deals",
        "action": "list",
        "params": {
          "filter": { "stageId": "NEW" },
          "select": ["id", "title", "amount"],
          "limit": 50,
          "withTotal": true
        }
      },
      {
        "id": "contacts",
        "entity": "contacts",
        "action": "list",
        "params": {
          "select": ["id", "name", "lastName"],
          "limit": 20,
          "withTotal": true
        }
      },
      {
        "id": "user1",
        "entity": "users",
        "action": "get",
        "entityId": 1
      }
    ]
  }'

JavaScript — личный ключ

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    calls: [
      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50, withTotal: true } },
      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20, withTotal: true } },
      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }
    ]
  })
})

const { data } = await res.json()
console.log('Сделки:', data.results.deals)
console.log('Контакты:', data.results.contacts)
console.log('Сводка:', data.summary)

JavaScript — OAuth-приложение

javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/batch', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    calls: [
      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50, withTotal: true } },
      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20, withTotal: true } },
      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }
    ]
  })
})

const { data } = await res.json()
console.log('Сделки:', data.results.deals)

Поля ответа

Поле Тип Описание
success boolean true, если запрос принят. Частичные ошибки внутри data.errors не переводят его в false.
data.results object Результаты по id каждого вызова. Значение — то, что вернул бы соответствующий эндпоинт Entity API: массив записей для list / search, объект для get / create, нормализованная запись для update, объект { id, deleted: true } для delete, схема полей для fields.
data.totals object Общее количество записей под фильтр для list / search-вызовов. Ключи — id соответствующих вызовов. У list-вызова присутствие подчиняется тому же правилу, что meta.total одиночного списка: не заказал количество — ключа нет. У search-вызова количество заказывается всегда. Плюс своя ветка: отрицательный params.start отменяет подсчёт на стороне Битрикс24, и тогда числа нет даже при withTotal: true. Оба случая разобраны в абзацах «Количество записей в списочном вызове» и «Отмена подсчёта со стороны Битрикс24» выше. Вызова, завершившегося ошибкой, — тоже нет.
data.errors object Ошибки по id неудачных вызовов. Каждое значение — { "code": "...", "message": "..." }.
data.summary.total number Общее количество вызовов в запросе.
data.summary.succeeded number Количество успешных вызовов.
data.summary.failed number Количество вызовов с ошибкой.
data.meta object Дополнительные сведения по id вызовов с action: "list" или action: "search": total (может отсутствовать — см. выше), returned, hasMore, truncated, а при потере страницы выборки — pageErrorSample.
data.meta.<id>.warnings array Предупреждения по этому вызову. Появляется, только когда они есть. Приходят те же коды, что у одиночного эндпоинта, и в той же форме — code, field, message. Для заменённой сортировки users приходит одно предупреждение с code: "SORT_FALLBACK_TO_ID" и field: "sort". Обычная сортировка по id предупреждение не добавляет. Ошибка выполнения остаётся в data.errors. Разбирайте массив по code, не по позиции.

Пример ответа

JSON
{
  "success": true,
  "data": {
    "results": {
      "deals": [
        { "id": 575, "title": "Тест валюты", "amount": 0 },
        { "id": 741, "title": "Поставка оборудования", "amount": 250000 }
      ],
      "contacts": [
        { "id": 1, "name": "Иван", "lastName": "Петров" }
      ],
      "user1": [
        { "ID": "1", "NAME": "Мария", "ACTIVE": true }
      ]
    },
    "totals": {
      "deals": 1798,
      "contacts": 305
    },
    "errors": {},
    "summary": {
      "total": 3,
      "succeeded": 3,
      "failed": 0
    },
    "meta": {
      "deals": { "total": 1798, "returned": 2, "hasMore": true, "truncated": false },
      "contacts": { "total": 305, "returned": 1, "hasMore": true, "truncated": false }
    }
  }
}

Частичные ошибки

Если часть вызовов не прошла проверку или вернула ошибку на стороне Битрикс24, успешные результаты остаются в data.results, неудачные — в data.errors под тем же id:

JSON
{
  "success": true,
  "data": {
    "results": {
      "deals": [
        { "id": 575, "title": "Тест валюты" }
      ]
    },
    "totals": {
      "deals": 1798
    },
    "errors": {
      "unknown": {
        "code": "UNKNOWN_ENTITY",
        "message": "Unknown entity \"foobar\". Check GET /v1/guide for available entities."
      }
    },
    "summary": {
      "total": 2,
      "succeeded": 1,
      "failed": 1
    },
    "meta": {
      "deals": { "total": 1798, "returned": 1, "hasMore": true, "truncated": false }
    }
  }
}

Запись, которую Битрикс24 принял, но не применил, — тоже ошибка подвызова. Подвызов create или update, у которого не применилась стадия или воронка (stageId / categoryId у сделок, stageId / statusId у лидов — несуществующее значение) либо явно запрошенный ручной режим суммы у элемента смарт-процесса (isManualOpportunity: true у типа без товарной части), переходит из data.results в data.errors под своим id с кодом STAGE_NOT_APPLIED или AMOUNT_NOT_APPLIED: message называет запрошенное и фактическое значение, details.unappliedFields и details.currentValues — что не применилось и что стоит в записи, а data внутри этой ошибки несёт запись, которую Битрикс24 вернул в ответе на подвызов, целиком, вместе с её id. Запись при этом уже создана или изменена, остальные поля тела могли примениться: исправьте значение и пошлите только его, а не весь вызов заново. Лишних обращений к Битрикс24 у этой проверки нет — сверяется запись, которую Битрикс24 и так возвращает в ответе на каждый такой подвызов. Тот же вызов с корректным значением отвечает как прежде. Сумма без явного isManualOpportunity: true не проверяется — по ответу её не отличить от законного пересчёта по товарным позициям.

Пауза по лимиту приходит по отдельному вызову. Когда метод приостановлен на несколько минут, отказ достаётся не всему пакету, а конкретному вызову — в data.errors.<id> здесь и в data[i].error у пакета одной сущности POST /v1/{entity}/batch. Приостановку описывают два кода: OPERATION_TIME_LIMIT — приостановлена связка «ваш ключ и этот метод», TIMEOUT_QUARANTINE — пауза действует на весь портал. Конверт при этом отвечает 200, поэтому заголовка Retry-After для отдельного вызова у него нет.

Отдельный вызов может отбиться и по другим причинам, и у каждой свой код. Кроме двух кодов приостановки это RATE_LIMITED: превышен темп запросов к порталу. QUEUE_OVERFLOW и QUEUE_TIMEOUT означают, что очередь портала переполнена или вызов не дождался в ней очереди. Во втором случае запрос до Битрикс24 не дошёл, повтор безопасен. BITRIX_TIMEOUT означает, что портал принял вызов и не ответил в срок, поэтому исход неизвестен. ERROR_LOOP_DETECTED приходит, когда платформа временно приостановила метод после серии отказов. TOKEN_EXPIRED означает, что пользовательская OAuth-сессия приложения истекла: повторно откройте приложение из меню Битрикс24. TOKEN_REFRESH_FAILED означает, что обновить авторизацию портала не удалось и повтор не поможет до переподключения ключа. У двух ошибок авторизации — TOKEN_EXPIRED и TOKEN_REFRESH_FAILED — поля retryAfter нет: повтор не поможет до повторной авторизации. Остальные коды из этого списка приходят с retryAfter в секундах. Отказ без собственного кода приходит как AUTO_PAGINATION_FAILED в общем пакетном вызове и CALL_FAILED в пакете одной сущности. Вызов сущностей bizproc-templates, bizproc-activities и bizproc-robots на портале, где бизнес-процессы не входят в тариф или выключены, приходит с кодом BIZPROC_MODULE_NOT_ENABLED и в общем пакетном вызове, и в пакете одной сущности: повтор не поможет, пока администратор портала не включит бизнес-процессы.

Если вызов отбила платформа, зная о действующей паузе, рядом с кодом приходят retryAfter в секундах, scope и hint — дождитесь срока, а дальнейшее действие выбирайте по коду и семантике именно этого подвызова. Так отбиваются вызовы, которые платформа выполняет отдельными запросами: здесь это search, list, чьё окно не умещается в одну страницу Битрикс24, и list у сущностей mail-mailboxes и humanresources-nodes при любом размере окна. В пакете одной сущности так обрабатывается любой читающий вызов, то есть list, get и fields. Если же паузу применил сам Битрикс24 к вызову внутри общего пакетного запроса, придут только code и message, без срока повтора. Читающий подвызов повторяйте не раньше чем через пять минут. Для записи сначала проверьте эффект по бизнес-ключу или отдельным чтением и повторяйте только когда убедились, что операция не выполнилась. Политика доставки и повторов для каждого кода — Что безопасно повторять.

Пример ответа при ошибке

Если все вызовы не прошли валидацию, возвращается 400 INVALID_REQUEST с разбивкой по id в data.errors:

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "All calls in the batch failed validation"
  },
  "data": {
    "errors": {
      "x": {
        "code": "MISSING_ENTITY_ID",
        "message": "Action \"get\" requires entityId."
      }
    }
  }
}

Ошибки

HTTP Код Описание
400 INVALID_REQUEST Тело запроса не соответствует схеме или все вызовы провалили валидацию.
400 UNKNOWN_ENTITY В одном из вызовов передано неизвестное имя сущности.
400 ACTION_NOT_SUPPORTED Сущность не поддерживает указанное действие (например, delete для справочной сущности без удаления).
400 MISSING_ENTITY_ID Действия get, update, delete требуют entityId.
400 EMPTY_CREATE_BODY Вызов create без единого поля тела. Возвращается для конкретного вызова в data.errors.
400 EMPTY_UPDATE_BODY Вызов update без единого поля тела. Возвращается для конкретного вызова в data.errors.
400 NESTED_FIELDS_ENVELOPE В params передан объект fields, хотя схема сущности не объявляет такое поле. Возвращается для конкретного вызова в data.errors; отправляйте поля плоско внутри params.
400 INVALID_PARAMS В поле, объявленном простым значением, передан объект или массив — в том числе файл парой «имя файла и содержимое в base64», который пакетный вызов не принимает. Возвращается для конкретного вызова в data.errors.
400 UNKNOWN_SORT_FIELD Одиночное обычное поле сортировки users отличается от id. Несколько распознанных полей вместо этого дают fallback на id по возрастанию с SORT_FALLBACK_TO_ID. Ошибка одиночного поля возвращается для конкретного вызова в data.errors, соседние вызовы выполняются.
400 INVALID_SORT_FIELD Сортировка имеет форму, которую сущность не поддерживает: небезопасное имя поля либо несколько полей для сущности с плоской сортировкой. У users несколько распознанных полей вместо отказа дают предупреждение. Ошибка возвращается для конкретного вызова в data.errors, соседние вызовы выполняются.
400 BIZPROC_CALLBACK_BATCH_UNSUPPORTED Вызов create или update для bizproc-activities либо bizproc-robots, где handler ведёт на субдомен Black Hole. Такой обработчик регистрируется одиночным запросом. Возвращается для конкретного вызова в data.errors.
400 MISSING_REQUIRED_PARAMS В list-вызове calendar-events не переданы обязательные type и ownerId в params.
400 UNSUPPORTED_FILTER В params.filter вызова переданы поля, которые метод сущности не принимает как фильтр — например, calendar-events.
400 MISSING_DYNAMIC_PARAM Для смарт-процессов (entity: "items") не передан entityTypeId внутри params.
400 INVALID_DYNAMIC_PARAM entityTypeId для смарт-процессов задан некорректно (не положительное целое).
400 USE_DEDICATED_ENTITY Для переданного entityTypeId существует выделенная сущность — использовать её, а не items.
400 ENTITY_CUSTOM_ROUTES Сущность работает только через специализированные маршруты (например, task-comments — через /v1/tasks/:taskId/comments).
400 INVALID_CALL Объект вызова не содержит обязательных полей entity и action.
401 TOKEN_MISSING У ключа нет настроенных OAuth-токенов или для OAuth-приложения не передан Authorization: Bearer ....
401 TOKEN_REFRESH_FAILED Не удалось обновить OAuth-токен портала.
403 MANAGEMENT_KEY_NO_ENTITY_ACCESS Запрос пришёл с management-ключа — пакетные вызовы доступны только APP-ключам.
403 SCOPE_NOT_ALLOWED Все вызовы запросили скоупы, которых нет у ключа. Если хотя бы один вызов проходит — этот код возвращается внутри data.errors для конкретных вызовов, а сам запрос успешен. Элементы data.errors с этим кодом несут cause = key_scope_missing, requiredScope, fix и hint — разбор в Авторизация, ключи и права.
422 BITRIX_ERROR Битрикс24 отклонил вызов. Тело ответа содержит bitrixError.error и bitrixError.error_description.
429 RATE_LIMITED Превышен лимит 30 запросов в минуту на портал — общий для всех его API-ключей. Точное значение — в заголовке x-ratelimit-limit (потолок делится на реплики). У отказа всего пакетного запроса срок приходит заголовком Retry-After. Сформированная платформой подошибка RATE_LIMITED внутри ответа 200 передаёт срок полем retryAfter, без отдельного заголовка; прямой отказ Битрикс24 внутри общего пакета может прийти без срока.
429 QUEUE_OVERFLOW На портале накопилось слишком много одновременных вызовов Битрикс24 (по умолчанию 100 и больше в ожидании). Ответ возвращается мгновенно с HTTP-заголовком Retry-After: N (секунды) — клиент должен дождаться его и повторить с экспоненциальным backoff + jitter. Тело: error.code = QUEUE_OVERFLOW, error.retryAfter дублирует заголовок.
429 QUEUE_TIMEOUT Запрос ожидал в очереди портала более 80 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить (Retry-After). Ответ содержит userMessage и hint.
502 BITRIX_UNAVAILABLE Битрикс24 ответил с ошибкой 5xx, или связь с порталом оборвалась до ответа. В error.message — машинный код причины, например ECONNRESET, если он известен. В error.hint — правило повтора. Платформа не повторяет пакет сама. Перед повтором вызовов на запись перечитайте сущности: изменение могло уже примениться.
503 BITRIX_TIMEOUT Битрикс24 принял запрос, но не ответил за 60 секунд — исход неизвестен. Для вызовов на запись внутри пакета: сначала перечитайте сущность, изменение могло примениться.
500 INTERNAL_ERROR Внутренняя ошибка прокси.

Полный список общих ошибок API — Коды ошибок.

Отказы OPERATION_TIME_LIMIT и TIMEOUT_QUARANTINE приходят по отдельному вызову внутри успешного 200 — они описаны в разделе Частичные ошибки.

Известные особенности

search и list с limit > 50 обходят нативный пакетный вызов Битрикс24. Эти вызовы выполняются как отдельные последовательные запросы со страничной выборкой до 5000 записей — каждый потребляет свою квоту rate-limit Битрикс24 независимо. Остальные вызовы — list с limit ≤ 50, get, create, update, delete, fields — объединяются в один пакетный вызов на стороне Битрикс24 и стоят одну единицу rate-limit суммарно.

list у сущностей mail-mailboxes и humanresources-nodes обходит нативный пакетный вызов при любом limit. Эти сущности обслуживаются семейством методов REST 3.0, а нативный пакетный вызов Битрикс24 умеет отправлять только методы прежнего поколения — раньше такой подвызов возвращал ERROR_METHOD_NOT_FOUND даже при limit в пределах 50. Теперь он выполняется отдельным запросом, как search, и стоит своей квоты rate-limit. Соседние вызовы других сущностей по-прежнему уезжают одним пакетом. Исключение действует только на list: get у этих сущностей в пакетном вызове по-прежнему не отвечает данными — читайте запись её собственным маршрутом. Отказ такого подвызова приходит под кодом AUTO_PAGINATION_FAILED в глобальном POST /v1/batch и под CALL_FAILED в POST /v1/{entity}/batch.

Количество записей у этих двух сущностей приходит всегда. withTotal: false на их list не отключает подсчёт: платформа продолжает возвращать total и hasMore. Параметр остаётся допустимым, но нагрузку на портал не снимает.

Стоимость list в единицах rate-limit Битрикс24. Каждые 50 записей = 1 единица. При limit > 50 авто-пагинатор делает несколько вызовов:

limit Единиц Битрикс24
1–50 1 (нативный batch)
51–2 550 2
2 551–5 000 3

У mail-mailboxes и humanresources-nodes строки «1–50» не бывает: их list всегда идёт отдельными запросами по 50 записей, то есть 1 единица на каждые 50 записей начиная с первой. Один вызов в массиве calls — это одна операция для платформы, но несколько запросов к порталу: это разные единицы измерения, не путайте их при планировании квоты. И считайте с запасом: если портал отвечает временной ошибкой, платформа повторяет запрос, а при неудаче повторяет весь обход целиком — вместе с уже успешными страницами. На неудачном обходе фактический расход доходит примерно до восьмикратного от расчётного.

Если действие в одном вызове провалилось, остальные продолжают выполняться. Ошибки попадают в data.errors под тем же id, успешные результаты — в data.results. Поле success остаётся true, проверять нужно data.summary.failed или присутствие нужного id в data.results.

users.get возвращает массив, а не объект. Это особенность Entity API: ответ get для пользователей — [ { ID, NAME, ... } ]. Первый элемент — искомая запись.

Потеря страницы выборки при сбое подзапроса. Если во время авто-пагинации list / search-вызова один из подзапросов страницы упал, результат обрезается до непрерывного префикса, а в data.meta[<id>].pageErrorSample приходит { code, message } первого сбоя. Поле hasMore при этом остаётся true — оставшиеся записи можно дозапросить.

В code приходит либо код ошибки Битрикс24, либо код самого Вайбкод. Кодов Вайбкод сегодня три, и все означают одно: обход прервал не Битрикс24, а сам Вайбкод, и вернул непрерывное начало выборки. KEYSET_DISCONTINUITY — обнаружен разрыв в последовательности страниц, продолжать значило бы отдать дубли. PAGE2_COUNT_FAILED — не удался подсчёт записей: тайм-аут, лимит запросов или ошибка портала. LAZY_COUNT_NO_PROGRESS — метод вернул те же записи вместо следующих. Реакция во всех трёх случаях та же — дозапросить остаток.

У двух последних кодов есть следствие для меты: meta.<id>.total и data.totals.<id> в таком ответе отсутствуют — количество не сосчитано, и число отданных строк его не заменяет. Границей остаётся hasMore.

calendar-events в пакетном вызове. Обязательные type и ownerId передаются в params вызова. Фильтр для этой сущности не поддерживается — оставшиеся поля в params.filter возвращают UNSUPPORTED_FILTER, отсутствие type или ownerId — MISSING_REQUIRED_PARAMS.

Выделенные сущности недоступны в пакетном вызове. Чаты, сообщения, лента, база знаний, звонки и рабочий день обслуживаются выделенными маршрутами — вызов с entity: "chats", "messages", "posts", "note", "calls" или "workday" возвращает ошибку с указателем на нужный маршрут. Пакетный вызов поддерживает только сущности из справочника. Для чтения сообщений многих диалогов одним запросом используйте POST /v1/chats/messages/bulk — до 50 диалогов за вызов.

Обработчик действия или робота на субдомене Black Hole регистрируется одиночным запросом. Вызов create или update для bizproc-activities и bizproc-robots, где handler ведёт на такой субдомен, пакетный вызов отклоняет: BIZPROC_CALLBACK_BATCH_UNSUPPORTED приходит в data.errors под id этого вызова. Обработчик на своём домене проходит пакетным вызовом. Форма отказа на POST /v1/{entity}/batch, поведение на аккаунте без надёжной доставки и что даёт одиночная регистрация — Доставка вызовов действий и роботов.

Пакетный вызов не принимает файл в поле, объявленном простым значением. Так объявлена фотография сотрудника personalPhoto: пара «имя файла и содержимое в base64» в пакете отклоняется, INVALID_PARAMS приходит в data.errors под id этого вызова, а на POST /v1/{entity}/batch весь запрос отвечает 400 BATCH_ITEM_VALIDATION с номером элемента. Причина в размере: подзапрос пакета едет строкой запроса, и пакетные маршруты остались на общем потолке тела, тогда как одиночные подняты до 40 МиБ. За пределом длины подзапроса значение обрезалось бы, а обрезанная запись всё равно отвечает успехом. Отправляйте файл одиночным вызовом — POST /v1/users или PATCH /v1/users/:id. Какие формы поля принимаются и какие отклоняются — раздел «Фотография профиля» на странице Обновить сотрудника.

Проверка формы охватывает поля, объявленные в схеме сущности, и поля, о типе которых сообщает сам Битрикс24 в своём списке полей, — в том числе пользовательские UF_* (границы — в разделе INVALID_PARAMS). Поле, которое портал объявляет многозначным, — например FILES у записей таймлайна, — она по-прежнему не судит: содержимое уедет в подзапросе без предупреждения, и тот же предел длины действует и на него. Такие поля тоже отправляйте одиночным вызовом.

Пакетные операции по одной сущности. Специализированный эндпоинт POST /v1/{entity}/batch работает с одной сущностью. Набор действий у каждой сущности свой: полный список — в operations.batch ответа GET /v1/guide (data.batch в GET /v1/{entity}/fields перечисляет только действия ЗАПИСИ). Действие, которого у сущности нет, отвечает 400 ACTION_NOT_SUPPORTED — в том числе чтение, выключенное у сущности через disabledOperations. Для delete передаётся массив ids, для create и update — items (поля в каждом элементе передаются плоско; объект fields при отсутствии такого поля в схеме отклоняет пакет целиком с 400 BATCH_ITEM_VALIDATION и индексом элемента, причиной NESTED_FIELDS_ENVELOPE), для чтений list / get / fields — массив calls. Записи идут внутренними пакетами по 50 штук, до 500 за запрос, ответ — массив результатов с пометкой success для каждого элемента. Элемент create / update, у которого Битрикс24 не применил стадию, воронку или явно запрошенный ручной режим суммы, приходит с success: false, кодом STAGE_NOT_APPLIED либо AMOUNT_NOT_APPLIED в error, пояснением в message и details.unappliedFields / details.currentValues — и сохраняет id: запись уже создана или изменена, повторять её не нужно. Это та же проверка, что описана выше для общего вызова, и лишних обращений к Битрикс24 она не делает. Для смарт-процессов путь несёт сегмент типа: POST /v1/items/{entityTypeId}/batch. В list-вызове поле filter проходит через транслятор фильтров — работают псевдонимы полей и операторы $gt, $contains, $in. Некорректный фильтр отклоняет ТОЛЬКО свой подвызов: ответ 200, код отказа в data[i].error.code, остальные подвызовы выполняются. Проверяйте наличие error у каждого элемента data — как и в глобальном POST /v1/batch.

Список содержимого папки в пакетном запросе. В POST /v1/files/batch с action: "list" передавайте folderId в calls[].params. Для POST /v1/folders/batch используйте parentId. Допускается и вложенное написание в calls[].params.filter, прямой параметр имеет приоритет. Идентификатор корневой папки — rootFolderId из списка хранилищ. Если не удалось получить непустой скалярный параметр, соответствующий элемент data содержит error.code: "MISSING_REQUIRED_PARAMS", остальные вызовы выполняются. Ответ запроса остаётся 200. При заданном прямом скалярном параметре массив, объект или null в одноимённом ключе filter приводит к ошибке подвызова INVALID_FILTER_OPERATOR. То же ограничение действует для list файлов и папок в глобальном POST /v1/batch.

Смотрите также