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

[← Журнал изменений](/docs/changelog) · [Сентябрь 2026](/docs/changelog/2026-09)

### FIX-0901-1: отказ по правам на доске спринта приходит как 403, а не как ошибка платформы

**Было**

Ключ, у пользователя которого нет доступа к скрам-проекту, получал на колонки доски спринта ответ `422 BITRIX_ERROR` — тот же класс, которым платформа Вайбкод сообщает о бизнес-ошибке Битрикс24. Отличить «нет прав» от «что-то временно не так на портале» по коду было нельзя, и запрос повторяли, хотя состояние стабильное и повтор ничего не меняет.

```
HTTP 422
{ "success": false, "error": { "code": "BITRIX_ERROR", "message": "Access denied", "b24Code": "0" } }
```

**Стало**

`GET /v1/scrum/sprints/{sprintId}/stages` и `POST /v1/scrum/sprints/{sprintId}/stages` отвечают на отказ по правам кодом `403 BITRIX_ACCESS_DENIED` — тем же, что описан в общем справочнике ошибок. Это сигнал «не повторять, а выдать пользователю доступ к скрам-проекту».

```
HTTP 403
{ "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } }
```

Успешные ответы не меняются: список колонок по-прежнему приходит с HTTP 200, созданная колонка — с HTTP 201. Не меняется и ответ на несуществующий спринт: он остаётся `404 ENTITY_NOT_FOUND`.

### BC-0901-2: пустая фотография сотрудника отклоняется при обновлении

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

**Было**

При UPDATE сотрудника пустая строка или строка только из пробельных символов в `personalPhoto` доходила до Битрикс24 как команда снять текущую фотографию. Одиночный `PATCH /v1/users/:id` возвращал `200 success:true`, хотя фотография удалялась.

**Стало**

Такие значения отклоняются до вызова Битрикс24 с `INVALID_PARAMS`. Одиночный `PATCH /v1/users/:id` возвращает `400 success:false`; пакетные маршруты сохраняют свои конверты ошибок. На глобальном `POST /v1/batch` так же отклоняется `personalPhoto: null`: кодировщик подзапроса превращает `null` в пустое значение строки запроса, то есть в ту же команду снять фотографию. На `PATCH /v1/users/:id` и в пакете по сущности `null` нового отказа не получает. Чтобы оставить фотографию без изменений, не передавайте `personalPhoto`. На CREATE в `POST /v1/users` пустая строка не получает новый отказ; рабочая inline-пара и отдельная проверка приглашения сотрудника не изменились.

### FIX-0901-3: описания лимита частоты называют долю процесса, а не только общий кап

**Было**

Описания [POST /v1/feedback](/docs/feedback/submit) в путеводителе `GET /v1/guide`, в блоке `feedback.limits` ответа [GET /v1/me](/docs/keys-auth) и в схеме `GET /v1/openapi.json` называли лимит числом — «5 запросов в минуту». Запросы обслуживает несколько процессов платформы, каждый держит свою долю лимита, поэтому клиенту приходило меньше обещанного, и заголовок `X-RateLimit-Limit` расходился с описанием. То же расхождение было на страницах справки по отправке обращения и загрузке вложения, а в схеме — у пяти операций раздела Коворк.

**Стало**

Описания называют число и рядом поясняют, что предел делится между процессами платформы, а действующее значение приходит в заголовке `X-RateLimit-Limit`. У операций Коворк в схеме описание отказа `429` приведено к той же форме, что уже стоит на страницах справки. Одна общая строка `429` на странице обращений разделена на две — у создания обращения и у загрузки вложения счётчики разные.

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

Значения лимитов не менялись, поведение прежнее. Клиент, который закладывал число из описания, получал отказ раньше ожидаемого — теперь источник действующего значения назван явно: читайте `X-RateLimit-Limit` из ответа.

### BC-0901-4: обновление комментария задачи отклоняет поля только для чтения

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

**Было**

На старой карточке
[PATCH /v1/tasks/:taskId/comments/:id](/docs/entities/task-comments/update),
которому клиент возвращал объект комментария из GET с изменённым `message`, мог
ответить HTTP 200 и передать в Битрикс24 поля только для чтения. Элемент
[POST /v1/tasks/:taskId/comments/batch](/docs/entities/task-comments/comments-batch)
мог аналогично завершиться с `success:true`.

**Стало**

Single PATCH с полем только для чтения возвращает HTTP 400
`READONLY_FIELD` до обращения к Битрикс24. Для успешного обновления комментария
старой карточки запросом только с `{message}` статус ответа остаётся HTTP 200;
на новой карточке сохраняется `410 GONE`.

В custom batch верхний ответ остаётся HTTP 200 с `success:true`, а запрещённый
элемент получает `success:false` и `error:READONLY_FIELD`, не отправляется в
Битрикс24 и не мешает выполнению валидных соседних элементов.

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

Для single PATCH формируйте новое тело только с `{message}` и не отправляйте
обратно поля ответа `id`, `taskId`, `authorId`, `createdAt` или их aliases. В
custom batch оставьте lowercase `id` селектором комментария и передавайте рядом
только `message`: удалите дополнительный `ID` и остальные поля только для
чтения. Клиентам, которые уже отправляют только документированные writable-поля,
ничего менять не нужно.

### FIX-0901-5: ошибка 401 TOKEN_MISSING называет причину на всех маршрутах V1

**Было**

Причину, по которой у личного ключа нет вебхука Битрикс24, ответ называл только на
маршрутах сущностей (`/v1/deals`, `/v1/tasks` и т. п.) и в [POST /v1/batch](/docs/batch).
Остальные семейства — чаты, списки, почта, скрам, заметки, открытые линии, боты,
пользовательские поля и прочие — отвечали плоским текстом «API key has no tokens
configured.» без поля `error.details`. Один и тот же сломанный ключ на `/v1/deals`
получал объяснение, а на `/v1/chats` — текст, из которого не следовало ничего.

**Стало**

Ответ `401 TOKEN_MISSING` устроен одинаково на всех маршрутах V1: личный ключ получает
причину в `error.details.reason` и текст с нужным действием, ключ приложения — указание
на недостающий OAuth-шаг. Ответ остаётся HTTP 401, набор кодов не менялся.

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

Разбирайте `error.details.reason` — контрактом является он, а не `error.message`.
Текст сообщения на этих маршрутах изменился, и код, сравнивающий его со строкой
«API key has no tokens configured.», перестанет попадать; такой разбор был ненадёжен и
раньше. Причины перечислены в ответе `GET /v1/me` в блоке `b24Credentials`.

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

**Было**

После успешного [DELETE /v1/storage/objects/{key}](/docs/storage/objects/delete) новая [прямая загрузка POST /v1/storage/objects/upload](/docs/storage/upload/direct) с тем же ключом отвечала `409 STORAGE_KEY_DELETED` до физической уборки объекта через 30 дней.

**Стало**

Для объекта приложения в состоянии `COMPLETED` без multipart-сессии прямая загрузка отвечает HTTP 200, сохраняет те же `id` и `visibility` и записывает новое содержимое. Удалённая публичная ссылка с этим `id` снова становится доступна с новыми байтами. Это не восстановление прежнего содержимого.

Путь B остаётся отключённым и отвечает `503 STORAGE_PRESIGNED_UPLOAD_DISABLED` без URL. Путь C, удалённые объекты `PENDING` и объекты с multipart-сессией по-прежнему отвечают `409 STORAGE_KEY_DELETED`. Сам DELETE и последующее чтение без новой подходящей прямой загрузки по-прежнему дают `410 STORAGE_OBJECT_DELETED` в течение периода хранения.

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

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

### FIX-0901-7: временный отказ склада образов больше не помечает galaxy-приложение сломанным

**Было**

`POST /v1/infra/servers` с полем `source`, упёршийся в `502 GALAXY_BASE_IMAGE_UNAVAILABLE` или в нехватку места на хосте, переводил слот в `status=error` — при том что тот же отказ на `POST /v1/infra/servers/:id/deploy` статус не трогал, а текст ошибки обещал, что слот, контейнер и том `/data` целы. Повтор деплоя `error` не снимал: `GET` продолжал отдавать сломанный слот, и приложение переставало удерживать свой хост от засыпания.

**Стало**

Оба временных отказа оставляют слот в `status=provisioning`; причина по-прежнему видна в `provisionError` ответа `GET /v1/infra/servers/:id`. Повтор того же деплоя на слоте, сломанном такой причиной, снимает `error` в начале попытки. Если слот бросить, платформа через ~20 минут всё равно завершит его ошибкой, но сохранит настоящую причину вместо общей `DEPLOY_INCOMPLETE`. Подсказки в `error.hint`, чеклист в `/v1/me` и документация больше не называют срок «2–3 минуты»: окно недоступности склада бывает и часовым.

### BC-0901-8: Обычный чат-бот блокирует удаление ключа

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

**Было**

Удаление API-ключа могло удалить привязанного обычного чат-бота вместе с токеном, нужным для штатного снятия регистрации на портале.

**Стало**

Удаление ключа с обычным чат-ботом, включая отключённую строку Bot Platform, возвращает `409 KEY_HAS_LINKED_AGENT`. Возьмите числовой `bitrixBotId` из `details.bots` ответа `409`, затем снимите регистрацию через `DELETE /v1/bots/:botId` или перенесите бота на другой ключ.

### FIX-0901-9: загрузка файлов и AI-запросы получили отказ 429 при перегрузке памяти

**Было**

`POST /v1/files/upload` (до 70 МБ), `POST /v1/note/documents/{id}/files` (до 40 МБ),
`POST /v1/chat/completions` (до 30 МБ) и `POST /v1/audio/transcriptions` (аудио до 25 МБ)
принимали любое число одновременных крупных тел. При нескольких параллельных загрузках
предельного размера запросы могли обрываться без ответа — в том числе чужие, идущие в этот
момент.

Ещё одно наблюдаемое отличие: запрос без ключа или с неверным ключом на этих маршрутах мог
получить `400` (неразобранный JSON), `413` (размер) или `415` (тип данных) — то есть ответ о
теле раньше ответа о ключе.

**Стало**

Одновременные тела крупнее 1 МиБ ограничены общим объёмом. Запрос сверх лимита получает `429`
с кодом `LARGE_BODY_BACKEND_BUSY` и заголовком `Retry-After: 5` — до обращения к Bitrix24, то
есть без побочных эффектов, и одинаково независимо от того, объявлен ли `Content-Length`:

```json
{
  "success": false,
  "error": {
    "code": "LARGE_BODY_BACKEND_BUSY",
    "message": "Too many large request bodies are being processed. Retry in a few seconds.",
    "retryAfter": 5
  }
}
```

На OpenAI-совместимых `POST /v1/chat/completions`, `POST /v1/ai/chat/completions` и
`POST /v1/audio/transcriptions` (+ `POST /v1/ai/audio/transcriptions`) конверт — как у остальных
ответов этой поверхности, то есть без `success` и с кодом в нижнем регистре:

```json
{
  "error": {
    "message": "Too many large request bodies are being processed. Retry in a few seconds.",
    "type": "rate_limit_exceeded",
    "code": "large_body_backend_busy",
    "retryAfter": 5
  }
}
```

Запрос без ключа или с неверным ключом теперь получает `401` на всех этих маршрутах — проверка
ключа идёт до чтения тела. Успешные запросы и тела до 1 МиБ не затронуты; повтор через 5 секунд
проходит штатно.

⚠️ На транскрипциях лимит считается по объявленному `Content-Length`. Загрузка без него
(`Transfer-Encoding: chunked`) в общий объём не попадает и ограничена только собственным
потолком в 25 МБ на файл.

### FIX-0901-10: создание Hermes-агента больше не падает из-за размера стартового пакета

**Было**

Создание Hermes-агента завершалось ошибкой сразу после шага выдачи сервера. Виртуальная машина
не создавалась вовсе, агент оставался в состоянии ошибки с кодом инцидента, а поле сервера
в карточке оставалось пустым. Повторные попытки давали тот же результат. Причина — стартовый
пакет для облака вырос и перестал помещаться в предел, который облако отводит на такие пакеты.

**Стало**

Служебные комментарии больше не уезжают в облако вместе с установочным скриптом, поэтому
стартовый пакет снова помещается в предел с большим запасом, и виртуальная машина создаётся.
Сам установочный скрипт и все прочие способы его доставки не изменились. Дополнительно перед
обращением к облаку добавлена проверка размера: если пакет когда-нибудь снова вырастет сверх
предела, запрос в облако не отправляется вовсе, а Вайбкод возвращает привычную ошибку
провайдера с кодом инцидента.

### NEW-0901-11: редактор бизнес-процессов доступен через API

Появился раздел `/v1/workflow-designer/*` — работа с шаблонами нового редактора бизнес-процессов на языке самого редактора: блоки, связи, каталог типов блоков, проверка графа, черновики и публикация. Это не то же самое, что `/v1/bizproc-templates`: тот раздел читает и пишет строки шаблонов, где граф лежит непрозрачным блоком.

Требуется scope `bizprocdesigner` — отдельный от `bizproc`. Добавьте его в ключ и перевыпустите ключ.

Запись идёт двумя шагами. `POST /v1/workflow-designer/templates/{id}/draft` сохраняет **черновик**: работающий бизнес-процесс продолжает выполняться по опубликованной версии, и черновик можно показать человеку, переписать или бросить. `POST /v1/workflow-designer/templates/{id}/publish` делает черновик рабочей версией — необратимо, и вместе с публикацией удаляются **все** черновики шаблона, включая чужие. Публикация требует `draftFingerprint` из `GET /v1/workflow-designer/templates/{id}`: так публикуется ровно тот граф, который вы прочитали и показали человеку, а переписанный кем-то черновик отбивается вместо тихой подмены.

Начинать работу стоит с `GET /v1/workflow-designer/capabilities`: он отвечает, доступен ли редактор этому порталу и этому ключу, а если нет — называет причину (`DESIGNER_NOT_SUPPORTED` — портал ещё не обновлён до версии, отдающей редактор через API, либо модуля нет, `DESIGNER_UNAVAILABLE` — редактор выключен или не входит в тариф, `SCOPE_DENIED` — у ключа нет scope, `DESIGNER_REQUIRES_WRITE_KEY` — ключ только на чтение, а операция пишет, `DESIGNER_PROBE_FAILED` — проверка не завершилась и состояние редактора неизвестно). Различить эти состояния по отказу самих методов нельзя, поэтому проверка вынесена в отдельный вызов.

Ключ только на чтение раздел обслуживает: граф, каталог блоков, поля документа, инструкцию портала и `validate` читает и он. `DESIGNER_REQUIRES_WRITE_KEY` приходит только на трёх пишущих операциях — создание шаблона, сохранение черновика и публикация.

**Затронутые эндпоинты:** `GET /v1/workflow-designer/capabilities`, `POST /v1/workflow-designer/templates`, `GET /v1/workflow-designer/templates/{id}`, `GET /v1/workflow-designer/templates/{id}/brief`, `GET /v1/workflow-designer/templates/{id}/blocks`, `GET /v1/workflow-designer/templates/{id}/blocks/{blockId}`, `GET /v1/workflow-designer/templates/{id}/document-fields`, `POST /v1/workflow-designer/templates/{id}/validate`, `POST /v1/workflow-designer/templates/{id}/draft`, `POST /v1/workflow-designer/templates/{id}/publish`

### BC-0901-12: удаление сервера удаляет и привязанного к нему агента

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

**Было**

[DELETE /v1/infra/servers/:id](/docs/infra/servers/delete) удалял только сервер. Агент, который на нём работал, оставался в платформе Вайбкод как живой: его состояние по-прежнему читалось «работает», бот оставался зарегистрированным на портале Битрикс24, ключ агента — действующим, а ссылка агента вела на сервер, которого уже нет.

**Стало**

Вместе с сервером удаляется и привязанный к нему агент. Запись агента помечается удалённой, бот снимается с портала Битрикс24, ключ агента отзывается, карточка приложения снимается с каталога Битрикс24. Успешное удаление отвечает прежним HTTP 200 с телом `{"success": true}`.

Появился один новый исход. Если в момент вызова того же агента параллельно менял другой запрос, ответ — `409 AGENT_DELETE_CONFLICT` в обычной форме отказа `{"success": false, "error": {"code": "...", "message": "..."}}`. Тогда не удалён и сам сервер: он продолжает работать и тарифицироваться, а запрос нужно повторить.

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

Сценарий, который рассчитывал пережить удаление сервера и переиспользовать агента, надо перестроить: агент создаётся заново после создания нового сервера. Код `AGENT_DELETE_CONFLICT` обрабатывается как повторяемый — сервер цел, повторите тот же запрос. Удаление сервера без агента и удаление сервера вида `GALAXY_APP` работают как раньше.
