# Изменения API: 13 августа 2026

[← Журнал изменений](/docs/changelog) · [Август 2026](/docs/changelog/2026-08)

### FIX-0813-1: отказ сборки нативного модуля называется своей причиной, а не «не найден Python»

**Было**

Приложение на Node с зависимостью, которая содержит машинный код (например `better-sqlite3`),
разворачивалось через раз. Такие зависимости ставятся в два хода: сначала скачивается уже
собранный файл, а если не вышло — модуль собирается из исходников на месте. Когда скачивание
срывалось из-за внешней сети, начинался второй ход и падал — в образе приложения нет инструментов
сборки. В ответе на деплой и на карточке приложения оказывалась последняя строка этого второго
хода, `Could not find any Python installation to use`, и она уводила от настоящей причины: клиент
искал ошибку в своём коде и в версии Python, хотя ни то, ни другое сломано не было. Категория
отказа приходила общая — `INSTALL_FAILED`, с подсказкой про нехватку компилятора.

**Стало**

У такого отказа своя категория — `NATIVE_PREBUILD_UNAVAILABLE`, она приходит в поле `category`
ответа 502 `GALAXY_APP_BUILD_FAILED` и в `buildHint` карточки приложения. Текст подсказки говорит
то, что есть: готовую сборку не удалось скачать, внешний источник не ответил, это временно,
повторите развёртывание через несколько минут. Категория ставится, только когда обе улики в логе
сборки совпали — скачивание сорвалось по сети И собрать из исходников оказалось нечем; отказы,
которые повтор не лечит (для этой платформы готовых сборок не публикуют, на хосте кончилось
место), в неё не попадают и сохраняют прежний текст. Повторяет деплой клиент — платформа сборку
сама не пересылает.

### FIX-0813-2: Формы ответов методов API описаны в машинной схеме

**Было**

Машинная схема не показывала фактические формы ответов для [POST /v1/duplicates/find](/docs/duplicates) и [GET /v1/lists/{iblockId}/elements](/docs/lists/elements). Это затрудняло обработку результата поиска дублей и Bitrix24-native полей элементов списков.

**Стало**

Схема описывает для поиска дублей объект с ключами типов сущностей или пустой массив, а для элементов списков — массив в конверте с динамическими ключами свойств и счётчиком `meta.total`, не меняя фактический ответ API.

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

Интеграции могут использовать машинную схему для выбора формы ответа. Для элементов списков учитывайте, что параметр `limit` игнорируется.

### NEW-0813-3: настоящее состояние спящего galaxy-приложения в ответе GET сервера и в ответе логов

`GET /v1/infra/servers/:id` для galaxy-приложения теперь отдаёт блок `reachability`, который отвечает на вопрос «может ли приложение ответить прямо сейчас». Поле `status` не изменилось — это состояние учётной записи приложения, и во время пробуждения оно отстаёт от машины: запись остаётся в `sleeping`, пока платформа поднимает галактику, а на холодной машине это занимает минуты. Рядом с ним `reachability` несёт сводный `effectiveStatus`, состояние галактики-носителя `hostStatus` и `hostTunnel`, живо снятые `container` и `forwarder`, исход опроса `probe` и его время `probedAt`. Опрос идёт только по работающей галактике, спящую он не будит, поэтому у спящей галактики `container` и `forwarder` приходят как `unknown`. У серверов остальных типов блок равен `null`.

Ответ `GET /v1/infra/servers/:id/logs` для приложения на спящей галактике дополнен полем `recovery` и называет рабочий путь: вызов пробуждения, признак `logsPreserved` (пробуждение запускает тот же контейнер, поэтому строки, записанные до сна, остаются в журнале), бюджет подъёма холодной галактики в секундах, чем проверять готовность и доступно ли этому приложению окно пробуждения по расписанию. Поле `hint` осталось строкой и теперь тоже называет вызов пробуждения.

Разбор состояний и порядок действий — [Сон и пробуждение Galaxy-приложения](/docs/infra/galaxy-sleep).

### FIX-0813-4: скачивание файла объявляет требуемый скоуп в openapi.json

**Было**

У операции `GET /v1/files/{fileId}/download` в машинной спецификации не было поля `x-required-scope`, хотя рантайм отвечает `403 SCOPE_DENIED` без скоупа. Клиент или агент, собиравший ключ по спецификации, видел «скоуп не нужен» и получал отказ на первом же вызове. Эта же операция попадала в любой срез `openapi.json?scope=`, включая срезы других модулей.

**Стало**

Операция объявляет `x-required-scope: disk` — основной скоуп. Обработчик принимает и `crm`: ключ только с ним скачивает файл, прикреплённый к пользовательскому полю карточки CRM. Второй скоуп объявлен новым необязательным полем `x-alternative-scopes` рядом с основным. В срезах операция остаётся при `openapi.json?scope=disk` и `?scope=crm`, в остальных её больше нет.

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

Клиент, читающий только `x-required-scope`, запросит `disk` и продолжит работать как раньше. Клиенту с ключом на одном `crm` теперь видно из спецификации и со страницы операции, что вызов ему доступен: раньше об этом сообщали только текст отказа и самоописание ключа в `/v1/me`.

### FIX-0813-5: Понятный текст ошибки сборки вместо машинного вывода и внешних адресов

**Было**

Когда сборка приложения падала из-за недоступности хранилища базовых образов, в `provisionError` и в ответе 502 приходил дословный вывод сборщика: имя внешнего хранилища, путь запроса и публичный IP-адрес. Для остальных отказов сборки в тексте тоже могли оказаться внешние ссылки и публичные IP-адреса.

**Стало**

Недоступность хранилища образов описывается фиксированной фразой: причина и действие — повторить тот же деплой через несколько минут, слот и данные не тронуты. Категория отказа (`provisionErrorCategory`) и признак повторяемости не изменились. Во всех прочих отказах сборки причина по-прежнему передаётся как есть, но внешние адреса в ней заменяются на пометки — и ссылки целиком, и имя хранилища образов без схемы, когда строка сама говорит про образ, и адрес, названный вообще без пути в строке сетевого отказа (`getaddrinfo ENOTFOUND …`, «не удалось разрешить имя хоста»), и публичные IP-адреса. Адреса самой платформы, локальные и внутренние остаются видны, как и имя образа с версией, имена файлов и имена пакетов: пометка ставится там, где текст сам называет адрес адресом, — поэтому имя пакета вида `socket.io` остаётся читаемым, хотя по форме не отличается от имени хранилища. Одно исключение: числовой ряд из четырёх частей (`11.0.16.1`) неотличим от IP-адреса, поэтому версия такого вида тоже станет пометкой.

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

Менять ничего не нужно: коды ошибок, категории и признак повторяемости те же. Клиент, который разбирал текст `provisionError` по подстрокам, для этого класса отказа получит стабильную фразу вместо изменчивого вывода сборщика, а полный лог сборки по-прежнему доступен в поле `buildLog` того же ответа.

### NEW-0813-6: манифест бандла агента сообщает режим сверки рантайма

В ответ [GET /v1/agent-bundles/:kind/manifest.json](/docs/agents) добавлены два необязательных поля.

`runtime_integrity` принимает значение `"on"` или `"off"` и говорит агенту, сверять ли файлы своего окружения с контрольными суммами, записанными при установке. Агент выполняет сверку только при значении `"on"`; отсутствие поля означает, что она выключена.

`runtime_integrity_budget` — целое число, которое платформа сейчас всегда присылает равным единице. Агент читает его как разрешение: больше нуля — восстановление допускается, ноль — запрещено. Частоту попыток ограничивает сам агент, не чаще одной в час, поэтому значения больше единицы поведение не меняют. Режимом восстановления управляет не это поле, а настройка платформы; поле нужно, чтобы агент без него по умолчанию ничего не восстанавливал.

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

### NEW-0813-7: манифест бандла агента получил операцию точечного ремонта рантайма

В ответе [GET /v1/agent-bundles/:kind/manifest.json](/docs/agents) в объекте `operations` появился ключ `repair_runtime`.

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

Поле `available_to` у неё содержит единственное значение `admin`: операция редкая и запускается вручную, поэтому вызов от имени регулярных заданий отклоняется с ошибкой `OPERATION_FORBIDDEN`. Успехом считается не только нулевой код возврата, но и подтверждение от агента, что окружение сошлось; иначе операция отвечает `status: "failed"` с причиной в поле `error`.

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

### FIX-0813-8: Отказ reauth больше не советует OAuth ключам без OAuth

**Было**

[POST /v1/bots/{botId}/reauth](/docs/bots/management/reauth) на мёртвых кредах всегда отвечал `410 REAUTH_REQUIRED` с одним и тем же советом — перезапустить авторизацию через `POST /v1/oauth/authorize` либо пересоздать личный ключ. Ключу, который ходит в Битрикс24 через входящий вебхук, этот совет выполнить нечем: ни потока авторизации, ни токена обновления у него нет. Владелец такого ключа читал инструкцию и упирался в тупик.

**Стало**

Текст отказа зависит от того, чем ключ авторизуется, а в `error.details` появилось поле `credentialKind` — `oauth`, `webhook` или `unknown`. Вебхучному ключу отказ называет реальную причину (вебхук мёртв, чаще всего удалён на стороне Битрикс24) и реальное лекарство — перевыпуск вебхука, при котором идентификатор и строка ключа сохраняются, а привязанные боты продолжают работать. Ключу с OAuth текст прежний.

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

Менять ничего не нужно: код ответа и его статус не изменились. Клиент, который разбирал текст отказа строкой, увидит новую формулировку у вебхучных ключей — надёжнее ветвиться по `error.details.credentialKind`.

### FIX-0813-9: удаление galaxy-приложения на непробуждаемом хосте отвечает терминальным 409

**Было**

`DELETE /v1/infra/servers/{id}` для приложения на galaxy-хосте, который нельзя разбудить
(заморожен счёт либо стоит запрет пробуждения), отвечал `502 GALAXY_HOST_UNREACHABLE`
с объектом `error.hint` и советом повторить позже. Совет не срабатывал никогда: пробуждение
было не провалено, а запрещено, поэтому клиент повторял запрос до собственного таймаута.

**Стало**

Такой отказ терминален и приходит как `409 GALAXY_HOST_WAKE_BLOCKED`. В теле — поле
`error.reason` с причиной: `BILLING_FROZEN`, `ACCESS_EXPIRED`, `STOPPED` или `UNKNOWN`.
Объекта `error.hint` на этом пути больше нет — он описывал восстановление недостижимого
хоста, а восстанавливать здесь нечего; для настоящей недостижимости `502` с `hint`
сохраняется без изменений. Повторять запрос бессмысленно — нужно снять причину.

Заодно уточнён текст `409 GALAXY_HAS_APPS` при удалении самого хоста: удаление галактики
вместе с её приложениями доступно в кабинете, на публичном интерфейсе такой операции нет.

### NEW-0813-10: пробный период Маркета включается с ключа десктопа Коворк/Код

Появился эндпоинт `POST /v1/cowork/activate-market-trial`: он включает одноразовый пробный период подписки Маркета для аккаунта Битрикс24, к которому привязан ключ десктопа Коворк/Код. Раньше программный путь был только у личных ключей и ключей приложений — ключ десктопа эндпоинт `POST /v1/portals/{id}/activate-market-trial` отклонял, и этот отказ остаётся в силе.

Параметра пути нет: аккаунт берётся из привязки ключа, поэтому клиенту не нужно знать внутренний идентификатор. Тело обязательное — `{"acknowledgedOneTimeConsumption": true}`, ровно литерал `true`. Им клиент подтверждает, что показал пользователю: включается одноразовый период, который нельзя отозвать, и назвал дату окончания. Подтверждение попадает в журнал действий аккаунта.

Ответ при успехе — `{"success": true, "data": {"status": "activated", "trialEndsAt": "…"}}`; вместо `activated` может прийти `already_active` (период или подписка уже действуют) либо `pending` — включение состоялось, подтверждения от Битрикс24 ещё нет, и повторять запрос в этом случае не нужно. Срок задаёт Битрикс24, поэтому показывайте пользователю дату из `trialEndsAt`, а не своё число дней.

Отказы: `400 DISCLOSURE_REQUIRED` (нет подтверждения), `403 INSUFFICIENT_SCOPE` (у ключа нет права `vibe:cowork`), `403 COWORK_DESKTOP_KEY_REQUIRED` (ключ другого класса — например, ключ места агента с тем же правом), `403 WRITE_BLOCKED_READONLY_KEY`, `409 ALREADY_ACTIVATED`, `409 TRIAL_ACTIVATION_UNAVAILABLE`, `503 TRIAL_ACTIVATION_RETRY`. Предел частоты — 3 запроса в час на аккаунт.

Перед показом шага активации читайте `activation.marketTrial.available` в [GET /v1/cowork/state](/docs/cowork/state): это предрасчёт, `false` окончателен, а `true` разрешает предлагать, но не обещает успех — отказ на самом включении обрабатывать всё равно нужно. В регионах с тарифной моделью доступа такого пробного периода нет как продукта: предрасчёт отвечает `region_not_supported`, а сам вызов — `409 TRIAL_ACTIVATION_UNAVAILABLE`.

### FIX-0813-11: временные ошибки больше не закрывают пробный период навсегда

**Было**

У каждого аккаунта был счётчик неудачных включений пробного периода, и он доходил до потолка от ЛЮБОЙ ошибки — в том числе от той, где Битрикс24 ничего не решал: запрос до него не дошёл, он ответил внутренней ошибкой или не сложилась наша собственная авторизация. Дойдя до потолка, аккаунт получал `409 TRIAL_ACTIVATION_UNAVAILABLE` на любой следующий запрос, и вернуть его в рабочее состояние было нечем. Ответ `503 TRIAL_ACTIVATION_RETRY` при этом предлагал повторить — то есть подсказка вела ровно в ту ловушку, где серия сетевых сбоев стоила аккаунту одноразового пробного периода.

**Стало**

Счётчик расходуют только решения Битрикс24 о самом аккаунте. Ошибка транспорта, внутренняя ошибка на стороне Битрикс24 и проблема с нашей авторизацией попытку не тратят — повтор после `503 TRIAL_ACTIVATION_RETRY` теперь безопасен, как и написано в ответе.

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

Менять ничего не нужно. Повторять запрос после `503` можно так же, как и раньше, — но теперь это действительно не приближает аккаунт к отказу. `409 TRIAL_ACTIVATION_UNAVAILABLE` остаётся окончательным и означает то, что означал: решение Битрикс24 о самом аккаунте.

### FIX-0813-12: активации пробного периода снова хватает на три попытки в час

**Было**

[POST /v1/portals/{id}/activate-market-trial](/docs/activate-market-trial) обещал в описании три запроса в час на аккаунт, а на деле отдавал одну попытку: заголовок `x-ratelimit-limit` приходил со значением `1`, и второй запрос в течение часа получал `429 RATE_LIMITED` с `retry-after` около часа. У пользователя, у которого включение сорвалось из-за временной ошибки, кнопка «Повторить» оставалась бесполезной до конца часа.

**Стало**

Аккаунт получает те самые три попытки в час, как и написано в описании. Значение `x-ratelimit-limit` совпадает с обещанным, `429` приходит с четвёртого запроса.

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

Менять ничего не нужно. Если вы заложили у себя паузу в час после первого же `429`, её можно вернуть к обычной обработке заголовка `retry-after`.

### NEW-0813-13: новый код отказа доступа INT_VIBE_PLUS_REQUIRED

В справочнике кодов появился `INT_VIBE_PLUS_REQUIRED` (HTTP 402). На международном сегменте он приходит там же, где приходит `INT_TARIFF_REQUIRED` — на создании и пробуждении инфраструктуры и на выписке ключей — и означает, что аккаунту Битрикс24 нужен тариф Vibe+. Добавление аддитивное: прежние коды и форма ответа не изменились, поэтому обрабатывайте незнакомый код как отказ и ветвитесь по `error.code`, а не по тексту сообщения. Разбор кодов — в [Ошибках](/docs/errors).

### NEW-0813-14: состояние Cowork/Code отдаёт оплаченный срок

Ответ [GET /v1/cowork/state](/docs/cowork/state) получил два поля в объекте `subscription`. `termMonths` — на сколько месяцев вперёд оплачено сиденье (`1`, `3`, `6` или `12`; у помесячного — `1`). `paidThroughAt` — дата, до которой оплачено, в формате ISO 8601.

Это не то же самое, что `currentPeriodEnd`. Расчётный период — окно квоты, оно сдвигается каждые 30 дней независимо от того, на какой срок куплено сиденье. Поэтому у сиденья, оплаченного на год, `currentPeriodEnd` наступает через месяц, а `paidThroughAt` — через одиннадцать.

Заодно уточнено описание `subscription.pendingTier`: понижение тарифа применяется на `paidThroughAt`, а не на `currentPeriodEnd`. До появления сроков эти даты всегда совпадали, поэтому прежняя формулировка была верной; теперь совпадение сохраняется только у помесячных сидений. По той же дате заканчивается доступ, если подписка отменена: отмена прекращает автопродление, а оплаченный срок дослуживается целиком.

Прежние вызовы работают без изменений — оба поля добавлены, ни одно не переименовано и не удалено.

### FIX-0813-15: переименование сервера теперь видно в кабинете

**Было**

[PATCH /v1/infra/servers/:id](/docs/infra/servers/update) меняет `displayName` и `description` сервера — документация этой ручки называет их двумя текстовыми полями, которые человек видит в личном кабинете и в карточке приложения в каталоге Битрикс24, и другой ручки для них нет. Но список и карточка приложения в кабинете показывали не сервер, а копию его имени и описания, снятую в момент создания приложения. После переименования `GET /v1/infra/servers/:id` и `GET /v1/me/sources` отдавали новое значение, а кабинет — прежнее, и вернуть его к правде было нечем.

**Стало**

У приложения со связанным сервером кабинет показывает `displayName` сервера. Описание кабинет берёт своё, если его там задавали, иначе — описание сервера, а правка описания через эту ручку теперь доходит до приложения и тогда, когда у него было своё описание: последняя правка выигрывает.

Имя стало одним значением с двумя дверями: переименование приложения в кабинете меняет `displayName` сервера, а переименование сервера обновляет карточку. Заголовок карточки в каталоге Битрикс24 после любой из этих правок перевыкладывается автоматически. Имя, введённое в кабинете при создании приложения, теперь попадает и в `displayName` нового сервера, а не только в карточку.

Действий со стороны клиента не требуется. Приложения, созданные до исправления, тоже следуют за сервером: имя видно в кабинете сразу, а описание — с первой же правки через эту ручку, до неё в кабинете остаётся прежний текст.
