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

Изменения API: 22 сентября 2026

← Журнал изменений · Сентябрь 2026

BC-0922-1: пакет одной сущности листает списки: offset в подвызове наконец читается

Поддержка старого формата до: не предусмотрена

Было

Списочный подвызов POST /v1/{entity}/batch игнорировал offset: параметр не извлекался из params, на сторону Битрикс24 не уезжал и клиентским окном не применялся. Два подвызова, отличающиеся только смещением, возвращали HTTP 200 и одни и те же записи — листать пакетом одной сущности было невозможно, тогда как общий POST /v1/batch и одиночные GET /v1/{entity} и POST /v1/{entity}/search смещение читали. У сущностей, чей метод Битрикс24 навигацию не поддерживает, тот же подвызов тоже отвечал HTTP 200 — первой порцией записей при любом смещении, то есть молча не тем окном, которое просил клиент.

Стало

Подвызов читает offset и отдаёт честное окно [offset, offset + limit) — тем же разбором, что общая дверь: смещение выравнивается под страницу Битрикс24, остаток снимается с головы на нашей стороне, а у сущностей, чей метод навигацию не применяет (statuses, deal-categories, bizproc-activities, bizproc-robots) и у тех, что отдают весь набор одним ответом, окно режется по полной коллекции. Ответ подвызова теперь несёт hasMore рядом с total, а вырожденное окно приезжает предупреждением OFFSET_BEYOND_FETCHED_PAGE в meta этого же подвызова.

Ломающая часть одна: сущность, чей метод Битрикс24 смещение принять не может (сегодня это telephony-lines), на подвызов с offset больше нуля отвечает ошибкой UNSUPPORTED_OFFSET вместо прежних HTTP 200 и первой порции записей. Отказ пер-вызовный — соседние подвызовы пакета выполняются, и сам пакет по-прежнему отвечает HTTP 200. Вместе со смещением подвызов начал соблюдать и limit: страница, которую Битрикс24 вернул длиннее запрошенной, режется по limit (по умолчанию 50), как на остальных дверях. Раньше такой подвызов отдавал всё, что прислал портал, — с окнами это означало бы, что страницы разных смещений перекрываются и клиент читает одни записи дважды.

Что делать интеграторам

  1. Уберите offset из подвызовов к telephony-lines: смещение этой сущности недоступно, и ответ UNSUPPORTED_OFFSET называет это прямо. Нужна выборка — сужайте её фильтром.
  2. Если код рассчитывал на страницу длиннее запрошенной — передавайте нужное число в limit явно, до 5000 записей.
  3. Листайте по hasMore из ответа подвызова, а не по арифметике от total.

NEW-0922-2: два новых кода отказа для ключей рантайма агента

Ключ рантайма агента теперь получает два кода отказа, которых раньше не было. Пока ход агента ждёт подтверждения пользователя, POST /v1/chat/completions отвечает 409 с кодом agent_turn_awaiting_confirmation: обращения к модели по такому ходу не выполняются, поэтому ожидание ответа человека больше не расходует лимит. Код снимается, как только пользователь подтвердил или отменил операцию, а также по истечении срока ожидания.

Вызов DELETE к V1 от того же ключа, совпавший с предыдущим по методу и адресу в пределах окна в 30 секунд, отвечает 409 с кодом AGENT_WRITE_ALREADY_EXECUTED. Такой вызов на портал не уходит, а в поле error.firstStatus возвращается код ответа первого удаления и в error.firstExecutedAt — его время. Неуспешное первое удаление повтор не запирает: ретрай проходит обычным порядком. Создание и обновление дедупликации не подлежат.

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

NEW-0922-3: приём результата долгого метода решения

Появился публичный маршрут POST /v1/solution-calls/:callId/result, куда решение присылает результат асинхронного вызова метода по контракту (solution.invoke с mode: async). Адрес, одноразовый reply-токен и срок приходят решению вместе с самим вызовом в заголовках X-Vibe-Reply-Url, X-Vibe-Reply-Token и X-Vibe-Reply-Deadline; платформа шлёт вызов с Prefer: respond-async — решение отвечает 202 и присылает результат сюда либо отвечает 200 с тем же телом сразу. Аутентификация — Authorization: Bearer vcr_…, ключ платформы на этом маршруте не принимается. Тело — {"outcome":"completed","result":{…}} либо {"outcome":"failed","error":{"code","message","problem"}}; ответ 200 с data.state. Ошибки: 401 REPLY_TOKEN_INVALID (токен не подошёл ни к одному открытому вызову; существование callId не раскрывается), 409 SOLUTION_CALL_CLOSED (вызов уже закрыт, error.state несёт его состояние), 422 RESULT_INVALID (тело больше 512 КиБ, не JSON нужной формы или result не по схеме того снимка контракта, по которому вызов принят). Ответ 422 закрывает вызов как failed — повторять с тем же телом бессмысленно. Принятый исход платформа доставляет на портал Битрикс24 сама. Прежние вызовы и ответы не меняются: до этого релиза mode: async отвечал FEATURE_DISABLED, и на порталах без включённой возможности ответ остаётся прежним.

FIX-0922-4: отказ Битрикс24 «не передан параметр» отвечает 400, а не 422

Было

Когда Битрикс24 отклонял вызов до запуска метода — потому что вызов не принёс параметр, который метод объявляет обязательным, — портал отвечал Could not find value for parameter {…}, а платформа Вайбкод передавала это наружу как 422 BITRIX_ERROR, то есть как бизнес-ошибку портала. Имя недостающего параметра лежало только в тексте сообщения, подсказки не было, и повтор того же запроса возвращал тот же отказ.

Стало

Тот же отказ приходит как 400 INVALID_PARAMS — код той же группы, что и остальные отклонения параметров со стороны Битрикс24, — а error.hint называет параметр, значения которого не хватило, и говорит, что повтор без изменения вызова не поможет. Ответ на любой запрос, который Битрикс24 принимает, не изменился.

Влияние на интеграторов

Клиент, который различал этот случай по 422, увидит 400 INVALID_PARAMS. Ответ по-прежнему несёт текст Битрикс24 в error.message, а имя параметра теперь ещё и в error.hint. Отказы, отклонённые проверками самой платформы до обращения к порталу, как и раньше отвечают 400 MISSING_REQUIRED_PARAMS.

FIX-0922-5: смена адреса портала: вызов отвечает 409 `PORTAL_ADDRESS_CHANGED` вместо 500

Было

После смены адреса портала в Битрикс24 вебхук выданного ключа оставался выписан на прежний адрес. Платформа отбивала такой вызов до отправки — секрет не уходит туда, где портала больше нет, — но отказ был безымянным: любой проксируемый запрос отвечал 500 INTERNAL_ERROR без кода и без подсказки, а в батч-конверте подвызов уезжал в общий бакет CALL_FAILED. Причину и путь восстановления клиент из ответа узнать не мог.

Стало

Отказ называет и причину, и действие: 409 с кодом PORTAL_ADDRESS_CHANGED, подсказка ведёт на переподключение ключа — в разделе «Ключи» кнопка «Переподключить»; строка ключа и привязанные к нему боты при этом сохраняются. Тот же код с той же подсказкой едет в подошибке батч-конверта. Срока ожидания отказ не несёт намеренно: повтор не поможет, пока вебхук ключа не перевыпущен.

FIX-0922-6: удаление приложения освобождает ключ авторизации в карточке

Было

DELETE /v1/apps/{id} снимал приложение и отзывал парные ключи, но карточка приложения продолжала считать ключ авторизации выданным. Выдать новый ключ было нельзя — дверь выдачи отвечала 409 APPLICATION_HAS_AUTH_KEY, а перевыпуск — 409 APPLICATION_NO_AUTH_KEY. Тем же следствием POST /v1/cowork/applications/{id}/key возвращал warningCodes со значением APPLICATION_HAS_AUTH_KEY для приложения, у которого ключа авторизации уже не было.

Стало

Удаление снимает и привязку: после него приложение считается без ключа авторизации, ложный APPLICATION_HAS_AUTH_KEY в warningCodes по такому приложению больше не приходит, а выдача нового ключа проходит штатно. Успешный ответ самого удаления не изменился — это по-прежнему HTTP 204.

FIX-0922-7: схема агрегации в OpenAPI описывает поля так же, как их принимает API

Правка касается ОПИСАНИЯ в GET /v1/openapi.json; поведение POST /v1/{entity}/aggregate не меняется, ответы прежние.

Было

Поле aggregate[].field публиковалось закрытым списком из "*" и полей группировки сущности. Список группировки и поля, по которым считаются sum/avg/min/max, — разные множества, поэтому клиент, проверяющий тело запроса по спеке, не отправлял вызовы, которые API выполняет: агрегацию по числовому полю сущности вне списка группировки (у сделок это probability, taxValue, receivedAmount и другие) и по пользовательскому полю портала типа integer, double или money. Одновременно спека разрешала пары, на которые API всегда отвечает 400 INVALID_PARAMS: count по именованному полю и числовую функцию по "*" или пустому имени. Поле groupBy публиковалось таким же закрытым списком и не допускало пользовательских полей, которые API принимает.

Стало

aggregate[].field описан в паре с function: count считается по "*", а sum/avg/min/max принимают имя числового поля — как объявленного в сущности, так и пользовательского поля портала. Числовые поля сущности перечислены в examples как подсказка, а не как ограничение: набор пользовательских полей зависит от портала и в общей спеке не публикуется, актуальный список отдаёт GET /v1/{entity}/fields. Пары, на которые API всегда отвечал отказом, схема теперь тоже отвергает — включая агрегацию по полю, которое сущность объявляет нечисловым: такое имя API отклоняет независимо от того, что настроено на портале. groupBy допускает пользовательские поля и отвергает имена, совпадающие с ключами ответа (count, aggregates, meta, groups), — их API не принимал никогда. Текстовое описание операции больше не выдаёт список группировки за список полей агрегации: теперь оно называет обе роли раздельно.

FIX-0922-8: подняты дефолтные лимиты на пользователя — ключи, серверы, боты

Было

На портале, где эти лимиты ни разу не настраивали вручную, по умолчанию действовали ограничения на пользователя: 10 API-ключей, 5 серверов, 5 ботов.

Стало

Дефолты подняты до 100 ключей, 50 серверов и 50 ботов на пользователя. Изменение затрагивает только порталы, которые не задавали свои значения; портал с собственной настройкой сохраняет её без изменений. Существующие запросы работают по-прежнему — доступного объёма стало больше.

BC-0922-9: Повтор незавершённой ротации ключа требует восстановления

Поддержка старого формата до: не предусмотрена

Было

После неполного отката замены ключа запрос с новым Idempotency-Key мог ответить 201 для осиротевшего кандидата, хотя отзыв токенов исходного ключа не был подтверждён.

Стало

Повторная ротация исходного или нового ключа отвечает 409 KEY_ROTATION_RECOVERY_REQUIRED. Замена ключа приложения и назначение такого ключа серверу отвечают 409 APPLICATION_KEY_RECOVERY_REQUIRED. Новый Idempotency-Key не обходит отказ. Выдача токена доступа при незавершённой ротации также отвечает 409 KEY_ROTATION_RECOVERY_REQUIRED, а если сервер уже сменил ключ — 403 SERVER_KEY_MISMATCH, без нового токена. Передача бота с исходным или целевым ключом в состоянии незавершённой ротации отвечает 400 TARGET_KEY_INVALID с error.reason: recovery_required, без изменения владельца. Параллельная передача того же портала отвечает существующим 409 BOT_TRANSFER_CONFLICT вместо непрозрачного 500; привязка не меняется.

Затронутые эндпоинты: POST /v1/keys/{id}/rotate, DELETE /v1/keys/{id}, POST /v1/cowork/applications/{id}/key, POST /v1/infra/servers, POST /v1/infra/servers/{id}/access-tokens, POST /v1/bots/{botId}/transfer.

Неподтверждённый отзыв отвечает 500 KEY_ROTATE_REVOKE_FAILED без сырого секрета. Кандидат указан в error.details.orphanKeyId, остаток отката — в error.details.strandedSlots. Непустой остаток требует поддержки. Отсутствующий или пустой остаток сам по себе не разрешает повтор. Ничем не используемый кандидат удаляется только штатным DELETE-эндпоинтом после подтверждения, что на него больше не ссылаются другие ресурсы.

Влияние на интеграторов

Не повторяйте запрос с новым ключом идемпотентности. Завершите восстановление через поддержку либо подтвердите штатное удаление пустого кандидата, затем перечитайте актуальное состояние ключа и сервера перед новым запросом. Поддержка прежнего поведения не предусмотрена.

FIX-0922-10: служебные имена JavaScript больше не подменяют значение параметра

Было

Имена, которые есть у любого объекта JavaScript — constructor, toString, valueOf, hasOwnProperty, — при сверке со списком допустимых значений считались найденными в этом списке. Значением оказывалась служебная функция, и дальше поведение расходилось по ручкам:

  • GET /v1/userfields/constructor — отказ 400 UNKNOWN_ENTITY не приходил, вместо него возвращалась ошибка Битрикс24;
  • GET /v1/requisite-links?filter[constructor]=… и ?sort=constructor — вместо 400 UNKNOWN_FILTER_FIELD / 400 UNKNOWN_SORT_FIELD в Битрикс24 уходило мусорное имя поля;
  • GET /v1/openline-configs?filter[constructor]=… и ?sort=constructor — мусорное имя поля вместо ожидаемого CONSTRUCTOR; отказа по неизвестному полю у этой ручки нет и не было;
  • POST/PATCH /v1/userfields/:entity — поле с таким именем уезжало в Битрикс24 под подменённым именем вместо передачи как есть; то же — у внутренних ключей элементов списка (list);
  • POST /v1/users/invite — то же подменённое имя вместо передачи как есть;
  • model: "constructor" в запросах к AI подменял имя модели служебным значением.

Стало

Список допустимых значений проверяется по собственным ключам, поэтому служебные имена в нём не находятся. Там, где ручка отвечает отказом на неизвестное значение, этот отказ приходит до обращения к Битрикс24; там, где отказа нет, имя поля передаётся как есть.

NEW-0922-11: билет десктопа Коворк/Код для телефонного доступа

Новый метод POST /v1/cowork/relay-ticket выдаёт десктопному приложению Коворк/Код короткоживущий подписанный билет, по которому relay телефонного доступа пускает десктоп. В теле передаётся pubkey — публичный ключ Ed25519 десктопа (32 байта, base64url без паддинга). Ответ 200 содержит ticket (JWT с алгоритмом EdDSA, живёт 5 минут) и expiresAt. Метод доступен только ключу десктопного приложения со скоупом vibe:cowork и только при активном месте Коворк/Код.

Коды отказов: 403 INSUFFICIENT_SCOPE (нет скоупа vibe:cowork), 403 COWORK_DESKTOP_KEY_REQUIRED (ключ не десктопного приложения), 404 COWORK_NOT_ACTIVATED (нет места), 403 COWORK_SEAT_INACTIVE (место не активно), 400 INVALID_PUBKEY (неверный ключ), 429 (не больше 30 билетов в час на человека), 503 COWORK_FEATURE_DISABLED и 503 COWORK_RELAY_NOT_CONFIGURED (выдача билетов временно недоступна).

FIX-0922-12: политика «только владелец» работает одинаково на всех входах в приложение

Было

При политике OWNER_ONLY пользователь с записью в списке доступа открывал приложение через плейсмент внутри Битрикс24, но получал отказ по прямой ссылке. Документация при этом обещает, что при OWNER_ONLY записи списка доступа не применяются: сценарий «вернуть приватность» — перевести сервер обратно в OWNER_ONLY и оставить записи в базе — на деле закрывал доступ не для всех.

Стало

Вход один и тот же на всех путях: при OWNER_ONLY приложение открывает только владелец, а записи списка доступа не применяются, как и написано в документации. Чтобы снова открыть доступ конкретным людям, переключите политику на NAMED_USERS — записи уже в базе и начнут действовать сразу.

Влияние на интеграторов

Если ваш сценарий опирался на то, что человек из списка доступа входит через плейсмент при OWNER_ONLY, переключите сервер на NAMED_USERS: набор людей останется прежним.

FIX-0922-13: приложению в галактике снова можно задать расписание пробуждения

Было

Приложению внутри галактики — в том числе AI-агенту — нельзя было задать окно расписания: POST /v1/infra/servers/{id}/wake-schedules отвечал 400 ALWAYS_ON_CONFLICT, как серверу, который владелец оплатил на круглосуточную работу. На самом деле такой выбор никто не делал: тариф приложения наследуется от галактики, а галактике доступны только тарифы без прерываний, поэтому признак «работает круглосуточно» выполнялся сам собой. Вместе с тем, что агенту недоступен сон по бездействию, у владельца не оставалось способа остановить работу на ночь — при том, что оплата шла круглосуточно.

Стало

Тариф, унаследованный от галактики, больше не считается выбором круглосуточного режима: окна расписания приложению в галактике задаются обычным порядком. У отдельного сервера, которому владелец сам выбрал тариф без прерываний и отключил сон, поведение прежнее — 400 ALWAYS_ON_CONFLICT.

Влияние на интеграторов

Действий не требуется. Запрос, который раньше отклонялся для приложения в галактике, теперь создаёт окно; ответ GET /v1/infra/servers/{id}/logs у спящего приложения больше не сообщает об отказе окна.

NEW-0922-14: в библиотеке расписаний работы появились три новые готовые заготовки

GET /v1/work-schedules отдаёт три дополнительных готовых расписания — weekdays-9-19, weekdays-9-20 и weekdays-8-19 (будни, понедельник–пятница). Раньше готовых было три, и, если рабочая неделя аккаунта в них не попадала, оставалось заводить своё расписание через POST /v1/work-schedules, даже когда отличие было в одном часе.

Новые заготовки заводятся в аккаунте при первом чтении библиотеки, как и прежние, и так же не редактируются: у заготовки canEdit: false, а попытка правки отвечает WORK_SCHEDULE_PRESET_READONLY. Назначать их машинам платформа сама не станет — они лишь появляются в списке.

Прежние ключи и их окна не менялись, уже назначенные машины остались на своих расписаниях.

Набор заготовок может пополняться и дальше, поэтому незнакомый presetKey стоит считать заготовкой без локальной подписи, а не ошибкой. Различать заготовки надёжнее по presetKey, а не по name: имя зависит от языка ключа.