Лимиты и оптимизация
Вайбкод сам объединяет вызовы и пагинирует выборки на стороне сервера. Эта статья описывает встроенные механизмы и подсказывает, какой эндпоинт выбирать под задачу.
Базовый URL: https://vibecode.bitrix24.tech/v1 | Авторизация: X-Api-Key
Авто-пагинация | Пакетные вызовы | Поиск по датам | Агрегация | Очередь портала | Кэширование | Сводные лимиты
Авто-пагинация в `list`
Параметр limit в GET /v1/{entity} принимает значения до 5000. Если limit > 50, Вайбкод сам разбивает выборку на внутренние страницы по 50 записей и собирает их в один ответ:
GET /v1/deals?limit=500&filter[stageId]=NEW
Возвращается до 500 записей плюс мета-поля meta.total и meta.hasMore. Если под фильтр попадает больше 5000 записей, ответ обрезается, а в meta.truncated приходит true — для остатка нужно либо сузить фильтр, либо использовать POST /v1/{entity}/search.
Пакетные вызовы по нескольким сущностям
POST /v1/batch объединяет до 50 операций над разными сущностями в один HTTP-запрос. Каждый вызов идентифицируется собственным id, ошибка одного не отменяет остальные.
Подходит для дашбордов и страниц-сводок, где одной загрузкой нужны данные из разных мест:
{
"calls": [
{ "id": "deals", "entity": "deals", "action": "list", "params": { "filter": { "stageId": "NEW" }, "limit": 50 } },
{ "id": "tasks", "entity": "tasks", "action": "list", "params": { "filter": { "responsibleId": 1 }, "limit": 20 } },
{ "id": "user", "entity": "users", "action": "get", "entityId": 1 }
]
}
Полная спецификация — Пакетные вызовы.
Пакетные операции по одной сущности
POST /v1/{entity}/batch массово создаёт, обновляет или удаляет до 500 записей одной сущности. Внутри Вайбкод разбивает запрос на пакеты по 50 элементов:
curl -X POST https://vibecode.bitrix24.tech/v1/deals/batch \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "update",
"items": [
{ "id": 575, "stageId": "WON" },
{ "id": 741, "stageId": "WON" }
]
}'
Действия: create, update, delete, list, get, fields. Для delete передаётся массив ids, для create и update — items, для list / get / fields — calls.
Массовое сканирование с дозагрузкой связанных данных
Когда нужно прочитать тысячи записей одной сущности и подтянуть к ним связанные данные из других сущностей, поток выглядит так:
Выгрузить корневой список одним вызовом — Вайбкод сам пагинирует на сервере:
GET /v1/deals?limit=5000&select=id,title,companyId,assignedByIdСобрать
idсвязанных сущностей и догрузить пакетами по 50 черезPOST /v1/batch:{ "calls": [ { "id": "company-15", "entity": "companies", "action": "get", "entityId": 15 }, { "id": "company-22", "entity": "companies", "action": "get", "entityId": 22 }, { "id": "user-1", "entity": "users", "action": "get", "entityId": 1 } ] }Один HTTP-запрос — до 50 связанных записей. Цикл повторяется для следующего пакета
id.
В таком сценарии корневая выгрузка занимает один сетевой запрос: Вайбкод сам поднимает страницы по 50. Ассоциации догружаются в темпе один HTTP-запрос на 50 элементов вместо запроса на каждый элемент.
Поиск с разбиением по датам
POST /v1/{entity}/search рассчитан на крупные выборки. Если в фильтре есть условие по дате с диапазоном больше 14 дней, Вайбкод автоматически делит запрос на окна по 7 дней и обрабатывает их параллельно:
{
"filter": { "$gte": { "createdAt": "2026-01-01" }, "$lte": { "createdAt": "2026-04-30" } },
"select": ["id", "title", "stageId"],
"limit": 5000
}
В ответе появляются мета-поля:
| Поле | Описание |
|---|---|
meta.windowCount |
Количество окон, на которые был разбит запрос. |
meta.windowErrors |
Количество окон, по которым Битрикс24 вернул ошибку. Остальные окна возвращают свои данные. |
meta.truncated |
true, если под фильтр попало больше 5000 записей и часть осталась за пределами выборки. |
Разбиение отключается флагом "autoWindow": false в теле запроса — применяйте его при таймаутах сети или нестабильной выдаче. Полный список параметров search — в документации каждой сущности.
Агрегация вместо выборки записей
Когда нужны только счётчики, суммы, минимумы, максимумы или средние — POST /v1/{entity}/aggregate возвращает результат одним вызовом, без выгрузки самих записей:
{
"aggregate": [
{ "field": "amount", "function": "sum" },
{ "field": "amount", "function": "avg" }
],
"filter": { "stageId": "WON" },
"groupBy": "assignedById"
}
Ответ содержит data.count, data.aggregates и массив data.groups с разбивкой по полю группировки. Массив data.groups присутствует только при заданном groupBy — без него ответ ограничен одним объектом сводных значений. Для функции count результат возвращается одним вызовом независимо от размера выборки. Функции sum / avg / min / max подгружают записи постранично до 5000 штук — при большем объёме приходит meta.truncated: true.
Очередь портала
У каждого портала Битрикс24 своя очередь к API Вайбкод: одновременно выполняются до двух запросов, остальные ждут места. Если запрос провисел в очереди дольше 30 секунд, возвращается 429 QUEUE_TIMEOUT с подсказкой userMessage и hint.
Что снижает нагрузку на очередь:
- Объединять разнородные обращения через
POST /v1/batch— один HTTP-запрос вместо нескольких. - Для массового CRUD по одной сущности —
POST /v1/{entity}/batch, до 500 записей за запрос. - Для широких выборок —
GET /v1/{entity}?limit=...с пагинацией на стороне сервера илиPOST /v1/{entity}/searchс разбивкой по датам. - Когда нужны числа, а не записи —
POST /v1/{entity}/aggregate.
Повтор при перегрузке очереди. Под нагрузкой очередь возвращает два разных кода, и оба означают «повтори позже»:
429 QUEUE_OVERFLOW— очередь переполнена, запрос отклонён сразу, за миллисекунды. В заголовкеRetry-After— рекомендованная пауза в секундах.429 QUEUE_TIMEOUT— запрос ждал места дольше 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить. В телеerror.retryAfter— рекомендованная пауза.
Виджеты аналитики, которые шлют пачку /search подряд, должны делать повтор с экспоненциальной задержкой и случайным разбросом по времени (backoff с джиттером), учитывая Retry-After, а не повторять мгновенно в цикле — это усугубляет перегрузку. Снизьте параллелизм: выполняйте запросы последовательно или объедините их в POST /v1/batch.
async function callWithBackoff(url, options, maxRetries = 4) {
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, options)
if (res.status !== 429) return res
if (attempt >= maxRetries) return res
// Оба кода (QUEUE_OVERFLOW, QUEUE_TIMEOUT) отдают паузу в заголовке Retry-After;
// error.retryAfter в теле дублирует то же значение
const headerWait = Number(res.headers.get('Retry-After'))
const bodyWait = Number((await res.clone().json())?.error?.retryAfter) || 0
const baseSec = headerWait || bodyWait || Math.min(2 ** attempt, 30)
const jitterMs = Math.floor(Math.random() * 1000)
await new Promise(r => setTimeout(r, baseSec * 1000 + jitterMs))
}
}
Загрузка сообщений из нескольких диалогов
POST /v1/chats/messages/bulk возвращает сообщения не более чем из 50 диалогов в одном ответе и принимает курсоры lastId / firstId и limit для каждого диалога:
{
"dialogs": [
{ "dialogId": "chat253", "limit": 20 },
{ "dialogId": "chat741", "lastId": 9357, "limit": 50 }
]
}
Скоуп: im. Формат ответа — { results, errors, summary }, аналогично /v1/batch.
Кэширование
Часть ответов отдаётся из кэша, чтобы повторные чтения не нагружали Битрикс24 и очередь портала. Кэш прозрачен — тело ответа совпадает с некэшированным, а заголовок X-Cache показывает, откуда пришёл ответ.
Кэш ответов `/v1/users` и `/v1/statuses`
Ответы GET /v1/users и GET /v1/statuses кэшируются на стороне сервера: пользователи — 60 секунд, справочники CRM — 5 минут. Это ускоряет дашборды, которые запрашивают эти эндпоинты при каждой загрузке.
Кэш привязан к личному ключу vibe_api_.... Для ключа авторизации OAuth-приложения vibe_app_... кэш не используется — у разных пользователей разный доступ к данным портала.
Запись через API — POST /v1/users, PATCH /v1/users/:id и аналогичные — сбрасывает кэш сразу. Правка напрямую в интерфейсе Битрикс24 кэшу не видна, поэтому такие изменения могут отображаться с задержкой до конца времени жизни кэша: до 60 секунд для пользователей и до 5 минут для справочников.
Чтобы получить заведомо свежие данные в обход кэша, добавьте заголовок Cache-Control: no-cache:
curl -H "X-Api-Key: YOUR_API_KEY" \
-H "Cache-Control: no-cache" \
https://vibecode.bitrix24.tech/v1/users
Заголовок X-Cache в ответе показывает, как был обработан запрос:
| Значение | Что означает |
|---|---|
HIT |
Ответ отдан из кэша |
MISS |
Ответ получен из Битрикс24 и сохранён в кэш |
COALESCED |
Запрос присоединился к уже выполняющемуся обращению за теми же данными |
BYPASS |
Кэш не использовался — ключ авторизации OAuth-приложения или заголовок Cache-Control: no-cache. Причина указывается в заголовке X-Cache-Bypass-Reason |
HTTP-кэш служебных эндпоинтов
GET /v1/openapi.json и GET /v1/guide возвращают объёмные документы, которые клиенту незачем перекачивать при каждом запуске. Оба ответа несут стандартные заголовки HTTP-кэша:
/v1/openapi.json—Cache-Control: public, max-age=300. Спецификация одинакова для всех клиентов, поэтому её может хранить любой кэш./v1/guide—Cache-Control: private, max-age=300. Состав ответа зависит от скоупов ключа, поэтому общий кэш хранить его не должен.ETag— отпечаток содержимого, меняется только при изменении документа или набора скоупов ключа.
Сохраните ETag из первого ответа и передавайте его в заголовке If-None-Match при повторных запросах. Если содержимое не изменилось, эндпоинт отвечает 304 Not Modified с пустым телом вместо повторной передачи всего документа:
# Первый вызов — полное тело и ETag (openapi.json не требует авторизации)
curl -i https://vibecode.bitrix24.tech/v1/openapi.json
# ... ETag: "a1b2c3d4e5f6a7b8"
# Повторный вызов — 304 Not Modified, тело не передаётся
curl -i -H 'If-None-Match: "a1b2c3d4e5f6a7b8"' \
https://vibecode.bitrix24.tech/v1/openapi.json
Заголовок max-age=300 также разрешает клиенту и промежуточному кэшу повторно использовать ответ в течение 5 минут, не обращаясь к серверу.
Сводные лимиты
| Сценарий | Ограничение |
|---|---|
GET /v1/{entity} — limit |
до 5000 записей, при limit > 50 — авто-пагинация на стороне Вайбкод |
POST /v1/batch — число вызовов |
до 50 в одном запросе |
POST /v1/{entity}/batch — массовый CRUD |
до 500 записей в одном запросе |
POST /v1/{entity}/batch — чтение list / get / fields |
до 50 вызовов в массиве calls |
POST /v1/{entity}/search — limit |
до 5000 записей, при диапазоне дат > 14 дней — окна по 7 дней |
POST /v1/chats/messages/bulk — диалогов |
до 50 в одном запросе |
| Очередь портала | 2 одновременных запроса, ожидание до 30 секунд |
Кэш ответов /v1/users / /v1/statuses |
60 секунд / 5 минут, обход — заголовок Cache-Control: no-cache |