[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"docs-batch":3,"docs-tabs-batch":6},{"content":4,"lastmod":5},"\n# Пакетные вызовы\n\nОдин HTTP-запрос объединяет до 50 операций над разными сущностями. Каждый вызов идентифицируется собственным `id` и обрабатывается независимо: ошибка одного вызова не отменяет остальные.\n\n`POST \u002Fv1\u002Fbatch`\n\n**Скоуп:** проверяется индивидуально по сущности (`crm`, `task`, `im`, `disk` и др.) | **Базовый URL:** `https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1` | **Авторизация:** `X-Api-Key` (APP-ключ)\n\n## Поля запроса (body)\n\n| Поле | Тип | Обяз. | Описание |\n|------|-----|:---:|---------|\n| `calls` | array | ★ | Массив вызовов (от 1 до 50). Каждый элемент — объект, формат описан в таблице ниже. |\n\n## Поля одного вызова\n\n| Поле | Тип | Обяз. | Описание |\n|------|-----|:---:|---------|\n| `id` | string | нет | Идентификатор вызова в ответе. Если не передан — присваивается порядковый индекс (`\"0\"`, `\"1\"`, ...). Длина до 64 символов. |\n| `entity` | string | ★ | Имя сущности во множественном числе: `deals`, `contacts`, `companies`, `tasks`, `users`, `files`, `folders` и другие. Полный список сущностей, доступных вашему ключу, возвращает `GET \u002Fv1\u002Fme` — см. [Ключи и авторизация](\u002Fdocs\u002Fkeys-auth). |\n| `action` | string | ★ | Операция: `list`, `get`, `create`, `update`, `delete`, `fields`, `search`. |\n| `entityId` | number \u002F string | для `get` \u002F `update` \u002F `delete` | Идентификатор записи. |\n| `params` | object | нет | Параметры операции в едином entity-формате (имена полей в `camelCase`, фильтры в [синтаксисе фильтрации](\u002Fdocs\u002Ffiltering)). |\n\nПараметры внутри `params` совпадают с параметрами одиночного эндпоинта Entity API:\n\n- `list` и `search` — `filter`, `select`, `order`, `limit`\n- `get` — поле `include`, если сущность его поддерживает\n- `create` и `update` — поля сущности (имена в `camelCase`)\n- `delete` и `fields` — параметры не нужны\n- смарт-процессы (`entity: \"items\"`) — внутри `params` обязательно `entityTypeId`\n\nИдентификатор записи для `get` \u002F `update` \u002F `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`.\n\n## Примеры\n\n### curl — личный ключ\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbatch \\\n  -H \"X-Api-Key: YOUR_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"calls\": [\n      {\n        \"id\": \"deals\",\n        \"entity\": \"deals\",\n        \"action\": \"list\",\n        \"params\": {\n          \"filter\": { \"stageId\": \"NEW\" },\n          \"select\": [\"id\", \"title\", \"amount\"],\n          \"limit\": 50\n        }\n      },\n      {\n        \"id\": \"contacts\",\n        \"entity\": \"contacts\",\n        \"action\": \"list\",\n        \"params\": {\n          \"select\": [\"id\", \"name\", \"lastName\"],\n          \"limit\": 20\n        }\n      },\n      {\n        \"id\": \"user1\",\n        \"entity\": \"users\",\n        \"action\": \"get\",\n        \"entityId\": 1\n      }\n    ]\n  }'\n```\n\n### curl — OAuth-приложение\n\n```bash\ncurl -X POST https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbatch \\\n  -H \"X-Api-Key: YOUR_APP_KEY\" \\\n  -H \"Authorization: Bearer USER_SESSION_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"calls\": [\n      {\n        \"id\": \"deals\",\n        \"entity\": \"deals\",\n        \"action\": \"list\",\n        \"params\": {\n          \"filter\": { \"stageId\": \"NEW\" },\n          \"select\": [\"id\", \"title\", \"amount\"],\n          \"limit\": 50\n        }\n      },\n      {\n        \"id\": \"contacts\",\n        \"entity\": \"contacts\",\n        \"action\": \"list\",\n        \"params\": {\n          \"select\": [\"id\", \"name\", \"lastName\"],\n          \"limit\": 20\n        }\n      },\n      {\n        \"id\": \"user1\",\n        \"entity\": \"users\",\n        \"action\": \"get\",\n        \"entityId\": 1\n      }\n    ]\n  }'\n```\n\n### JavaScript — личный ключ\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbatch', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_API_KEY',\n    'Content-Type': 'application\u002Fjson'\n  },\n  body: JSON.stringify({\n    calls: [\n      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50 } },\n      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20 } },\n      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }\n    ]\n  })\n})\n\nconst { data } = await res.json()\nconsole.log('Сделки:', data.results.deals)\nconsole.log('Контакты:', data.results.contacts)\nconsole.log('Сводка:', data.summary)\n```\n\n### JavaScript — OAuth-приложение\n\n```javascript\nconst res = await fetch('https:\u002F\u002Fvibecode.bitrix24.tech\u002Fv1\u002Fbatch', {\n  method: 'POST',\n  headers: {\n    'X-Api-Key': 'YOUR_APP_KEY',\n    'Authorization': 'Bearer USER_SESSION_TOKEN',\n    'Content-Type': 'application\u002Fjson'\n  },\n  body: JSON.stringify({\n    calls: [\n      { id: 'deals', entity: 'deals', action: 'list', params: { filter: { stageId: 'NEW' }, select: ['id', 'title', 'amount'], limit: 50 } },\n      { id: 'contacts', entity: 'contacts', action: 'list', params: { select: ['id', 'name', 'lastName'], limit: 20 } },\n      { id: 'user1', entity: 'users', action: 'get', entityId: 1 }\n    ]\n  })\n})\n\nconst { data } = await res.json()\nconsole.log('Сделки:', data.results.deals)\n```\n\n## Поля ответа\n\n| Поле | Тип | Описание |\n|------|-----|---------|\n| `success` | boolean | `true`, если запрос принят. Частичные ошибки внутри `data.errors` не переводят его в `false`. |\n| `data.results` | object | Результаты по `id` каждого вызова. Значение — то, что вернул бы соответствующий эндпоинт Entity API: массив записей для `list` \u002F `search`, объект для `get` \u002F `create`, схема полей для `fields`. |\n| `data.totals` | object | Общее количество записей под фильтр для `list` \u002F `search`-вызовов. Ключи — `id` соответствующих вызовов. |\n| `data.errors` | object | Ошибки по `id` неудачных вызовов. Каждое значение — `{ \"code\": \"...\", \"message\": \"...\" }`. |\n| `data.summary.total` | number | Общее количество вызовов в запросе. |\n| `data.summary.succeeded` | number | Количество успешных вызовов. |\n| `data.summary.failed` | number | Количество вызовов с ошибкой. |\n| `data.meta` | object | Дополнительные сведения по `id` вызовов с `action: \"list\"` или `action: \"search\"`: `total`, `returned`, `hasMore`, `truncated`. |\n\n## Пример ответа\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"results\": {\n      \"deals\": [\n        { \"id\": 575, \"title\": \"Тест валюты\", \"amount\": 0 },\n        { \"id\": 741, \"title\": \"Поставка оборудования\", \"amount\": 250000 }\n      ],\n      \"contacts\": [\n        { \"id\": 1, \"name\": \"Иван\", \"lastName\": \"Петров\" }\n      ],\n      \"user1\": [\n        { \"ID\": \"1\", \"NAME\": \"Мария\", \"ACTIVE\": true }\n      ]\n    },\n    \"totals\": {\n      \"deals\": 1798,\n      \"contacts\": 305\n    },\n    \"errors\": {},\n    \"summary\": {\n      \"total\": 3,\n      \"succeeded\": 3,\n      \"failed\": 0\n    },\n    \"meta\": {\n      \"deals\": { \"total\": 1798, \"returned\": 2, \"hasMore\": true, \"truncated\": false },\n      \"contacts\": { \"total\": 305, \"returned\": 1, \"hasMore\": true, \"truncated\": false }\n    }\n  }\n}\n```\n\n## Частичные ошибки\n\nЕсли часть вызовов не прошла проверку или вернула ошибку на стороне Битрикс24, успешные результаты остаются в `data.results`, неудачные — в `data.errors` под тем же `id`:\n\n```json\n{\n  \"success\": true,\n  \"data\": {\n    \"results\": {\n      \"deals\": [\n        { \"id\": 575, \"title\": \"Тест валюты\" }\n      ]\n    },\n    \"totals\": {\n      \"deals\": 1798\n    },\n    \"errors\": {\n      \"unknown\": {\n        \"code\": \"UNKNOWN_ENTITY\",\n        \"message\": \"Unknown entity \\\"foobar\\\". Check GET \u002Fv1\u002Fguide for available entities.\"\n      }\n    },\n    \"summary\": {\n      \"total\": 2,\n      \"succeeded\": 1,\n      \"failed\": 1\n    },\n    \"meta\": {\n      \"deals\": { \"total\": 1798, \"returned\": 1, \"hasMore\": true, \"truncated\": false }\n    }\n  }\n}\n```\n\n## Пример ответа при ошибке\n\nЕсли все вызовы не прошли валидацию, возвращается `400 INVALID_REQUEST` с разбивкой по `id` в `data.errors`:\n\n```json\n{\n  \"success\": false,\n  \"error\": {\n    \"code\": \"INVALID_REQUEST\",\n    \"message\": \"All calls in the batch failed validation\"\n  },\n  \"data\": {\n    \"errors\": {\n      \"x\": {\n        \"code\": \"MISSING_ENTITY_ID\",\n        \"message\": \"Action \\\"get\\\" requires entityId.\"\n      }\n    }\n  }\n}\n```\n\n## Ошибки\n\n| HTTP | Код | Описание |\n|------|-----|----------|\n| 400 | `INVALID_REQUEST` | Тело запроса не соответствует схеме или все вызовы провалили валидацию. |\n| 400 | `UNKNOWN_ENTITY` | В одном из вызовов передано неизвестное имя сущности. |\n| 400 | `ACTION_NOT_SUPPORTED` | Сущность не поддерживает указанное действие (например, `delete` для справочной сущности без удаления). |\n| 400 | `MISSING_ENTITY_ID` | Действия `get`, `update`, `delete` требуют `entityId`. |\n| 400 | `MISSING_DYNAMIC_PARAM` | Для смарт-процессов (`entity: \"items\"`) не передан `entityTypeId` внутри `params`. |\n| 400 | `INVALID_DYNAMIC_PARAM` | `entityTypeId` для смарт-процессов задан некорректно (не положительное целое). |\n| 400 | `USE_DEDICATED_ENTITY` | Для переданного `entityTypeId` существует выделенная сущность — использовать её, а не `items`. |\n| 400 | `ENTITY_CUSTOM_ROUTES` | Сущность работает только через специализированные маршруты (например, `task-comments` — через `\u002Fv1\u002Ftasks\u002F:taskId\u002Fcomments`). |\n| 400 | `INVALID_CALL` | Объект вызова не содержит обязательных полей `entity` и `action`. |\n| 401 | `TOKEN_MISSING` | У ключа нет настроенных OAuth-токенов или для OAuth-приложения не передан `Authorization: Bearer ...`. |\n| 401 | `TOKEN_REFRESH_FAILED` | Не удалось обновить OAuth-токен портала. |\n| 403 | `MANAGEMENT_KEY_NO_ENTITY_ACCESS` | Запрос пришёл с management-ключа — пакетные вызовы доступны только APP-ключам. |\n| 403 | `SCOPE_NOT_ALLOWED` | Все вызовы запросили скоупы, которых нет у ключа. Если хотя бы один вызов проходит — этот код возвращается внутри `data.errors` для конкретных вызовов, а сам запрос успешен. |\n| 422 | `BITRIX_ERROR` | Битрикс24 отклонил вызов. Тело ответа содержит `bitrixError.error` и `bitrixError.error_description`. |\n| 429 | `QUEUE_OVERFLOW` | На портале накопилось слишком много одновременных вызовов Битрикс24 (по умолчанию более 100 в ожидании). Ответ возвращается мгновенно с HTTP-заголовком `Retry-After: N` (секунды) — клиент должен дождаться его и повторить с экспоненциальным backoff + jitter. Тело: `error.code = QUEUE_OVERFLOW`, `error.retryAfter` дублирует заголовок. |\n| 429 | `QUEUE_TIMEOUT` | Запрос ожидал в очереди портала более 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить (`Retry-After`). Ответ содержит `userMessage` и `hint`. |\n| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 ответил с ошибкой 5xx. |\n| 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за 15 секунд — исход неизвестен. Для write-вызовов внутри batch: сначала перечитайте сущность, изменение могло примениться. |\n| 500 | `INTERNAL_ERROR` | Внутренняя ошибка прокси. |\n\nПолный список общих ошибок API — [Коды ошибок](\u002Fdocs\u002Ferrors).\n\n## Известные особенности\n\n**`search` и `list` с `limit > 50` обходят нативный пакетный вызов Битрикс24.** Эти вызовы выполняются как отдельные последовательные запросы со страничной выборкой до 5000 записей — каждый потребляет свою квоту rate-limit Битрикс24 независимо. Остальные вызовы — `list` с `limit ≤ 50`, `get`, `create`, `update`, `delete`, `fields` — объединяются в один пакетный вызов на стороне Битрикс24 и стоят одну единицу rate-limit суммарно.\n\n**Стоимость `list` в единицах rate-limit Битрикс24.** Каждые 50 записей = 1 единица. При `limit > 50` авто-пагинатор делает несколько вызовов:\n\n| `limit` | Единиц Битрикс24 |\n|---------|-----------------|\n| 1–50 | 1 (нативный batch) |\n| 51–2 550 | 2 |\n| 2 551–5 000 | 3 |\n\n**Если действие в одном вызове провалилось, остальные продолжают выполняться.** Ошибки попадают в `data.errors` под тем же `id`, успешные результаты — в `data.results`. Поле `success` остаётся `true`, проверять нужно `data.summary.failed` или присутствие нужного `id` в `data.results`.\n\n**`users.get` возвращает массив, а не объект.** Это особенность Entity API: ответ `get` для пользователей — `[ { ID, NAME, ... } ]`. Первый элемент — искомая запись.\n\n**Пакетные изменения для одной сущности.** Если нужно создать, обновить или удалить много записей одной сущности (до 500 штук), используется специализированный эндпоинт `POST \u002Fv1\u002F{entity}\u002Fbatch` с телом `{ \"action\": \"create\" | \"update\" | \"delete\", \"items\" | \"ids\": [...] }`. Он выполняет операции внутренними пакетами по 50 записей и возвращает массив результатов с пометкой `success` для каждого элемента.\n\n## Смотрите также\n\n- [Лимиты и оптимизация](\u002Fdocs\u002Foptimization) — авто-пагинация, пакетные вызовы, агрегация\n- [Синтаксис фильтрации](\u002Fdocs\u002Ffiltering) — как описывать `params.filter`\n- [Entity API](\u002Fdocs\u002Fentity-api) — справочник сущностей и одиночных эндпоинтов\n- [Ключи и авторизация](\u002Fdocs\u002Fkeys-auth) — типы ключей, скоупы, самоописание через `GET \u002Fv1\u002Fme`\n- [Коды ошибок](\u002Fdocs\u002Ferrors) — общий справочник\n","2026-07-03",{}]