Лимиты и оптимизация

Вайбкод сам объединяет вызовы и пагинирует выборки на стороне сервера. Эта статья описывает встроенные механизмы и подсказывает, какой эндпоинт выбирать под задачу.

Базовый 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, ошибка одного не отменяет остальные.

Подходит для дашбордов и страниц-сводок, где одной загрузкой нужны данные из разных мест:

JSON
{
  "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 элементов:

Terminal
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 и updateitems, для list / get / fieldscalls.

Массовое сканирование с дозагрузкой связанных данных

Когда нужно прочитать тысячи записей одной сущности и подтянуть к ним связанные данные из других сущностей, поток выглядит так:

  1. Выгрузить корневой список одним вызовом — Вайбкод сам пагинирует на сервере:

    GET /v1/deals?limit=5000&select=id,title,companyId,assignedById
  2. Собрать id связанных сущностей и догрузить пакетами по 50 через POST /v1/batch:

    JSON
    {
      "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 дней и обрабатывает их параллельно:

JSON
{
  "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 возвращает результат одним вызовом, без выгрузки самих записей:

JSON
{
  "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.

javascript
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 для каждого диалога:

JSON
{
  "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:

Terminal
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.jsonCache-Control: public, max-age=300. Спецификация одинакова для всех клиентов, поэтому её может хранить любой кэш.
  • /v1/guideCache-Control: private, max-age=300. Состав ответа зависит от скоупов ключа, поэтому общий кэш хранить его не должен.
  • ETag — отпечаток содержимого, меняется только при изменении документа или набора скоупов ключа.

Сохраните ETag из первого ответа и передавайте его в заголовке If-None-Match при повторных запросах. Если содержимое не изменилось, эндпоинт отвечает 304 Not Modified с пустым телом вместо повторной передачи всего документа:

Terminal
# Первый вызов — полное тело и 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}/searchlimit до 5000 записей, при диапазоне дат > 14 дней — окна по 7 дней
POST /v1/chats/messages/bulk — диалогов до 50 в одном запросе
Очередь портала 2 одновременных запроса, ожидание до 30 секунд
Кэш ответов /v1/users / /v1/statuses 60 секунд / 5 минут, обход — заголовок Cache-Control: no-cache

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