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

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

### NEW-0814-1: ещё тридцать одна рабочая операция появилась в машинной схеме

Тридцать одна рабочая операция, которая уже была доступна через V1 и описывалась в документации, теперь добавлена в `GET /v1/openapi.json`: поля смарт-процессов, ссылки реквизитов, настройки карточек CRM, настраиваемые дела, почта, учёт времени, управление значком и зависшим сервером, перевод бота и поиск узлов кадровой структуры, а также шаблоны приложений. Методы и их ответы не менялись — добавлено только описание для клиентов и агентов, строящих интеграции по машинной схеме.

### BC-0814-2: закрепление порта отказывает вместо ложного подтверждения

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

**Было**

У закреплённого сервера [PATCH /v1/infra/servers/:id/port](/docs/infra/deploy/port) записывал запрошенный порт в настройки агента, не проверяя, слушает ли его на машине хоть один процесс. Публичный адрес после такой смены мог не отвечать вовсе, а вернуть машину в рабочее состояние получалось только неочевидным `port: 0`. Ответ `verified: true` означал при этом лишь, что агент вернулся на связь: агент, поднявшийся с автоматическим подбором порта, то есть без закрепления, выдавал ровно то же подтверждение. Два запроса подряд успевали увести агента на порт чужого запроса, и оба отвечали успехом.

**Стало**

Порт, которого на машине никто не слушает, отбивается кодом `409 PORT_NOT_APPLIED` до того, как настройки будут переписаны; сообщение перечисляет порты, которые агент видит слушающими. Запись NEW-0812-3 утверждала, что у закреплённого сервера этот код не приходит никогда, — он приходит, ровно в этом случае и без поля `agentError`.

Подтверждение стало строже: `verified: true` теперь означает, что настройки агента несут запрошенный порт, агент действительно перезапустился и поднялся именно с закреплением, а не с автоматическим подбором. Ответ дополнительно несёт `data.pinned` — осталась ли машина закреплённой после вызова.

Пока смена порта не доведена до конца, второй запрос к тому же серверу получает `409 SERVER_BUSY`. Сам эндпоинт получил ограничение частоты — 10 запросов в минуту.

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

Поднимайте процесс на целевом порту ДО смены порта: порядок «сначала закрепить порт, потом запустить на нём приложение» теперь отвечает отказом, а не успехом. Не отправляйте смену порта параллельно с выкладкой или с другой сменой порта того же сервера — дождитесь ответа предыдущего вызова. Уложитесь в 10 запросов в минуту.

### FIX-0814-3: параметр dimensions для модели bitrix/embeddings

**Было**

Параметр `dimensions` был объявлен в схеме `POST /v1/embeddings`, но любой запрос с ним для модели `bitrix/embeddings` получал `400 ai_provider_rejected` — независимо от значения, включая размерность, которую модель и так возвращает.

**Стало**

Для `bitrix/embeddings` параметр работает: допустимо целое от 32 до 4096, ответ содержит вектор указанной размерности, приведённый к единичной длине. Значение вне диапазона отклоняется с `400 invalid_request` и полем `param`. Запросы без параметра не изменились: полная размерность 4096.

Меньшая размерность не уменьшает расход по входным токенам и не ускоряет обработку — экономия возникает на стороне интегратора, на размере индекса и скорости поиска. Векторы разной размерности нельзя смешивать в одном индексе близости. Подробнее — [Создать эмбеддинги](/docs/ai/embeddings).

### FIX-0814-4: служебные метки в начале ответа модели больше не попадают в content

**Было**

После вызова инструмента итоговый ответ [POST /v1/chat/completions](/docs/ai/chat/completions) иногда начинался со служебных меток перед текстом. Запрос с `response_format`, в котором ответ состоял только из таких меток, возвращал `200` и непустой `content`.

**Стало**

Служебные метки в начале `content` снимаются. Если текста не осталось, `content` равен `null` — как у ответа без текста. Для запроса с `response_format` это уже описанный случай пустого `content` без `tool_calls`: HTTP `422` и код `structured_output_truncated`. Если после снятия меток остаётся текст, ответ `200` с очищенным `content`.

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

В обычном случае менять клиент не нужно: ответ тот же, только без префикса, а собственное вырезание префикса по-прежнему безопасно. Изменение касается вас, если вы полагались на ответ `200` для запроса с `response_format`, в котором модель не дала текста: теперь такой ответ приходит с кодом `422` и `structured_output_truncated`, как и описано на странице метода. Метки снимаются и в потоковом режиме. Поле `usage` не пересчитывается.

### FIX-0814-5: блокирующее пробуждение сервера реже отдаёт WAKE_TIMEOUT на холодном старте

**Было**

Блокирующее пробуждение — [POST /v1/infra/servers/:id/wake](/docs/infra/lifecycle/wake) с `?wait=true` и автопробуждение спящего сервера при [POST /v1/infra/servers/:id/deploy](/docs/infra/deploy) — отдавало `503 WAKE_TIMEOUT` в двух случаях, которые не зависели от длины ожидания. Если команда запуска машины терялась на стороне облака, платформа больше её не повторяла и через отведённое время сообщала, что машина не поднялась. А если агент на машине успевал подключить туннель раньше, чем платформа обновляла статус сервера, готовность всё равно не признавалась — и уже поднятая машина возвращалась в сон.

**Стало**

Пока платформа ждёт готовности, она переспрашивает облако о состоянии машины и повторяет команду запуска, если та не доехала. Подключённый туннель теперь сам считается доказательством готовности: сервер переводится в `running` и ответ возвращается, не дожидаясь очередного обновления статуса. Коды ошибок, форма ответа и окно ожидания (~6.5 минуты, затем `503 WAKE_TIMEOUT` и возврат сервера в `sleeping`) не изменились, поэтому клиентам менять ничего не нужно. Машина, которая действительно не поднялась, по-прежнему честно отдаёт `WAKE_TIMEOUT`.

### FIX-0814-6: дробный или мусорный идентификатор в пути больше не возвращает ЧУЖУЮ запись

**Было**

Запрос вида `GET /v1/tasks/1.5` отвечал `200` и возвращал запись с идентификатором `1`: нецелое значение уходило в Битрикс24 как есть, тот отбрасывал дробную часть, и клиент получал ДРУГУЮ реальную запись вместо ошибки. То же на изменении и удалении — правка или удаление молча попадали не в ту запись. Затронуты сущности с целочисленным идентификатором; подмену записи удалось наблюдать вживую у двенадцати из них (задачи, рабочие группы, сотрудники, отделы, статусы, хранилища, сайты, страницы, папки, ленты событий, настройки открытых линий, шаблоны реквизитов), у остальных запрос отклонял сам Битрикс24. Часть сущностей (например сделки) уже отвечала `400`, поэтому поведение внутри одного API различалось.

**Стало**

Нецелый идентификатор отклоняется с `400 INVALID_PARAMS` до обращения к Битрикс24 — единообразно на чтении, изменении и удалении, и в одиночных запросах, и в пакетных (`/v1/batch`, `/v1/<раздел>/batch`). Правило действует для всех сущностей с числовым идентификатором. Целые значения работают как прежде. Сущности, у которых идентификатор не число (например статусы заказа `N`/`P`/`F`, валюты, коды бизнес-процессов), а также чаты, принимающие форму `chat1`, сохраняют прежнее поведение.

### NEW-0814-7: чтение ленты уведомлений и счётчика непрочитанных

Появился [GET /v1/notifications](/docs/notifications/list) — чтение ленты уведомлений сотрудника и счётчика непрочитанных. Раньше API Вайбкод умел только отправлять уведомления, отмечать их прочитанными и удалять, поэтому приложению-инбоксу приходилось держать вторую, отдельную интеграцию с Битрикс24 ради чтения.

Ответ несёт список уведомлений, карточки их авторов, общий счётчик, счётчик непрочитанных и признак `hasMore`. Размер страницы задаёт `limit` (от 1 до 50, по умолчанию 50); значение вне диапазона приводится к границе, и применённый размер всегда виден в `meta.appliedLimit`. Постраничный обход идёт курсором Битрикс24: `lastId` и `lastType` передаются только вместе. Счётчик непрочитанных без выкачивания страницы: вызов с `limit=1`.

Лента принадлежит владельцу токена — своего параметра «чей инбокс» у операции нет, поэтому по личному ключу возвращается лента владельца ключа, а лента конкретного сотрудника доступна по ключу OAuth-приложения с заголовком `Authorization: Bearer`. Лента не отфильтрована по приложению: в ней будут уведомления других приложений и системные уведомления портала, отбирать свои нужно по `notifyTag` или `notifyModule`.

### NEW-0814-8: История рабочего дня в V1 API

Появился эндпоинт [GET /v1/workday/records](/docs/workday/records) — история рабочих дней одного сотрудника за период. Он отдаёт время начала и завершения дня, отработанные секунды, длительность перерывов и признак подтверждения записи, поэтому отчёты по опозданиям и переработкам собираются через API Вайбкод, без отдельной интеграции с учётом рабочего времени на портале.

Параметр `userId` обязателен: без него портал Битрикс24 отказывает в вызове. Период задаётся необязательными `from` и `to` в формате ISO-8601 с явным смещением часового пояса или `Z`; если период не передан, возвращается окно за последние 7 дней. Дата без времени отклоняется — граница рабочего дня зависит от часового пояса, и молчаливое приведение к UTC переклассифицировало бы те самые опоздания, ради которых эндпоинт и нужен.

За один запрос возвращается не больше 50 записей, глубина берётся через `offset` или `page`. Признак продолжения — `meta.hasMore`. Поле `meta.total` приходит только тогда, когда страница оказалась короче запрошенного `limit`: в этом случае размер выборки известен точно, а на полной странице он неизвестен, и выдуманное число туда не подставляется.

Скоуп прежний — `timeman`. Права на чтение чужого табеля определяет портал Битрикс24: их выдают администратору или прямому руководителю сотрудника.

### FIX-0814-9: отказ INT_VIBE_PLUS_REQUIRED ведёт на страницу тарифа в аккаунте

**Было**

У кода `INT_VIBE_PLUS_REQUIRED` поля `details.upgradeUrl` и `alternatives[0].url` несли общую страницу цен Битрикс24. Тариф линейки Vibe+ подключается в самом аккаунте, поэтому общая страница не показывала, что именно нужно сделать.

**Стало**

Оба поля несут адрес аккаунта клиента, открывающий разбор нужного тарифа: `https://<домен аккаунта>/online/?feature_promoter=limit_why_pay_tariff_vibe`. Тот же адрес отдаёт слот `servers.create` в [GET /v1/me](/docs/keys-auth/me) — раньше он расходился с телом отказа.

Если домен аккаунта распознать не удалось, оба поля по-прежнему несут общую страницу цен: битого адреса наружу не уходит.

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

Менять ничего не нужно. Форма ответа прежняя, оба поля остаются строкой с адресом. Клиент, который вёл человека по `details.upgradeUrl`, теперь приводит его к нужному тарифу вместо общего прайса. Прежний код отказа, состав полей и статус ответа не изменились.

### BC-0814-10: расшифровка аудио принимает файл только в поле file, не обрезает его молча, а отказ распознавания возвращает как 400

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

**Было**

POST `/v1/audio/transcriptions` брал первую файловую часть multipart независимо от имени поля, а расширение имени файла не проверял: неизвестное расширение подставлялось как `audio/mpeg` и уезжало к распознаванию. Файл сверх лимита 25 МБ не отклонялся, а молча обрезался по лимиту: ответ приходил 200 с расшифровкой только начала записи, и она тарифицировалась, — признака обрезки в ответе не было. Любой не-2xx от сервиса распознавания возвращался как 502 `ai_provider_unavailable`, включая отказ по содержимому запроса.

**Стало**

Файловая часть обязана называться `file`, иначе 400 `no_file` — независимо от размера присланного файла. Проверка срабатывает до вызова распознавания. Расширение в имени файла НЕ проверяется: контейнер определяет распознавание по содержимому, поэтому редкие форматы диктофонов, имя без расширения и часть без имени принимаются как раньше. Файл, который распознавание прочитать не смогло, возвращается как 400 `ai_provider_rejected`. Файл сверх 25 МБ отклоняется целиком — 413 `request_too_large`, без списания; обрезанной расшифровки больше не бывает. Отказ распознавания с HTTP 400 или 422 возвращается как 400 `ai_provider_rejected` с полем `providerStatusCode`; ограничение частоты с его стороны — как 429 `rate_limit_exceeded` с заголовком `Retry-After`; недоступность и ошибки авторизации остаются 502 `ai_provider_unavailable`.

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

Назовите файловую часть `file` — прежнее имя вроде `audio` больше не подходит. Записи длиннее 25 МБ режьте на части до отправки: теперь такой запрос отклоняется, а не расшифровывается частично. Если код различал ошибки по статусу, учтите, что отказ по содержимому теперь приходит как 400, а не 502, и повторять такой запрос бессмысленно. Расширения менять не нужно: список включает и те форматы, которые принимались молча. Старое поведение не возвращается.

### NEW-0814-11: изображения товаров каталога

Добавлены `GET /v1/catalog-products/:productId/images` для снимка метаданных штатных изображений товара и `GET /v1/catalog-products/:productId/images/:imageId` для одного изображения. В снимок входят детальная картинка, картинка анонса и галерея `MORE_PHOTO`, но не файлы из других пользовательских свойств. Оба метода требуют скоуп `catalog`, возвращают недоверенный `detailUrl` и не раскрывают подписанный `downloadUrl`; серверно загружать URL можно только после платформенной SSRF-проверки. [Документация](/docs/entities/catalog-products/images).

### NEW-0814-12: расшифровка аудио может списываться с квоты подписки Cowork/Code

Раньше вызов [POST /v1/audio/transcriptions](/docs/ai/audio/transcriptions) ключом со скоупом `vibe:cowork` не списывал ничего: расшифровка считалась по квоте аккаунта Битрикс24, а ключи подписки этот счётчик пропускают. Теперь у модели расшифровки может быть цена за минуту аудио, и такой вызов расходует квоту подписки — так же, как чат.

Пока цена не назначена, поведение прежнее: вызов бесплатный и лимитом подписки не ограничивается.

Когда цена назначена, а окно квоты исчерпано, ручка отвечает `402` с кодом `cowork_quota_exhausted` — тем же, что уже отдаёт чат, — и заголовком `Retry-After` с числом секунд до обновления окна. Тело несёт `window` (`5h` / `week` / `month`), `resetAt` и `nextTier`.

Форматы ответа без длительности (`text`, `srt`, `vtt`) тарифицируются по цене за вызов, потому что длительность аудио в них не приходит.

### FIX-0814-13: расписание пробуждения больше не сокращает заданный авто-сон

**Было**

Если у сервера одновременно заданы авто-сон (`sleepAfterMinutes` — 30, 60 или 240 минут) и включённое окно расписания пробуждения, порог простоя молча заменялся на платформенный короткий порог в 15 минут. Сервер засыпал через 15 минут вместо заданных, а `GET /v1/infra/servers/:id` и карточка сервера продолжали показывать выбранное значение — расхождение нельзя было увидеть нигде.

**Стало**

Заданное значение действует как задано: расписание отвечает только за момент пробуждения. Короткий порог остаётся ровно там, для чего он и вводился, — у сервера без авто-сна (`sleepAfterMinutes: null`), чтобы он всё же засыпал в промежутках между окнами. Ничего менять в интеграции не нужно; серверы с заданным авто-сном и расписанием теперь держатся включёнными до своего порога.

### NEW-0814-14: запись с повреждённой кодировкой возвращает предупреждение

**Было**

Если в названии или описании приходил текст, где не-ASCII символы уже заменены на вопросительные знаки, платформа молча сохраняла такое значение. Карточка приложения на портале показывала `????????? ????????`, и понять это можно было только глазами.

**Стало**

Значение по-прежнему сохраняется, но ответ дополнительно несёт массив `warnings` — он называет поля, пришедшие без единого не-ASCII символа, и предлагает отправить текст в UTF-8. Так отвечают `POST /v1/infra/servers` и `PATCH /v1/infra/servers/{id}` (`displayName`, `description`), `POST /v1/infra/servers/{id}/deploy` (`displayName`, `description`), `POST /v1/apps` и `PATCH /v1/apps/{id}` (`title`), `POST /v1/apps/{id}/publish` (`catalogTitle`, `catalogDescription`). Предупреждение приходит только на поле, которое вызов действительно применил: повторная присылка того же значения и поле, отброшенное деплоем как уже заполненное, молчат. Поле необязательное: когда сообщать нечего, его в ответе нет, поэтому прежние клиенты работают без изменений.
