Для AI-агентов: markdown этой страницы — /docs-content/changelog/2026-09-15.md индекс документации — /llms.txt
Изменения API: 15 сентября 2026
← Журнал изменений · Сентябрь 2026
BC-0915-1: Black Hole классифицирует ответ приложения по автору, а не по статусу; новый код BH_APP_TIMEOUT
Поддержка старого формата до: не предусмотрена
Было
Шлюз перехватывал ответ приложения по HTTP-статусу: 502 и 504 — всегда, 503 — если ответ не был Content-Type: application/json. Перехваченный ответ подменялся на 503 с кодом BH_APP_STARTING и заголовком Retry-After: 3, тело и заголовки приложения при этом терялись.
Стало
Шлюз классифицирует ответ по его автору, а не по статусу. Ответ, который написало само приложение, доходит до вызывающего дословно — статус, заголовки, тело. Это касается 502, 504 и 503 любого типа, кроме двух форм, неотличимых от отказа самого агента: 503 с Content-Type: text/html и 502 совсем без Content-Type по-прежнему заменяются экраном BH_APP_STARTING. Помимо этих двух форм подменяется только то, что приложение не писало: кадра из туннеля не было вовсе, либо ответил сам агент — сообщил, что на порту никто не слушает, либо отказал сам (например его текстовый отказ по перегрузке, 503 Too many concurrent requests с Content-Type: text/plain, под эти две формы не подпадает и тоже доходит дословно — это не ошибка вашего приложения, а насыщение агента параллельными запросами).
Собственное окно шлюза, в которое от приложения не пришло вовремя полного ответа (30 секунд без единого кадра, либо уже начатый ответ замолчал дольше 15 секунд), больше не выдаёт себя за BH_APP_STARTING — теперь это отдельный код 504 BH_APP_TIMEOUT без заголовка Retry-After: запрос мог быть доставлен приложению и выполниться, поэтому автоматический повтор небезопасен. От собственного 504 приложения (который тоже проходит дословно) он отличается только телом — error.code: BH_APP_TIMEOUT в JSON-конверте шлюза.
Что делать интеграторам
Обрабатывайте 504 BH_APP_TIMEOUT отдельно от 503 BH_APP_STARTING: перед повтором записи проверьте эффект операции по устойчивому идентификатору, Retry-After в ответе не будет. Если код полагался, что 502/503/504 от вашего приложения всегда приходит как BH_APP_STARTING без содержимого, — обновите обработку: теперь такие ответы (кроме двух форм выше) проходят с реальным телом и заголовками приложения. Чтобы собственная ошибка приложения не подменялась шлюзом, не отвечайте на неё 503 с Content-Type: text/html и не отвечайте 502 вовсе без заголовка Content-Type.
Подробнее — Среда выполнения приложения и Что безопасно повторять.
FIX-0915-2: подписка на события портала принимает коды событий с точками
Было
POST /v1/infra/servers/:id/event-subscriptions отклонял официальные коды событий Битрикс24 с точками, например CATALOG.PRODUCT.ON.ADD, ответом 400 INVALID_EVENT. Подписаться на такие события было нельзя.
Стало
Метод принимает оба формата кода события: без точек (ONTASKADD) и с точками (CATALOG.PRODUCT.ON.ADD). Для кодов без точек ответ по-прежнему HTTP 200. Код не переписывается: точки не удаляются, и в доставленных событиях приходит тот же код. Строчные коды по-прежнему получают 400 INVALID_EVENT.
Влияние на интеграторов
Менять ничего не нужно. Теперь можно подписываться на события Битрикс24, коды которых содержат точки.
FIX-0915-3: модели bitrixgpt-* больше не называют базовую модель в ответе
Было
Рассказывая о себе, модель семейства bitrixgpt-* могла назвать в тексте ответа стороннюю
базовую модель и её разработчика — и в обычном ответе (choices[].message.content), и в
потоковом (choices[].delta.content).
Стало
Правило распознаёт утверждение модели о себе от первого лица: связку, у которой название
стоит предикатом («я — …»), и формы самоописания («моя базовая модель …», «меня
разработал …»). В таком утверждении название базовой модели заменяется на публичное имя
модели, а разработчик — на Bitrix24. Правило работает одинаково в обычном и потоковом
режиме и применяется по фактически обслужившей модели, а не по полю model из запроса.
Ответ остаётся HTTP 200, его структура не меняется. Упоминание чужой модели в обычном
тексте ответа (например «Llama — модель с открытыми весами») не переписывается: правило
срабатывает только на высказывание модели о самой себе и не разбирает произвольные
формулировки — оно не заменяет продуктовую настройку идентичности. Не затрагиваются модели,
у которых происхождение указано в публичном идентификаторе, ключи с собственными
провайдерами (BYOK), поля reasoning_content и tool_calls.
На запросе с response_format (json_object или json_schema) правило не работает
вовсе — одинаково в обычном и потоковом режиме. Остальная обработка ответа при этом не
меняется: как и раньше, роутер извлекает блок рассуждений в reasoning_content.
FIX-0915-4: ссылка на страницу цен у аккаунтов Беларуси, Казахстана и Узбекистана ведёт на сайт их страны
Было
Аккаунт из Беларуси, Казахстана или Узбекистана без платного или демо-тарифа получал отказ BY_PAID_ONLY, KZ_PAID_ONLY или UZ_PAID_ONLY со ссылкой на страницу цен российского сайта Битрикс24: в полях details.upgradeUrl и alternatives[0].url ответа 402 метода POST /v1/infra/servers, в слоте capabilities.servers.create ответа GET /v1/me и в тексте userMessage. Купить там тариф для аккаунта из этих стран нельзя. Ссылка activation.tariffInfoUrl в ответе GET /v1/cowork/state у аккаунтов Казахстана и Узбекистана вела туда же.
Стало
Ссылка ведёт на страницу цен сайта страны аккаунта: https://www.bitrix24.by/prices/, https://www.bitrix24.kz/prices/ или https://www.bitrix24.uz/prices/. То же у любого другого отказа такого аккаунта, в котором есть ссылка на страницу цен. Коды отказа, статусы и структура ответа не изменились, поменялось только значение адреса. У аккаунтов других стран адрес прежний.
FIX-0915-5: приложения Black Hole на коробочном портале получают номер сотрудника при входе по прямой ссылке
Было
Сотрудник коробочного портала открывал приложение Black Hole по прямой ссылке, не входя в кабинет платформы. Если почта в его учётной записи Битрикс24 Нетворк не совпадала с почтой на портале, заголовок X-Vibe-User-Id приходил в приложение со значением net_<id>, как у посетителя не из портала. Именной доступ, выданный по номеру сотрудника, на такого посетителя не действовал.
Стало
Такой посетитель узнаётся по номеру сотрудника, уже записанному в его учётной записи на платформе Вайбкод. X-Vibe-User-Id приходит числом — тем же, что и при открытии приложения из портала, — и именной доступ по номеру сотрудника действует.
Влияние на интеграторов
Действий не требуется. Если приложение хранило данные таких посетителей под значением net_<id>, эти же люди теперь приходят с числовым идентификатором — тем, с которым они уже открывали приложение из портала.
FIX-0915-6: отказ на замороженном счёте не обещает оплату резервной модели из кошелька
Было
Ключ подписки Коворк/Код с исчерпанной квотой на счёте, замороженном за долг, получал от POST /v1/chat/completions отказ 402 ACCOUNT_FROZEN с текстом «резервная модель оплачивается из кошелька». Списания за ответ резервной модели не существует: он не расходует ни квоту подписки, ни баланс кошелька, а инференс платформа оплачивает сама. Интегратор, показывавший этот текст пользователю, объяснял отказ несуществующим списанием и отправлял искать деньги там, где их не снимают.
Стало
Текст называет настоящую причину: квота подписки исчерпана, а ответ резервной модели на замороженном счёте не выдаётся; продолжить работу можно после пополнения баланса. Код отказа ACCOUNT_FROZEN, статус 402 и форма тела прежние.
Влияние на интеграторов
Менять ничего не нужно: код отказа и статус не изменились. Обработчик, который показывает пользователю error.message, станет говорить правду про деньги.
FIX-0915-8: отказ в доступе к приложению Black Hole объясняет, под какой учётной записью узнали посетителя
Было
Посетитель, которому отказано в доступе к приложению Black Hole, видел страницу отказа на домене самого приложения. Она не называла, под какой учётной записью его узнала платформа, поэтому «я вошёл не тем аккаунтом» было не отличить от «меня не добавили в список доступа». Разобраться можно было только выйдя из учётной записи и войдя заново.
Стало
Обычная вкладка браузера переводится на страницу платформы «Нет доступа к приложению». Она называет имя и почту самого посетителя — те, под которыми его узнали, — и домен портала приложения, если посетитель состоит в этом портале. Ничего об авторе приложения и о списке доступа страница не показывает.
Открытие внутри Битрикс24 ничего не меняет: во встроенном окне остаётся прежняя страница отказа, потому что уводить встроенное приложение на другой адрес нельзя. Программные вызовы тоже не меняются — они по-прежнему получают ответ 403 с кодом BH_ACCESS_DENIED.
Влияние на интеграторов
Действий не требуется.
NEW-0915-9: самоописание API называет интеграцию 1С
Самоописание платформы теперь ведёт агента в раздел интеграции 1С. В ответе GET /v1/guide появился блок onecApi — три операции раздела с описанием полей запроса, состояний операции и ссылками на документацию, а в GET /v1/me добавлена строка в api._rules с тем же маршрутом чтения данных. Прежние поля обоих ответов не изменились.
Страницы раздела описывают предусловия, порядок обмена и коды отказов — Интеграция 1С.
FIX-0915-10: ключ внешнего участника привязан к своему серверу
Было
Запрос с ключом внешнего участника мог содержать в адресе сервер, отличный от сервера, для которого выпущен ключ. При действующем доступе к указанному серверу API обрабатывал такой запрос вместо ответа с ошибкой несовпадения.
Стало
Теперь запрос, в адресе которого указан сервер, отличный от сервера ключа, получает
EXTERNAL_COLLABORATOR_KEY_SERVER_MISMATCH без сведений о запрошенном сервере.
Влияние на интеграторов
Корректные вызовы с ключом своего сервера не меняются. Для работы с несколькими серверами используйте ключ соответствующего внешнего членства.
Затронутые эндпоинты: GET /v1/infra/servers/:id, PATCH /v1/infra/servers/:id, DELETE /v1/infra/servers/:id, POST /v1/infra/servers/:id/deploy, POST /v1/infra/servers/:id/exec, POST /v1/infra/servers/:id/upload, GET /v1/infra/servers/:id/logs, POST /v1/infra/servers/:id/wake, GET /v1/infra/servers/:id/sources, POST /v1/infra/servers/:id/sources, GET /v1/infra/servers/:id/sources/:versionId, PATCH /v1/infra/servers/:id/sources/:versionId, DELETE /v1/infra/servers/:id/sources/:versionId, GET /v1/infra/servers/:id/sources/:versionId/download.
BC-0915-11: публикация приложения больше не скрывает отказ привязки места
Поддержка старого формата до: не предусмотрена
Было
Публикация приложения отвечала HTTP 200 и переводила приложение в PUBLISHED, даже если Битрикс24 отклонил все запрошенные привязки. Обобщённый HTTP 401 ключа разработчика в прямой привязке мог ошибочно превращаться в INT_TARIFF_REQUIRED.
Стало
HTTP 401 ключа разработчика считается отказом учётных данных и при наличии OAuth-токена автоматически повторяется по OAuth, только если ответ Битрикс24 не называет окончательную неавторизационную причину — например, подписочный отказ или нехватку прав. Явные неавторизационные отказы остаются окончательными при любом HTTP-статусе. Если ни один транспорт не подтвердил привязку, публикация отвечает HTTP 502 PLACEMENT_BIND_FAILED, не переводит приложение в PUBLISHED и возвращает безопасные машинные код и статус Битрикс24 в error.failures. Если в том же запросе не подтверждено снятие старого места, его код приходит в error.failedUnbinds. Сохранённый список уже содержит успешно привязанную часть. Прямая привязка без успешного OAuth-отхода отвечает HTTP 403 B24_ACCESS_DENIED, а не тарифным пейволом.
Что делать интеграторам
Считайте публикацию успешной только при HTTP 200. При PLACEMENT_BIND_FAILED перечитайте приложение, сохраните уже привязанные места из data.placements следующего запроса чтения и повторите публикацию только после устранения перечисленных причин. Для B24_ACCESS_DENIED обновите учётные данные или передайте действующую OAuth-сессию. Решение об OAuth fallback платформа уже приняла до ответа; сохраняйте error.failures для диагностики, но не запускайте свой повтор по внутреннему коду Битрикс24.
NEW-0915-12: внешний API приложений открыт всем порталам
Адрес ANY /v1/applications/{id}/api/** доступен на всех порталах: платформа принимает HTTP-запрос снаружи — от робота бизнес-процесса Битрикс24 или от другого приложения, — доставляет его приложению по его туннелю и возвращает ответ приложения как есть. Принимаются GET, POST, PUT, PATCH, DELETE и HEAD; всё после /api/ приложение получает как свой путь запроса, строка запроса и тело передаются дословно. Путь проверяется в исходном и в однократно раскодированном виде, его предел — 2048 символов, недопустимая форма пути или строки запроса даёт 400 APP_API_BAD_PATH.
Ключ. Адрес принимает только ключ внешнего API, выпущенный для этого приложения в его карточке на платформе Вайбкод. Передаётся заголовком X-Api-Key либо Authorization: Bearer — формы равноправны. Личный ключ и ключ авторизации приложения получают 403 APP_API_NOT_GRANTED, а ключ внешнего API на любом другом адресе платформы — 403 APP_API_KEY_OUT_OF_SCOPE. Отсутствующий или отозванный ключ — 401 MISSING_API_KEY / 401 INVALID_API_KEY, ключ в режиме чтения на изменяющем вызове — 403 WRITE_BLOCKED_READONLY_KEY. Вызовы тарифицируются владельцу приложения как запросы API: замороженный счёт даёт 402 ACCOUNT_FROZEN, исчерпанная квота — 429 QUOTA_EXCEEDED.
Условия на стороне приложения. Канал открыт, когда в карточке приложения включён переключатель «Внешний API», у приложения есть сервер и сервер не засыпает. Иначе приходят 409 APP_API_NOT_ENABLED, 409 APP_API_NO_SERVER и 409 APP_API_NOT_ALWAYS_ON; неизвестное или удалённое приложение — 404 APP_API_APP_NOT_FOUND. Включённый переключатель открывает держателям ключа весь HTTP-контур приложения: отбора маршрутов на стороне платформы нет, аутентификацию и разграничение доступа своих маршрутов приложение делает само, и заголовок Authorization для этого остаётся свободным — платформа срезает его только тогда, когда в нём лежит её собственный ключ.
Что получает приложение. Исходные метод, путь, строку запроса, тело и заголовки вызывающего, кроме ключа платформы X-Api-Key, Cookie, Host, Content-Length, служебных заголовков соединения, всего префикса X-Vibe- и заголовков доверия к прокси — семейств X-Forwarded, X-Original, X-Rewrite, CF, Fastly и точечных имён, из которых библиотеки читают адрес клиента (Forwarded, X-Real-Ip, Client-Ip и подобные). Взамен платформа ставит X-Vibe-Request-Id, X-Vibe-Caller-Kind: external-api, X-Vibe-Caller-Portal-Id и X-Vibe-Caller-Key-Id; заголовков X-Vibe-User-* и X-Vibe-Authorization на этом пути нет — внешний вызов сессии не несёт.
Что получает вызывающий. Статус, тело и заголовки ответа приложения как есть, кроме Set-Cookie, Content-Length, служебных заголовков соединения и префикса X-Vibe-; ответы 3xx не разворачиваются. Отказ платформы от ответа приложения отличает заголовок X-Vibecode-Proxy-Error: 1 — он стоит на каждом ответе, который построила платформа, и приложение поставить его не может. Тело отказа — конверт V1 {"success": false, "error": {"code", "message"}}. Сквозной идентификатор вызова X-Vibe-Request-Id на ответе описан записью NEW-0914-13.
Пределы. Тело запроса — 4 МиБ, больше даёт 413 APP_API_PAYLOAD_TOO_LARGE. Тело ответа приложения — 4 МиБ, больше даёт 502 APP_API_RESPONSE_TOO_LARGE без Retry-After: повтор такой ответ не исправит. Частота — 120 запросов в минуту на ключ, действующее значение читайте из заголовка X-RateLimit-Limit; сверх него 429 APP_API_RATE_LIMITED с Retry-After. Приложение, которое не отвечает, недоступный или насыщенный канал — 503 APP_API_UNAVAILABLE с Retry-After в секундах; ответ, не пришедший за общий предел вызова в 30 секунд, — 503 APP_API_TIMEOUT с Retry-After (запись BC-0914-25). Ответ приложения вне контракта, например статусом 1xx, — 502 APP_API_BAD_ENVELOPE. Долгую работу выносите за пределы вызова: отвечайте сразу и досылайте результат отдельно.
NEW-0915-13: вложения в комментариях задач и скачивание файла комментария
Комментарий задачи теперь несёт список вложений. Ключ присутствует всегда: без файлов это пустой список. У каждого вложения есть идентификатор файла и путь для скачивания, а также имя и размер, когда Битрикс24 их отдал. Путь приходит без домена — склейте его с тем же базовым адресом API, к которому обращались. Комментарий, у которого нет текста, кроме приложенного файла, теперь различим по непустому списку вложений — раньше он приходил с пустым текстом и ничем не выдавал файл. Состав выдачи при этом не изменился: такой комментарий возвращался и прежде.
Скачать байты файла позволяет новая операция GET /v1/tasks/:taskId/comments/:id/files/:fileId/download. Ей достаточно доступа task: расширять права ключа до всего Диска не требуется, а отдать она способна только файл того комментария, который этому ключу и так доступен на чтение. Файл другого комментария, равно как и файл с совпавшим по числу идентификатором, операция не отдаёт. Отдаются именно байты — адрес файла на портале в ответ не попадает.
Список полей GET /v1/tasks/:taskId/comments/fields пополнился записью attachments с описанием формы элемента. Та же запись появилась в GET /v1/guide — в entities[task-comments].fields и fieldsDetailed, где форма элемента отдана машиночитаемо, ключом itemSchema. Это важно для агента без токена портала: живой список полей ему недоступен, а гайд отдаётся и так.
NEW-0915-14: типы цен каталога доступны через API
Идентификаторы типов цен зависят от портала, а узнать их через V1 было нечем: в скоупе catalog был обёрнут только склад. Из-за этого доки предлагали считать базовой ценой 1, и интеграции, сделавшие так, получали от Битрикс24 422 с сообщением про неверную группу цен.
Добавлена сущность только для чтения GET /v1/catalog-price-types — список, запись по идентификатору, поиск и справочник полей. В ответе приходят id, name, base, xmlId, sort, createdBy, modifiedBy, dateCreate и timestampX. Базовый тип цены портала — запись со значением base равным Y, и её id не обязан быть равен единице. Скоуп прежний, catalog, но его мало: catalog.priceType.* в Битрикс24 доступен только владельцу ключа с правами администратора портала. Запись не поддерживается, типы цен заводятся в интерфейсе Битрикс24.
Ответ 422 от POST /v1/catalog-prices на неизвестный catalogGroupId теперь несёт подсказку с указанием на новый эндпоинт. Утверждение «базовая цена — 1» убрано из документации цен каталога.
Затронутые эндпоинты: GET /v1/catalog-price-types, GET /v1/catalog-price-types/:id, POST /v1/catalog-price-types/search, GET /v1/catalog-price-types/fields, POST /v1/catalog-prices
BC-0915-15: ключ «только чтение» снова выкладывает приложение на свой сервер
Поддержка старого формата до: не предусмотрена
Было
Запись BC-0825-2 закрыла ключу в режиме «только чтение» любую запись на платформенных
ручках, включая доставку кода на собственный сервер. POST /v1/infra/servers/{id}/deploy,
POST /v1/infra/servers/{id}/exec,
POST /v1/infra/servers/{id}/upload,
POST /v1/infra/servers/{id}/icon и
POST /v1/infra/servers/{id}/unstick
отвечали 403 WRITE_BLOCKED_READONLY_KEY до выполнения операции.
Стало
Эти ручки такому ключу проходят, вместе с POST /v1/infra/servers/{id}/unstick —
снятием залипшего exec-лока, восстановлением ровно для них. ⚠️ Это НЕ DELETE /v1/infra/servers/{id}/lock:
тот снимает зависший лок операции и был исключением и раньше. Рамка решения: режим «только чтение» ограничивает
данные Битрикс24, а собственное приложение вызывающего остаётся в его распоряжении. Группа
неделима — выложить произвольный архив и означает исполнить произвольный код, поэтому
разрешение на deploy без exec было бы мнимым ограничением.
Остальное поведение режима не изменилось. По-прежнему отвечают 403 WRITE_BLOCKED_READONLY_KEY
создание сервера POST /v1/infra/servers, управление жизненным
циклом (POST /v1/infra/servers/{id}/stop, start, reboot,
POST /v1/infra/servers/{id}/wake, сон и расписания пробуждения),
удаление сервера, а также ИИ, хранилище, ключи и места встраивания.
⚠️ Но перечень «что по-прежнему отказывает» не читайте как закрытый: у центрального
ограничения есть и другие исключения, заведённые раньше этого изменения. POST /v1/apps
таким ключом отвечает 201 — приложение и парный ключ заводятся в режиме «только чтение»,
а 403 приходит лишь на попытке выписать «чтение и запись». DELETE /v1/cowork/key
проходит как аварийный выход, ровно как и DELETE /v1/infra/servers/{id}/lock выше.
Полный состав исключений платформенного гейта приходит в writeRestriction.exceptions
ответа GET /v1/me — сверяйтесь с ним, а не с этим абзацем.
Три эффекта такого ключа теперь видны порталу, и это цена решения. Первая выкладка сервера с публичным субдоменом заводит карточку приложения в каталоге портала, а её видят все сотрудники — иконка меняет картинку той же карточки. И выкладка на спящий сервер поднимает машину сама, то есть начинает расходовать баланс Вайбкод. Отдельный вызов пробуждения при этом остался запрещён: разбудить сервер, ничего на него не выкладывая, таким ключом нельзя.
И третье, самое важное для того, кто выдаёт ключи: режим «только чтение» перестал быть
границей для владельца сервера. Выкладка и exec исполняют код в контейнере, где лежат
выданные платформой креденшлы приложения — персональный API-ключ приложения (он в режиме
«чтение и запись») и токены приложения к порталу. Прочитав окружение, держатель ключа
«только чтение» получает право писать данные Битрикс24. Это принятая цена решения, а не
недосмотр: ручка сама данные портала не пишет, но даёт доступ к тем, кто пишет.
Список исключений центрального ограничения приходит в ответе
GET /v1/me полем writeRestriction.exceptions, а доступность операции —
блоком capabilities. Слот capabilities.servers.deploy под ключом «только чтение» больше не
приходит с available: false.
⚠️ Изменилась и форма одного соседнего ответа. GET /v1/infra/servers/{id}/logs на спящем
галактик-приложении отдаёт 200 с блоком recovery, и поле recovery.recoveryAction стало
УСЛОВНЫМ: оно отсутствует всякий раз, когда вызывающий пробуждение позвать не может. ⚠️ Список
условий НЕ закрыт — ветвитесь по НАЛИЧИЮ поля, а не по перечню. ⚠️ Обратное не гарантировано:
наличие поля означает лишь, что вызывающему не отказано по identity и режиму ключа; биллинг и
административный запрет пробуждения — отдельные оси, и названный адрес может ответить 402
или 403. Сегодня в него входят: режим
«только чтение», ключ Коворка/Кода, выключённый на аккаунте пилот галактик, ключ обслуживания
агента (чтение логов ему открыто, пробуждение — нет) и владелец, у которого идёт удаление
аккаунта; плюс доступ к приложению по связи, когда сервером владеет другой ключ.
Раньше поле приходило всегда и называло адрес пробуждения, который такому ключу отвечал 403.
Пустую строку вместо адреса не отдаём намеренно: машина попыталась бы её исполнить, а
отсутствие ключа читается как «пробуждения тут нет, смотри соседние поля».
Условным стало и третье поле того же блока — recovery.poll, адрес опроса готовности. Он
пропадает, когда GET /v1/infra/servers/{id} отказывает самому вызывающему: у ключа
обслуживания агента этого маршрута нет в перечне, а у владельца с идущим удалением аккаунта он
живёт в замороженном контуре, в отличие от чтения журнала. В этом состоянии подсказка велит
просто перечитать журнал позже.
В том же состоянии поле recovery.wakeSchedule стало вердиктом про ВЫЗЫВАЮЩЕГО, а не только
про приложение: оно приходит available: false, как правило с кодом той двери, которая отбила пробуждение
(WRITE_BLOCKED_READONLY_KEY, INFRA_FORBIDDEN_FOR_COWORK_KEY, GALAXY_DISABLED,
AGENT_MAINTENANCE_KEY_OUT_OF_SCOPE, user_self_deletion_pending, NOT_FOUND — набор
открыт, неизвестный код обрабатывайте как отказ). Прежде
поле судило одну пригодность приложения и могло прийти available: true рядом с подсказкой
«окно вам тоже откажут» — клиент, ветвящийся по нему, шёл в гарантированный 403. Создание
окна — та же запись, и отбивают её в основном те же двери, что и пробуждение. Исключение — дверь окна,
которая проверяется раньше двери пробуждения: тогда code и текст hint называют эту дверь окна.
⚠️ Но НЕ только они, и «кто может будить — у того ничего не изменилось» неверно: у окна есть
ДВЕ СВОИ двери, и каждая отвечает СВОИМ кодом. Первая: маршрут создания окна может быть вне
перечня, разрешённого вашему ключу, тогда как само пробуждение внутри него — так устроен ключ
внешнего участника; код EXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE. Вторая: маршруту окна нужен
скоуп vibe:infra, которого чтение логов и пробуждение НЕ требуют, поэтому до этого отказа
доходит и обычный ключ владельца без скоупа; код INFRA_SCOPE_REQUIRED, и лечится он выдачей
скоупа, а не сменой режима ключа. Любая из двух даёт available: false ДАЖЕ тому, кому
пробуждение разрешено, и адрес окна тогда не называется ни в одном поле ответа. Ветвитесь по
available, а не по тому, доступно ли вам пробуждение.
Появилось новое условное поле recovery.deliveryWakesHost — второй путь подъёма. Приходит,
когда пробуждение вызывающему недоступно, а деплой при этом доступен, и несёт action
(вызов деплоя) и cost (его цену словами). Основание: ключу «только чтение» деплой на свой
сервер РАЗРЕШЁН этим же изменением, а деплой на спящее галактик-приложение поднимает хост сам —
значит для него «поднять нечем» было бы неправдой. Цена названа рядом с адресом намеренно: это
выкладка кода и расход баланса, а не пробуждение, и звать её ради одного лишь чтения журнала
не надо.
⚠️ Поле условно ВДВОЙНЕ, и это важно для клиента: послабление снимает у деплоя гейт РЕЖИМА и
только его. Ключу Коворка/Кода, порталу с выключенным пилотом галактик и ключу обслуживания
агента POST …/deploy отказывают те же двери, что и пробуждению, — им поле не приходит вовсе.
Проверяйте его наличие, а не предполагайте: нет поля — открытого пути нет.
Вместе с полями в этом состоянии изменился и ТЕКСТ ответа. Проза hint и recovery.reason
больше не называют ни адрес пробуждения, ни создание окна по расписанию. Вместо адреса hint
называет РОВНО ТО условие, которое сработало у этого вызывающего (а не список через «или»),
и второй путь подъёма вместе с ценой. Вызывающему, который пробуждение позвать может, текст и
состав полей не изменились — кроме случаев, когда создание окна ему закрыто отдельно.
Тогда recovery.wakeSchedule приходит available: false с кодом той двери, а адрес окна не
называется ни одним полем. Таких дверей две, и обе не совпадают с дверями пробуждения:
маршрут окна вне перечня, разрешённого ключу (так устроен ключ внешнего участника —
пробуждение ему открыто, окно нет) — EXTERNAL_COLLABORATOR_KEY_OUT_OF_SCOPE; и отсутствие у
ключа скоупа vibe:infra, который проверяется ПЕРВОЙ строкой обработчика окна, тогда как
чтение логов и пробуждение его не требуют, — INFRA_SCOPE_REQUIRED. Код приходит от той
двери, которая сработала у вас, а не от соседней: перечень маршрутов проверяется раньше всех
прочих дверей, а скоуп — позже дверей режима, заморозки, Коворка и пилота, но РАНЬШЕ проверки
владения сервером. Поэтому вызывающему, который пришёл по связи приложения и при этом не несёт
vibe:infra, придёт INFRA_SCOPE_REQUIRED, а не NOT_FOUND.
Что делать интеграторам
Читать recovery.recoveryAction в ответе логов только после проверки, что ключ есть: без
проверки клиент разыменует отсутствующее поле и уйдёт либо в исключение, либо в запрос по
адресу undefined.
Не вытаскивать адрес пробуждения из hint регулярным выражением: в этом состоянии его там
нет, и выражение вернёт пустой результат, а не отказ.
Не ветвиться по recovery.wakeSchedule.available, считая его вердиктом про приложение: теперь
он учитывает и право вызывающего, и у отбитого приходит false там, где раньше приходил
true. Клиент, который на true создавал окно, отказа больше не получит — он его и не
запросит.
Проверять НАЛИЧИЕ recovery.deliveryWakesHost, а не предполагать его: поле приходит только
тем, кому деплой действительно доступен. И прежде чем звать action, прочитать соседний cost:
вызов выкладывает код и тратит баланс. Как способ «просто разбудить, чтобы прочитать журнал» он
не годится.
Проверять НАЛИЧИЕ recovery.poll — третьего условного поля того же блока. Адрес опроса
готовности пропадает, когда GET /v1/infra/servers/{id} отказывает самому вызывающему: у ключа
обслуживания агента этого маршрута нет в перечне, а у владельца с идущим удалением аккаунта он
живёт в замороженном контуре. Клиент, написанный по прежнему контракту, где поле приходило
всегда, разыменует отсутствующее поле и уйдёт либо в исключение, либо в опрос адреса
undefined. В этом состоянии готовность не опрашивают вовсе — подсказка велит перечитать
журнал позже.
Клиенту, который вызывает эти ручки, менять нечего — отказ просто перестал приходить.
Действие требуется администратору портала, который выдавал ключи «только чтение» именно потому, что такой ключ не мог выкладывать код. Проверьте, кому выданы такие ключи. Режим доступа для этой цели больше не подходит: он ограничивает данные Битрикс24, а не доставку.
Важно: снятие права vibe:infra доставку НЕ закрывает — оно проверяется только на создании
сервера и на окнах пробуждения. Доступ к доставке даёт любая из трёх веток: сервер заведён
этим ключом; сервер привязан к приложению, у которого этот ключ основной; владелец ключа
состоит в команде разработки сервера с правом на код.
Из-за этого надёжный рычаг один — отозвать ключ. Перепривязка сервера к другому ключу доставку НЕ закрывает: она меняет владельца сервера, но не трогает ни привязку приложения, ни членство в команде разработки, поэтому прежний ключ продолжит выкладывать код через эти две ветки.
FIX-0915-17: адрес переключателя режима для ключа авторизации приложения учитывает, где живёт карточка приложения
Было
Отказ по режиму доступа WRITE_BLOCKED_READONLY_KEY для ключа авторизации приложения
(vibe_app_*) всегда отдавал в details.switchUrl кабинет приложений "/applications". Но
карточка есть там не у каждого приложения: у приложения, не заведённого в разделе
«Приложения», её там нет, и держатель такого ключа попадал на страницу без переключателя.
Стало
Для ключа авторизации приложения details.switchUrl указывает на страницу, где лежит
карточка именно этого приложения: кабинет приложений "/applications", если приложение
заведено в этом разделе, иначе раздел ключей авторизации "/apps". Там карточка открывается
из меню строки, пункт «Информация», и блок Режим доступа стоит в ней сразу под ключом.
Для личного ключа ("/keys") и менеджмент-ключа ("/management-keys") адрес не изменился.
Текст сообщения по-прежнему называет тот же адрес, что и поле, а код отказа и сам ответ
остаются прежними — изменилось только значение switchUrl.
Влияние на интеграторов
Клиент, который читает switchUrl из ответа, ничего менять не должен. Подробности — на
страницах Режим доступа и
Ошибки авторизации.
NEW-0915-18: открытые линии: чаты по карточке CRM и подключение оператора к диалогу
Добавлены три эндпоинта, все требуют скоуп imopenlines и работают на любом портале.
GET /v1/openlines/crm/chats?crmEntityType=lead|deal|company|contact&crmEntityId=N отдаёт чаты открытой линии, привязанные к объекту CRM: { "success": true, "data": [ { "chatId": 2043, "connectorId": "telegrambot", "connectorTitle": "Telegram" } ] }. Необязательный activeOnly=false добавляет к открытым диалогам завершённые. У объекта без диалогов data пустой. Значение crmEntityType вне списка отбивается ответом 400 INVALID_PARAMS до вызова Битрикс24.
POST /v1/openlines/sessions/intercept с телом { "chatId": 2043 } переводит диалог на текущего оператора и отвечает { "success": true, "data": { "chatId": 2043, "intercepted": true } }. POST /v1/openlines/sessions/join с тем же телом добавляет оператора в диалог ещё одним участником и отвечает { "success": true, "data": { "chatId": 2043, "joined": true } }. Оба принимают chatId числом и строкой формы chat2043, оба пишут в живой диалог с клиентом и потому недоступны ключу «только чтение» — он получает 403 WRITE_BLOCKED_READONLY_KEY.
Прежде найти диалог открытой линии по карточке лида, сделки, компании или контакта было нечем, а из операторских действий API давал только POST /v1/openlines/operator/answer и POST /v1/openlines/operator/finish. Прежние запросы работают как работали.
Документация — Чаты по карточке CRM.