Для 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), как на остальных дверях. Раньше такой подвызов отдавал всё, что
прислал портал, — с окнами это означало бы, что страницы разных смещений перекрываются и
клиент читает одни записи дважды.
Что делать интеграторам
- Уберите
offsetиз подвызовов кtelephony-lines: смещение этой сущности недоступно, и ответUNSUPPORTED_OFFSETназывает это прямо. Нужна выборка — сужайте её фильтром. - Если код рассчитывал на страницу длиннее запрошенной — передавайте нужное число в
limitявно, до 5000 записей. - Листайте по
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:
имя зависит от языка ключа.