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

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

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

Базовый 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.hasMoremeta.total, если количество заказывалось — см. ниже). Если под фильтр попадает больше 5000 записей, в выборку попадают первые 5000, а meta.hasMore приходит true — для остатка нужно либо сузить фильтр, либо использовать POST /v1/{entity}/search.

Этот режим рассчитан на выборки в пределах 5000 записей. Коллекция в десятки тысяч записей читается курсором — Выгрузка большой коллекции.

Листание и количество записей

Это две разные задачи, и решаются они разными полями. Смешивать их — самая дорогая ошибка на списках.

Листание идёт по meta.hasMore. Признак выводится из полноты страницы: пришла полная — возможно, есть ещё, пришла неполная — коллекция кончилась. Коллекция ровно кратна limit — последний шаг вернёт пустой список, это штатный признак конца. Поле описывает состояние отдельного ответа, а не обещает неизменяемый снимок коллекции.

Если ответ метода содержит meta.nextAfterId, для больших обходов используйте сортировку строго по id по возрастанию, отключите точный подсчёт через withTotal=false и запросите через select только нужные поля вместе с id. Поле meta.nextAfterId несёт идентификатор последней отданной записи. Передайте его обратно как filter[>id], и следующая страница начнётся за ним. Такой обход не зависит от смещения и не дорожает к концу коллекции:

GET /v1/deals?order[id]=asc&limit=50&withTotal=false&select=id,title
GET /v1/deals?order[id]=asc&limit=50&withTotal=false&select=id,title&filter[>id]=<meta.nextAfterId предыдущего ответа>

Курсор доступен у сделок, лидов, контактов, компаний, предложений и элементов смарт-процессов. У остальных сущностей meta.nextAfterId в ответе нет: страницы там берутся через offset, а размер выборки сокращается фильтром. Готовый цикл обхода на JavaScript — Постраничный вывод.

На внутреннем уровне этот режим следует рекомендованной схеме Битрикс24: start=-1, order=ID ASC, фильтр ID больше последнего полученного идентификатора. Клиент не передаёт start в запросе к API Вайбкод. Вайбкод применяет его только к методам, для которых подтверждена совместная работа фильтра по id и start=-1. Для остальных методов сервис сохраняет корректность вызова и может не применить режим без подсчёта.

Такой обход предполагает, что записи не удаляются, а права доступа не меняются до его завершения. Если любое из условий нарушено, часть записей может быть пропущена. API Вайбкод не обещает полный обход как инвариант клиента.

Количество берётся из доступной операции агрегации. Подсчёт коллекции стоит Битрикс24 несоразмерно дорого — заметно дороже, чем отдать страницу. Если нужна точная цифра, сначала прочитайте operations.search.paginationStability.counting сущности в GET /v1/guide. Когда указание содержит путь агрегации, спросите число одним вызовом агрегации с функцией count. Когда указание есть, но пути нет, дешёвого точного подсчёта нет: читайте meta.total, только когда поле пришло, а обход ограничивайте по meta.hasMore. Если весь блок counting отсутствует вместе с общей операцией поиска, не угадывайте путь агрегации — перейдите по указателю на документацию сущности или домена из того же руководства и используйте только явно описанную операцию счёта. Не нужна цифра — отключите подсчёт параметром withTotal=false. У POST /v1/{entity}/search это одноимённое поле тела. В поддерживаемом режиме meta.total в ответе не придёт, а отдельный COUNT не выполняется. Важно: как приём оптимизации withTotal=false работает только при limit не больше 50 — там подсчёт действительно не заказывается. При limit больше 50 подсчёт нужен платформе, чтобы спланировать обход, поэтому параметр убирает число, а не нагрузку, и вдобавок отбрасывает точное количество, которое короткая первая страница отдала бы бесплатно.

Если withTotal не передан, значение берётся из настройки totalDefault на API-ключе, а при её отсутствии — из платформенного умолчания. Действующее сейчас значение показывает блок totalDefault в GET /v1/me.

Отключённый подсчёт не всегда означает отсутствие цифры: на вызове с offset = 0, где страница пришла короче запрошенного limit, точное количество известно из самой страницы и приходит бесплатно. Явный withTotal=false в запросе убирает и его — полная таблица присутствия поля в разделе Листание и количество записей.

Обратное тоже верно: присутствие meta.total не означает, что за него заплатили подсчётом. На многостраничном вызове (limit больше 50) платформа выполняет подсчёт, только когда без него не обойтись, — форма ответа при этом не меняется, meta.total приходит как приходил. Отдельного действия от вас это не требует.

Не эмулируйте счётчик обходом. Пролистать пять тысяч записей, чтобы узнать, что их 4863, — это сто вызовов вместо одного, и для учётной записи Битрикс24 это худшая из возможных нагрузок. Если операция агрегации доступна, один aggregate с count даёт ту же цифру за один вызов.

meta.total — информативное поле. Оно может отставать от текущего состояния коллекции до минуты, поэтому число отданных строк иногда оказывается больше него. Полнота выдачи от meta.total не зависит.

Выгрузка большой коллекции

Широкая выборка одним вызовом рассчитана на коллекции, которые целиком помещаются в 5000 записей. Когда под фильтр попадают десятки тысяч записей, задача меняет форму: такую коллекцию читают курсором, а не одним широким limit.

Курсор описан выше, в разделе Листание и количество записей: сортировка строго по id по возрастанию, withTotal=false, select с нужными полями и обязательным id, а meta.nextAfterId предыдущего ответа уходит обратно в filter[>id]. Каждый вызов читает одну короткую страницу, поэтому обход не дорожает к концу коллекции, а прерванный продолжается с последнего курсора, не начиная сначала. Готовый цикл на JavaScript — Постраничный вывод.

Признак того, что выборка не уложилась в отведённое ей время, — 429 с кодом OPERATION_TIME_LIMIT или RATE_LIMITED. Оба означают паузу для вызывающего ключа, и повтор того же широкого запроса приходит к тому же результату — переходите на курсор.

Отбор по пользовательскому полю

Отбор по значению пользовательского поля выполняет сам портал: условие передаётся в filter тем же именем, под которым поле стоит в схеме сущности — написание разобрано в разделе Фильтрация. Это первый способ, потому что читать приходится совпадения, а не всю коллекцию.

Если на большой коллекции такой запрос приходит в отказ по времени, возьмите поле в select и отберите нужные записи на своей стороне. Пользовательское поле передаётся в select наравне со стандартными, и курсор при этом работает.

GET /v1/companies?order[id]=asc&limit=50&withTotal=false&select=id,title,ufCrm_1698325419&filter[>id]=<meta.nextAfterId предыдущего ответа>

В ответе приходит значение поля по каждой записи, дальше отбор идёт без обращения к порталу. Этот путь читает коллекцию целиком, поэтому он запасной. Имена пользовательских полей портала перечисляет GET /v1/{entity}/fields.

Пакетные вызовы по нескольким сущностям

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": { "createdAt": { "$gte": "2026-01-01", "$lte": "2026-04-30" } },
  "select": ["id", "title", "stageId"],
  "limit": 5000
}

При частичном отказе окон, когда часть окон вернула данные и ответ приходит с HTTP 200, в meta появляются поля:

Поле Описание
meta.autoWindowed true, когда запрос был разбит на окна по датам.
meta.windowCount Количество окон, на которые был разбит запрос.
meta.windowErrors Количество окон, по которым Битрикс24 вернул ошибку. Остальные окна возвращают свои данные.
meta.windowErrorSample Объект { code, message } — код и текст первого сбойного окна, чтобы видеть причину потери данных.
meta.batchWaves Количество волн параллельной отправки окон. Приходит, когда сработала пакетная отправка окон.
meta.hasMore Есть ли записи за пределами limit. При выборке больше 5000 записей часть остаётся за границей — сузьте фильтр или диапазон дат.

Если упали все окна, этого мета-блока нет — возвращается реальный код ошибки Битрикс24, как для узкого диапазона: UNKNOWN_FILTER_FIELD, INVALID_PARAMS, BITRIX_ACCESS_DENIED, RATE_LIMITED, BITRIX_UNAVAILABLE или BITRIX_TIMEOUT (503). Отдельный код WINDOWED_SEARCH_FAILED больше не возвращается.

Разбиение отключается флагом "autoWindow": false в теле запроса — применяйте его при таймаутах сети или нестабильной выдаче. Полный список параметров search — в документации каждой сущности.

Неполная выдача

Выдача бывает неполной и тогда, когда ни одно окно не упало. Ответ в этом случае несёт массив meta.warnings с записью { "code": "WINDOW_TRUNCATED", "field": "...", "message": "..." }. Причин две, и называет сработавшую текст message: либо одно окно держало больше записей, чем возвращает одно чтение окна, либо чтения окон в сумме упёрлись в предельные 5000 записей, и оставшиеся окна не отправлялись. Код у обеих причин один — ветвиться по нему можно, не разбирая текст. Предупреждение приходит на сущностях, чей список Битрикс24 отдаёт постранично.

Поле field называет поле диапазона исходным именем Битрикс24, а не тем, которое вы отправили: у сущностей с собственными именами полей это разные строки. Сопоставление имён — в справочнике полей сущности, например GET /v1/deals/fields. Сравнивать field с ключами своего фильтра напрямую нельзя.

Ниже — блок meta поиска по сделкам за два года. Массив data в таком ответе заполнен и содержит набранные записи:

JSON
{
  "total": 5000,
  "hasMore": false,
  "autoWindowed": true,
  "windowCount": 105,
  "batchWaves": 2,
  "durationMs": 41230,
  "warnings": [
    {
      "code": "WINDOW_TRUNCATED",
      "field": "createdTime",
      "message": "This result is incomplete: the range filter on \"createdTime\" reached the 5000-row ceiling of a windowed search, so the remaining time windows were never requested. Narrow the date range or add filters — paging is not available on a windowed search."
    }
  ]
}

Проверяйте meta.warnings до того, как считать выдачу полной. Ни meta.hasMore, ни meta.total для этого не годятся: в примере выше оба говорят, что выдача закончилась, — они описывают набранное, а не то, что осталось за границей. Пагинация тоже не спасает: при активном разбиении по датам смещение больше нуля отклоняется кодом 400 UNSTABLE_OFFSET_PAGINATION, поэтому дочитать остаток следующей страницей не получится. Сузьте диапазон дат или добавьте фильтров, чтобы поиск перестал упираться в потолок. Поиск по узкому диапазону, который на окна не разбивается, этим предупреждением не затронут.

Агрегация вместо выборки записей

Когда нужны суммы, минимумы, максимумы или средние, сначала убедитесь, что GET /v1/guide показывает для сущности operations.aggregate. После этого 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, когда прочитано меньше записей, чем обещал data.count, — в том числе когда под фильтр попало больше 5000, — либо когда срез оборвался ошибкой подстраницы. Размер нехватки лежит в data.meta.recordsShortfall, оборванный срез — в data.meta.pageErrorSample. Потолок не единственная причина этой пометки, поэтому проверять её значением надёжнее, чем сравнивать data.count с 5000.

Для функции count действует отдельный канон листания и количества записей. Используйте её только по пути, явно указанному в operations.search.paginationStability.counting. Наличие operations.aggregate для других функций не доказывает доступность точного счёта, и наоборот. Пример ниже применим только к явно указанному пути. Не обходите коллекцию ради подсчёта:

JSON
{
  "aggregate": [ { "field": "*", "function": "count" } ],
  "filter": { "stageId": "NEW" }
}

Очередь портала

У каждого портала Битрикс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 с разбивкой по датам.
  • Когда нужны агрегаты, а не записи, и GET /v1/guide показывает operations.aggregatePOST /v1/{entity}/aggregate. Точный счёт использует только путь из operations.search.paginationStability.counting.

Повтор при перегрузке очереди. Под нагрузкой очередь возвращает два разных кода, и оба означают «повтори позже»:

  • 429 QUEUE_OVERFLOW — очередь переполнена, запрос отклонён сразу, за миллисекунды. В заголовке Retry-After — рекомендованная пауза в секундах.
  • 429 QUEUE_TIMEOUT — запрос ждал места дольше 30 секунд. Запрос не был отправлен в Битрикс24 — безопасно повторить. В теле error.retryAfter — рекомендованная пауза.

Виджеты аналитики, которые шлют пачку /search подряд, должны делать повтор с экспоненциальной задержкой и случайным разбросом по времени, учитывая 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))
  }
}

Паузы по отдельному методу. Кроме очереди запрос отбивают ещё две паузы. Обе отвечают 429 с заголовком Retry-After и снимаются автоматически, поэтому цикл повтора выше подходит и для них. Поле error.scope говорит, на кого пауза распространяется:

  • 429 OPERATION_TIME_LIMIT, scope: "apiKey" — Битрикс24 приостановил этот метод для вашего ключа примерно на 5 минут: метод исчерпал бюджет рабочего времени на портале. Остальные методы и другие ключи портала работают.
  • 429 TIMEOUT_QUARANTINE, scope: "portal" — метод несколько раз подряд не ответил порталу за отведённое вызову время, и пара «портал + метод» поставлена на паузу на стороне Вайбкод. Пауза действует для всех ключей портала. Не сокращайте интервал повторов: раз в 5 минут один вызов пропускается как проба восстановления, и частый повтор занимает этот слот собой — метод остаётся закрытым дольше. Механизм в процессе раскатки: пока он не включён на портале, этот код не приходит.

Эти паузы измеряются минутами, а не секундами, как отказы очереди. Ждать их в пользовательском запросе не стоит — переносите повтор в фоновую задачу.

Описание обоих кодов — Ошибки.

Клиентский таймаут

Ответ приходит не мгновенно: запрос сначала ждёт места в очереди портала, потом выполняется в Битрикс24. Обе фазы ограничены сверху, как и удержание соединения платформой, а таймаут на стороне клиента должен превышать сумму первых двух.

Фаза Предел Что приходит по истечении
Ожидание места в очереди портала 30 секунд 429 QUEUE_TIMEOUT — в Битрикс24 запрос не ушёл, повтор безопасен
Один вызов в Битрикс24 15 секунд 503 BITRIX_TIMEOUT
Удержание соединения платформой 660 секунд соединение закрывается

Отсюда рабочее значение: таймаут ожидания ответа — от 60 секунд, а не 30. Ожидание в очереди запрос проходит один раз, за себя целиком, а не за каждую страницу. Дальше запрос с limit > 50 читает записи несколькими последовательными вызовами по 50 штук, каждый со своим пределом в 15 секунд, поэтому широкая выборка отвечает дольше одной страницы.

Что помогает вместо одного длинного запроса:

  • Читать страницами по 50 записей и идти курсором. Каждый вызов короткий, а прерванный обход продолжается с последнего meta.nextAfterId, не начиная сначала.
  • Задавать таймауты раздельно — на установление соединения и на ожидание данных. В Python: requests.get(url, headers=headers, timeout=(10, 60)) — 10 секунд на соединение, 60 на ожидание данных от сервера.
  • Для выборок по широкому диапазону дат — POST /v1/{entity}/search: диапазон разбивается на окна, которые выполняются параллельными волнами.

Загрузка сообщений из нескольких диалогов

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` и `/v1/{entity}/fields`

Ответы GET /v1/users, GET /v1/statuses и GET /v1/{entity}/fields кэшируются на стороне сервера. Пользователи — 60 секунд. Справочники CRM и схемы полей — 5 минут. Это ускоряет дашборды, которые запрашивают эти эндпоинты при каждой загрузке.

Кэш GET /v1/users привязан к личному ключу vibe_api_.... Кэш GET /v1/statuses привязан к порталу: личные ключи одного портала используют одну запись, потому что стадии и справочники CRM общие для портала.

Кэш GET /v1/{entity}/fields привязан к порталу, ключу авторизации, сущности, параметрам пути, параметрам запроса и языку ответа. Полные ответы сохраняются на 5 минут. Ответы с предупреждением fields_partial не сохраняются, чтобы следующий запрос мог получить полную схему полей.

Для ключа авторизации OAuth-приложения vibe_app_... кэш не используется — у разных пользователей разный доступ к данным портала.

Запись через API сбрасывает соответствующий кэш сразу. POST /v1/users, PATCH /v1/users/:id и аналогичные операции сбрасывают кэш пользователей и справочников. POST / PATCH / DELETE на /v1/userfields/:entity и /v1/items/:entityTypeId/userfields сбрасывают кэш GET /v1/{entity}/fields для этой сущности или смарт-процесса. Правка напрямую в интерфейсе Битрикс24 кэшу не видна, поэтому такие изменения могут отображаться с задержкой до конца времени жизни кэша: до 60 секунд для пользователей и до 5 минут для справочников и схем полей.

Чтобы получить заведомо свежие данные в обход кэша, добавьте заголовок Cache-Control: no-cache. Для GET /v1/{entity}/fields также работает параметр refresh=true:

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 или refresh=true для /fields. Причина указывается в заголовке 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 в одном запросе
Очередь портала ограниченное число одновременных запросов, ожидание до 30 секунд
Кэш ответов /v1/users / /v1/statuses / /v1/{entity}/fields 60 секунд / 5 минут / 5 минут, обход — заголовок Cache-Control: no-cache, для /fields также refresh=true

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