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

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

### BC-0823-1: OpenAPI не предлагает поля только для создания в PATCH

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

**Было**

Поля, которые API принимает только при создании записи, выглядели в `GET /v1/openapi.json` как обычные свойства тела PATCH. Сгенерированный по этой схеме клиент мог отправить их при обновлении и получить `400 READONLY_FIELD`.

**Стало**

Для сущностей с полями только для создания PATCH использует отдельную входную схему без таких полей. У остальных сущностей PATCH по-прежнему использует прежнюю входную схему. Входная схема POST в обоих случаях сохраняет контракт создания.

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

Перегенерируйте SDK по новой OpenAPI-схеме и используйте тип, на который ссылается `requestBody` конкретного PATCH. Для затронутых сущностей это `UpdateInput`, для остальных остаётся `Input`. Удалите из тела обновления поля, которые разрешены только при создании; POST по-прежнему использует `Input`.

### NEW-0823-2: совместная работа нескольких сотрудников над кодом приложения

Владелец сервера может собрать команду разработки: сотрудники портала работают с сервером
своими личными ключами, без передачи ключа владельца и без перепривязки сервера. Роль
«Разработчик» получает выкладку, команды, файлы, логи и хранилище исходников; роль
«Администратор» — дополнительно управление машиной: жизненный цикл (стоп, старт,
перезагрузка, расписание сна, починка), настройки и безопасность, тариф и диск, резервные
копии, свой домен, карточку каталога, аудиторию приложения и расходы. Состав команды,
удаление сервера, ссылки доступа и перепривязка ключа остаются за владельцем. Состав
команды правит владелец или администратор портала на вкладке «Совместная работа».

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

У выкладки участника три отличия от выкладки владельца. Переменные окружения сохраняются:
поле `env` из его запроса не применяется (в ответе приходит предупреждение), а существующие
переменные приложения переживают выкладку — в том числе у приложений в галактике, где раньше
их гасила любая выкладка. Карточка каталога Битрикс24 и анонс подписчикам остаются за
владельцем: `displayName`, `description` и рассылка `changelog` от роли «Разработчик»
игнорируются с предупреждением, а само примечание к версии сохраняется в хранилище исходников.

Плюс защита от затирания чужой работы: поле `baseVersionId` в теле
[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) («я основывался вот на этой
версии исходников», например `v12`). Если в хранилище появилась более новая версия, выкладка
отклоняется кодом `SOURCE_VERSION_STALE` с номером актуальной версии и ссылкой на её
скачивание — вместо молчаливой перезаписи.

Заявленная версия проверяется на существование: номер впереди хранилища отклоняется кодом
`BASE_VERSION_NOT_FOUND` с номером актуальной версии — иначе защиту снимал бы любой
несуществующий номер.

На сервере, где владелец собрал команду разработки, это поле обязательно, как только в
хранилище есть хотя бы одна версия: выкладка без него отвечает `BASE_VERSION_REQUIRED` и
называет актуальную версию. Так выкладка вслепую поверх чужих правок отклоняется, даже если
о защите не знали. На сервере без команды поле по-прежнему необязательно, и выкладка без него
работает как раньше. Чтобы номер версии было откуда взять, ответ операции скачивания версии
теперь несёт поле `versionId` рядом со ссылкой — [Хранилище исходного кода](/docs/source-storage).

Отказ `409 EXEC_BUSY` теперь называет занявшего сервер: в `error.hint.holder` приходят имя
сотрудника, вид операции и время её начала, а `error.hint.reason` начинается с имени. У фоновой
операции платформы человека-инициатора нет, там `holder.name` приходит пустым. Поле аддитивное —
прежние поля отказа не изменились.

Участник теперь видит сервер в API, а не только работает с ним вслепую.
[GET /v1/infra/servers](/docs/infra/servers) отдаёт и те серверы, где человек состоит в
команде разработки: такие строки несут блок `access` с полем `via: "collaborator"`, ролью,
перечнем доступных действий и списком открытых вызовов, а собственные строки ключа —
`access.via: "owner"`. `GET /v1/infra/servers/:id` отвечает участнику `200` с урезанной
карточкой (без IP, доступа по SSH и управляющего ключа; расходы и порог сна — по роли)
вместо прежнего `404`. `GET /v1/me` перечисляет членства в `infra.collaboratorServers`.
Пробуждение машины [POST /v1/infra/servers/:id/wake](/docs/infra/lifecycle/wake) открыто и
роли «Разработчик» — раньше право было объявлено матрицей, но вызов отвечал `404`. Поиск
сотрудника для настройки аудитории, [GET /v1/infra/servers/:id/b24-users](/docs/infra/access/b24-users),
открыт роли «Администратор» — раньше отвечал отказом, хотя саму аудиторию эта роль уже
настраивает.

Дополнительно: администратор команды теперь может через свой личный API-ключ выполнять все
операции сервера, разрешённые его роли, — управление жизненным циклом (остановка, запуск,
перезагрузка, сон, ручное восстановление, расписание пробуждения, метрики), настройки
(SSH-доступ, порт, подписки на события портала, переключение режима `BLACKHOLE`/`OPEN` через
[PATCH /v1/infra/servers/:id/mode](/docs/infra/access/mode)), карточку каталога
([PATCH /v1/infra/servers/:id](/docs/infra/servers/update) — имя и описание) и аудиторию доступа
(политика доступа, список пользователей и подразделений). Раньше эти операции через V1-ключ участника отвечали `403`/`404` независимо
от роли — работали только через личный кабинет. Списки членств в V1 научились отдавать
страницу: `GET /v1/infra/servers` принимает необязательные `page` и `limit` и возвращает
рядом честный `total`. Без параметров ответ прежний и полный — контракт не меняется. В
`/v1/me` блок `infra.collaboratorServers` получил поле `total`.

Удаление версий исходников остаётся за владельцем: `DELETE /v1/infra/servers/:id/sources/:versionId`
и массовая чистка `POST /v1/infra/servers/:id/sources/cleanup` отвечают участнику любой роли
`403 NOT_AUTHORIZED`. Список, скачивание, депонирование и теги ему по-прежнему открыты.

Выкладка участника, которая обязана сохранить переменные окружения, отказывается работать,
если прочитать их не удалось: вместо молчаливого выката с пустым окружением приходит
`502 GALAXY_PRESERVED_ENV_UNREADABLE` с признаком `retryable`. Приложение при этом продолжает
работать на прежней версии.

Отказ по роли отделён от «сервера нет». Управляющая операция, которой роль участника не
покрывает, отвечает `403 SERVER_ROLE_FORBIDDEN`; в `error.hint` приходят его роль,
необходимый порог, отказанное действие и перечень вызовов, которые ему открыты. Для
постороннего ключа существование сервера по-прежнему скрыто — там остаётся `404`.

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

Поле `appUrl` в [GET /v1/infra/servers](/docs/infra/servers), `GET /v1/infra/servers/:id`
и `GET /v1/me` (блок `infra.collaboratorServers`) больше не обещает участнику команды
ссылку, которую он не вправе открыть. Раньше поле возвращалось непустым, как только у
сервера был поддомен, независимо от того, разрешает ли аудитория приложения открыть его
именно этому человеку — переход по такой ссылке отвечал отказом. Теперь `appUrl` пуст,
если аудитория (`accessPolicy`) не открывает приложение всем сотрудникам портала и у
участника нет личного гранта доступа. Есть исключение: участнику, которому доступ открыт
через подразделение, ссылка пока не показывается, хотя открыть приложение он может — такому
участнику её называет владелец или администратор команды.

### FIX-0823-3: метаданные OAuth и welcome-страница указывают на публичные адреса платформы

**Было**

Метаданные OAuth (`GET /.well-known/oauth-authorization-server`) могли объявлять в `issuer` и адресах эндпоинтов `http://localhost:3000` — адрес, недоступный ни одному клиенту.

Кнопки «Документация» / «На главную» welcome-страницы `GET /v1/me` могли вести не в тот кабинет, с которого её открыли.

**Стало**

Метаданные OAuth объявляют публичный домен платформы.

Кнопки welcome-страницы ведут в кабинет той платформы, с которой страницу открыли.
