Для AI-агентов: markdown этой страницы — /docs-content/changelog/2026-08-11.md индекс документации — /llms.txt

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

← Журнал изменений · Август 2026

NEW-0811-1: тарифы серверов называют единицу цены

В ответе GET /v1/infra/providers/{providerId}/plans у каждого тарифа появилось поле currency со значением "Vibes" — единица, в которой считаются priceMonthly и sleepPriceMonthly. Раньше цены приходили безымянными числами, и единицу приходилось брать из текста документации; теперь это та же машинная пометка, что у стоимости поиска в GET /v1/me.

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

NEW-0811-2: каталог данных приложения объявляется в теле деплоя

Приложение на отдельной виртуальной машине запускается под непривилегированной учётной записью, и платформа передавала ей во владение только каталог распаковки. Каталог состояния вне него — тот самый /opt/data, который наша документация советует для данных, переживающих выкат, — создаётся администраторскими шагами install и preStart, поэтому оставался за администратором, и первая же запись из приложения падала с ошибкой доступа. Обойти это можно было только ручной раздачей прав в preStart на каждом деплое.

Было

Приложение писало только в свой каталог распаковки. Для каталога состояния декларативного способа не было.

Стало

В теле POST /v1/infra/servers/{id}/deploy появились два необязательных поля. dataDirs — до восьми каталогов вне каталога распаковки, которые платформа создаёт и передаёт учётной записи приложения на каждом деплое, а при откате возвращает обратно. Путь — абсолютный, нормализованный, внутри /opt, /srv или /var/lib; сами корни отвергаются новым кодом INVALID_DATA_DIRS до того, как деплой займёт сервер. dataDirsRecursive дополнительно передаёт содержимое объявленных каталогов — нужно только для заранее развёрнутого дерева; для /opt/data не принимается, потому что там по нашему же рецепту восстановления базы лежит файл с паролем.

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

Прежние вызовы работают как раньше: без этих полей ни один каталог не создаётся и владельца не меняет.

NEW-0811-3: выпуск ключа ровно с выбранными платформенными правами

Тело POST /v1/keys принимает необязательное поле exactScopes. С exactScopes: true ключ сохраняет ровно те права, что перечислены в scopes: четыре платформенных (vibe:infra, vibe:ai, vibe:search, vibe:storage) не дописываются при выпуске, и vibe:ai / vibe:search не добавляются к правам запроса на лету. Поэтому GET /v1/me возвращает ровно сохранённый набор, а ключ без vibe:infra отвечает 403 INFRA_SCOPE_REQUIRED на POST /v1/infra/servers.

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

Ключи, выпущенные в кабинете, теперь тоже точные — снятая галочка платформенного права означает, что права у ключа нет. Раньше набор Вайбкод дописывался безусловно, и сузить права можно было только правкой ключа после выпуска.

NEW-0811-4: выгодные часы видны в подписке Cowork/Code и в отказе по исчерпанной квоте

В отдельные часы недели квота расходуется медленнее — тот же вызов забирает меньшую долю лимита. Раньше об этом можно было узнать только из расписания выгодных часов, теперь то же самое видно в ответах подписки Cowork/Code и в отказе по исчерпанной квоте, поэтому приложение может предложить перенести объёмную задачу на выгодный час, не собирая расписание само.

Ответ Что появилось
ОтветGET /v1/off-peak Что появилосьcurrentWindowEndsInHours — через сколько часов расход перестанет быть таким же выгодным. null, если в пределах недели вперёд дороже не станет
ОтветGET /v1/cowork/me Что появилосьБлок offPeak — действует ли скидка сейчас, какой множитель расхода и когда наступит ближайший выгодный час. Без сетки часов
ОтветGET /v1/cowork/state Что появилосьТот же блок offPeak вместе с сеткой часов на неделю и поле touSavedPct — какую долю расхода за текущий расчётный период сняли выгодные часы
ОтветОтказ 402 cowork_quota_exhausted на POST /v1/chat/completions Что появилосьoffPeakHint — через сколько часов снимется блокировка (inHours) и какой множитель расхода будет действовать в этот момент (multiplier). Приходит, только когда этот момент попадает в час со скидкой

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

Множитель — коэффициент расхода, а не размер скидки. Значение 0.5 означает, что вызов забирает половину той доли квоты, которую забрал бы без скидки.

Поля блока, примеры ответов и особенности — Выгодные часы в подписке Cowork/Code.

FIX-0811-5: ближайший выгодный час отсчитывается от границы часа, а не от минуты запроса

Было

Поле nextWindow.inHours в ответе GET /v1/off-peak отсчитывалось от момента запроса. Расписание почасовое, поэтому ответ «через 2 часа», полученный в 10:55, указывал на 12:55 — на середину выгодного часа, начавшегося в 12:00. Клиент, прибавивший это число к моменту запроса, попадал в дешёвый час, когда большая его часть была уже позади.

Стало

Отсчёт идёт от границы текущего часа в часовом поясе расписания. То же «через 2 часа», полученное в любую минуту между 10:00 и 11:00, указывает на 12:00 — на начало выгодного часа. Поле стало тем, чем его описывает документация, — ближайшим часом, который дешевле текущего. Расхождение с прежним прочтением не превышает одного часа.

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

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

BC-0811-6: машина, у которой не загружается операционная система, отвечает отдельным кодом

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

Было

Сервер, чья гостевая операционная система не стартует после прерванного обновления, выглядел как обычный «временно не на связи». Ремонт по нему запускался снова и снова и каждый раз возвращал сообщение про SSH-ключ, к которому поломка отношения не имеет, а POST /v1/infra/servers/:id/start отвечал 200 и поднимал машину, которая всё равно не загрузится. Отличить безнадёжную машину от временно недоступной по ответам API было нельзя.

Стало

Такая машина получает машинную метку provisionErrorCode = "GUEST_NOT_BOOTING" в ответах GET /v1/infra/servers/:id и списка серверов. POST /v1/infra/servers/:id/repair и POST /v1/infra/servers/:id/start отвечают 422 с кодом GUEST_NOT_BOOTING вместо заведомо бесполезной работы, в availableActions остаётся только delete, а GET /v1/me в блоке infra.unhealthyServers советует пересоздание вместо ремонта. Начисление за такую машину закрыто в момент вердикта.

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

Проверяйте provisionErrorCode перед запуском и ремонтом: значение GUEST_NOT_BOOTING терминально, повтор не поможет, сервер нужно пересоздать. Клиент, который вызывает start по расписанию, получит на такой машине 422 вместо прежнего 200 — обработайте этот код как «пересоздать», а не как временную ошибку. Прежнее поведение не сохраняется: 200 означал запуск машины, которая всё равно не загружается, и продолжал начисление за неё.

NEW-0811-7: у ответа «приложение не отвечает» появился отдельный код для сервера без выкладки

Было

Когда туннель до сервера открыт, а приложение не отвечает, машинному вызывающему всегда приходил один и тот же ответ 503 с кодом BH_APP_STARTING и заголовком Retry-After. Сервер, на который выкладки никогда не было, был неотличим от сервера, где приложение упало или слушает не тот порт, и повтор по таймеру выглядел осмысленным там, где ждать было нечего.

Стало

Если платформа не видела ни одной выкладки на этот сервер, ответ приходит с кодом BH_APP_NOT_DEPLOYED и без заголовка Retry-After — повторять по таймеру бессмысленно, нужна выкладка либо проверка адреса. Прежний BH_APP_STARTING с Retry-After остаётся для случая, когда выкладка была: там приложение действительно может подняться само. Статус ответа в обоих случаях 503, поэтому обработка, не разбирающая код, работает как раньше.

FIX-0811-8: создание шаблона документа объявляет требуемый скоуп в openapi.json

Было

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

Стало

Операция объявляет x-required-scope: documentgenerator, как остальные операции модуля. В срезах она остаётся только при openapi.json?scope=documentgenerator и в полной спецификации.

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

Ничего менять не нужно: поведение самого эндпоинта не изменилось. Клиенты, которые выводят набор скоупов из спецификации, теперь запросят documentgenerator сразу и не упрутся в 403.

FIX-0811-9: Пользовательские поля реквизитов в ответах

Было

crm.requisite.get не возвращал пользовательские поля реквизита в ответах V1.

Стало

После успешного crm.requisite.get сервис точечно добирает пользовательские поля реквизита и сохраняет успешный ответ, если этот дополнительный вызов недоступен.

NEW-0811-10: granted_scopes — фактические права выданного ключа в ответе обмена

POST /v1/connect/token отдаёт новое поле granted_scopes — набор прав, который реально несёт выданный API-ключ. Поле scopes не изменилось: там по-прежнему то, что приложение запросило при авторизации. Обычно наборы совпадают, но у приложений, которым права проставляет платформа, они расходятся — например при входе по коду устройства настольное приложение Cowork не просит ничего, поэтому scopes приходит пустым, а granted_scopes перечисляет весь набор ключа. Поле необязательное и может отсутствовать, если платформа не смогла прочитать права выданного ключа. Пустым оно не приходит, поэтому отсутствие означает «набор неизвестен», а не «прав нет». Прежние вызовы работают без изменений.

FIX-0811-11: OpenAPI: обязательные скоупы для bespoke-операций

Было Машинный OpenAPI-контракт не содержал x-required-scope для bespoke-операций, хотя их обработчики уже проверяли скоуп до вызова Bitrix24.

Стало Контракт публикует проверяемый обработчиком скоуп для операций CRM, bots, calls, chats, lists, note, notifications, posts, scrum, tasks, timelines, userfields, warehouses, workday и workflows. Прокси скачивания с двумя допустимыми скоупами оставлен без одиночной аннотации, потому что она была бы неточной.

FIX-0811-12: справочник /v1/guide отдаёт ссылку на документацию для сущности telephony-lines

Было

В ответе GET /v1/guide сущность telephony-lines приходила без поля docs. Страница с описанием линий существовала, но найти её по ответу справочника было нельзя.

Стало

Сущность telephony-lines содержит docs со ссылкой на раздел телефонии /docs/telephony/lines. Остальные поля ответа не изменились, действий на стороне клиента не требуется.

FIX-0811-13: запись с Content-Type: text/plain теперь отклоняется, а не создаёт пустую запись

Было

Запрос на создание или изменение (POST/PATCH) с заголовком Content-Type: text/plain и телом, не являющимся JSON, принимался: тело молча отбрасывалось, а запись всё равно выполнялась — POST создавал пустую сущность с кодом 201, PATCH тихо ничего не менял. Любой другой не-JSON тип уже отвечал 415.

Стало

Такой запрос отвечает 415 Unsupported Media Type, как и прочие не-JSON типы; пустая запись не создаётся. Отправляйте тело как application/json.

BC-0811-14: деплой не рапортует успех, когда порт остался за прежним процессом

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

Было

Деплой на POST /v1/infra/servers/{id}/deploy мог ответить success: true и healthcheck: ok, хотя порт приложения остался за процессом, который занимал его ещё до начала деплоя. Проверка живости получала 200 от него, а не от нового приложения, поэтому по публичному адресу продолжала отдаваться прежняя версия. Шаг stop_existing при этом честно предупреждал, что владелец порта не связан с новым приложением, но деплой шёл дальше и завершался успехом.

Стало

Если проверка живости получает 200, а порт при этом занят процессом, который был на нём ещё до начала этого деплоя, шаг healthcheck завершается ошибкой. В тексте ошибки указан владелец порта. Ответ становится success: false, у шага — status: "error", в потоковом режиме поток останавливается на том же шаге.

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

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

Проверьте, не держит ли порт приложения процесс, который переживает деплои: обратный прокси, менеджер процессов, а также контейнер или systemd-юнит, поднятый один раз из шага install или preStart и не пересоздаваемый при следующих деплоях. Такая схема раньше отвечала success: true, а теперь будет отвечать success: false: платформа не может подтвердить, что по этому адресу отвечает именно новая версия. Отдайте порт приложения самому приложению, а свой процесс переведите на другой порт. Всем остальным менять ничего не нужно: форма ответа прежняя, а сценарий, который раньше получал success: true при неподнявшейся новой версии, теперь получит success: false с причиной.

NEW-0811-15: предрасчёт стоимости смены тарифа Cowork/Code

GET /v1/cowork/subscription/preview?tier=<FREE|PRO|MAX|ULTRA> возвращает сумму, которая будет списана прямо сейчас при переходе на указанный тариф: полную цену операции, возврат за неиспользованный остаток оплаченного месяца и итог к списанию. Скоуп vibe:cowork, ответ не кэшируется, ограничение — 30 запросов в минуту на пару «аккаунт и пользователь».

Экран подтверждения стоит строить на этом ответе, а не на цене тарифа из tiers[].feeVibes в GET /v1/cowork/state: цена там — ценник, и сумма списания уже сегодня отличается от него в четырёх случаях. Повторный выбор тарифа, который уже стоит, списывает ноль; понижение, поставленное в очередь на конец оплаченного периода, сейчас не списывает ничего; повторный запрос про такое понижение — тоже ноль; повышение с зачётом остатка месяца списывает цену за вычетом возврата. Пара netVibes: "0" и scheduled: true прямо отвечает на вопрос «спишется ли сейчас», поэтому эти правила не нужно повторять в клиенте.

Вайбы приходят десятичной строкой в основных единицах — так же, как баланс и движения по счёту. Рядом идут currency (код валюты пополнения по ISO 4217 либо null) и topUpAvailable; это про пополнение кошелька, а не про цену тарифа — денежной цены тарифа и курса вайба к деньгам ответ не содержит.

FIX-0811-16: сообщение об отказе установки приложения называет ответ портала

Было

Когда Битрикс24 отказывал в установке приложения по ключу разработчика и причина не попадала ни в один распознаваемый код, ответ нёс DEVKEY_MINT_FAILED и общий текст Failed to install app via developer key. По нему нельзя было отличить отказ по правам от недоступности REST или сетевого сбоя.

Стало

К тому же тексту дописывается наблюдаемое: Failed to install app via developer key (Bitrix24 answered HTTP 403 BITRIX_REST_V3_EXCEPTION_ACCESSDENIEDEXCEPTION). Код ошибки (error.code), статус ответа и поле userMessage не изменились, так что разбор ответа по коду продолжает работать без правок. У отказов с распознанной причиной — подписка, тариф, устаревший ключ — текст прежний.

Ответ портала дописывается только когда он был: на сетевом сбое, когда портал не ответил вовсе, текст остаётся прежним. Код отказа дописывается в машинном виде и не длиннее 64 символов.

FIX-0811-17: чтение с ключом только для чтения не отклоняется как запись

Было

Ключ только для чтения мог получить 403 WRITE_BLOCKED_READONLY_KEY при запросах, которые читают данные через методы Битрикс24 timeman.status, timeman.settings, calendar.event.getbyid, bizproc.workflow.instances, lists.get.iblock.type.id, lists.element.get.file.url, crm.type.getByEntityTypeId и crm.activity.call.getTranscript.

Стало

Ключ только для чтения пропускает эти операции чтения. Неизвестные методы по-прежнему считаются записывающими и блокируются.

BC-0811-18: отметка «прочитано» требует ключа с правом записи

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

Было

Ключ в режиме «только чтение» мог отметить уведомления и сообщения прочитанными: POST /v1/notifications/read, POST /v1/chats/:dialogId/read и POST /v1/bots/:botId/chats/:dialogId/read выполнялись и меняли состояние портала — счётчик непрочитанного, статусы уведомлений. Проходили они потому, что право на запись определяется по имени вызываемого метода Битрикс24, а эти имена оканчиваются словом «read» и читались как чтение.

Стало

Все три операции под ключом «только чтение» отвечают 403 WRITE_BLOCKED_READONLY_KEY. Код добавлен в справочник ошибок каждой из трёх страниц. Ключ с правом записи работает как раньше.

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

Если сценарий отмечает прочитанным — выпишите или переключите ключ в режим с правом записи в разделе ключей кабинета. Чтение уведомлений и сообщений под ключом «только чтение» не изменилось. Подписка на события чатов (POST /v1/chats/events/subscribe и POST /v1/chats/events/unsubscribe) ключу «только чтение» по-прежнему доступна — это осознанное исключение, без которого агент в режиме чтения не смог бы следить за событиями.

FIX-0811-19: ещё пять читающих операций перестали отклоняться под ключом только для чтения

Было

Запись FIX-0811-17 сняла отказ у восьми читающих методов, но того же класса осталось ещё пять операций: GET /v1/tasks/:taskId/chat/messages, GET /v1/humanresources/nodes/:id/children, GET /v1/humanresources/employees/:id/subordinates, GET /v1/mail/messages/:id/thread и GET /v1/mail/mailboxes/:id/senders. Ключ в режиме «только чтение» отвечал на них 403 WRITE_BLOCKED_READONLY_KEY: право на запись определяется по имени вызываемого метода Битрикс24, а у этих операций оно оканчивается общим словом, и незнакомое имя трактовалось как запись. Ни одно обращение по ним не приходило — расхождение нашлось сверкой всего списка методов с их адресами.

Стало

Все пять отвечают ключу «только чтение» как обычное чтение. Отказ 403 WRITE_BLOCKED_READONLY_KEY остался на операциях записи в тех же разделах: отправка письма, правка оргструктуры, отправка сообщения в чат задачи.

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

Менять ничего не нужно: запросы, которые раньше отклонялись, теперь выполняются. Если ради этих операций вы выписывали ключ с правом записи — верните ему режим «только чтение».

NEW-0811-20: состояние Cowork/Code рассказывает, как аккаунту открыть работу с Битрикс24

В ответе GET /v1/cowork/state появился блок activation. Он говорит, по какой модели работает регион аккаунта (model: subscription или tariff), даёт ссылку на условия тарифов Битрикс24 (tariffInfoUrl — только при model: tariff и только для облачного аккаунта) и заранее отвечает, стоит ли предлагать включение пробного периода Маркета: marketTrial.available и marketTrial.unavailableReason (trial_already_activated, subscription_active, demo_used, region_not_supported, not_cloud, portal_state, not_supported), плюс журнал наших попыток — status, endsAt, activatedAt.

Признак считается до попытки, поэтому шаг включения можно не показывать там, где он заведомо не сработает. Значение false окончательно, значение true означает «предлагать можно», но не гарантирует успех: состояние аккаунта может измениться между запросом и нажатием, поэтому обработку отказа на самом включении оставьте. Список причин может пополняться — неизвестное значение читайте как «активацию не предлагать». Самого блока activation в ответе может не быть вовсе: так отвечает платформа, которая про него ещё не знает, и это штатное состояние — проверяйте наличие блока, а внутри него читайте значение поля.

FIX-0811-21: у состояния Cowork/Code появился предел частоты опроса

Было

GET /v1/cowork/state принимал запросы без ограничения частоты, хотя документация рекомендует опрашивать его раз в 15–30 секунд.

Стало

Предел есть: он общий на аккаунт и владельца ключа, то есть все устройства одного человека делят его. Сверх предела эндпоинт отвечает 429 RATE_LIMITED.

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

Клиент, соблюдающий рекомендованный интервал, предела не заметит: он расходует около двух запросов в минуту, а запас до потолка кратный. Если ваш опрос чаще, разредите его или обработайте 429.

FIX-0811-22: ссылка на повышение в ответе о возможностях больше не ведёт в никуда

Было

В GET /v1/me при отказе на создание сервера поле capabilities.servers.create.alternatives[].url (и тот же адрес в тексте userMessage) вело на страницу лицензии внутри самого аккаунта. Этот адрес различается между редакциями и версиями Битрикс24 и на части аккаунтов отдавал 404 — платформа отказалась от него в остальных ответах ещё в апреле, а здесь он остался.

Стало

Приходит устойчивый адрес: касса аккаунта там, где доступ открывается подпиской, и общая страница условий тарифов Битрикс24 там, где доступ тарифный. Заодно текст «оформите подписку» больше не показывается регионам, где подписки нет как продукта, — им остаётся общая формулировка и ссылка на условия тарифов.

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

Ничего менять не нужно: поле осталось на месте и по-прежнему может отсутствовать. Не сохраняйте значение у себя и не разбирайте его домен — это адрес платформы, а не вашего аккаунта.

FIX-0811-23: пауза перед повтором в отказе ai_congested зависит от настроенной базы и ограничена сверху

Было

Когда платформа ограничивала поток AI-запросов, POST /v1/chat/completions, POST /v1/embeddings и POST /v1/audio/transcriptions отвечали 429 с кодом ai_congested, заголовком Retry-After и полем retryAfter в теле. Названная пауза почти не разбрасывалась — соседние отказы приходили с близкими значениями, — и верхнего предела у неё не было.

Стало

Пауза разбрасывается шире и может прийти длиннее прежней; сверху она ограничена — не больше часа. Насколько именно — зависит от того, как платформа ограничивает поток в этот момент, поэтому единственное верное поведение прежнее: ждать ровно столько, сколько названо в ответе.

Заголовок Retry-After и поле retryAfter в теле по-прежнему несут одно и то же число.

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

Менять ничего не нужно: форма ответа, код ai_congested и набор полей не изменились. Если ваш клиент предполагал, что пауза укладывается в базу плюс две секунды, — снимите это предположение и ждите столько, сколько названо в Retry-After. Это относится и к вызовам через устаревшие адреса /v1/ai/*, которые ведут к тем же обработчикам.

NEW-0811-24: у прерванного деплоя в галактике появилась машинная причина и признак повтора

Ответ 502 GALAXY_DEPLOY_INTERRUPTED теперь несёт два новых необязательных поля. Прежние клиенты продолжают работать без изменений: код ошибки, retryable и error.hint остались на месте.

error.subcause называет, что именно произошло, — раньше все прерывания выглядели одинаково и единственным советом было «повторите»:

  • http_window_exhausted — окно запроса кончилось раньше, чем платформа успела проверить хоть раз. Сборка вполне могла завершиться на хосте, и повторный запрос подтвердит это за секунды.
  • exec_channel_busy — канал команд хоста был занят до конца отведённого ожидания.
  • no_this_deploy_container — хост ответил, но здорового контейнера именно этого деплоя не нашлось.
  • tail_unreached — связь оборвалась, и чистого ответа до дедлайна не пришло.
  • source_fetch_interrupted — добывание архива с исходниками прервалось до начала сборки, приложение при этом не тронуто.

error.repeated становится true, когда одно и то же приложение прерывалось несколько раз за короткое окно. В этом случае error.hint перестаёт советовать простой повтор и предлагает сначала проверить, стартует ли приложение, а если оно заведомо рабочее — обратиться в поддержку с идентификатором сервера.

Заодно текст ошибки перестал утверждать, что хост доступен, в том случае, когда платформа его ни разу не спросила.

Затронутые эндпоинты: POST /v1/infra/servers/:id/deploy

FIX-0811-25: создание galaxy-приложения сообщает, что присланные provider, plan и region не применены

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

Было

POST /v1/infra/servers на портале, который размещает приложения в галактиках, отвечал 201, а в data.provider, data.plan и data.region возвращал значения хоста. Отличить «платформа взяла моё» от «платформа взяла чужое» по ответу было нельзя.

Стало

Тот же запрос по-прежнему отвечает 201 и по-прежнему наследует значения хоста — поведение не изменилось. Изменился ответ: рядом с data появляется запись в warnings[], если присланное значение расходится с действующим. Она называет разошедшиеся поля, показывает оба значения, предупреждает, что повторная отправка ничего не изменит, и указывает на placement со значением dedicated — способ получить машину с выбранными вами характеристиками. Совпавшие поля не упоминаются, поэтому корректный вызов остаётся без предупреждения. Слишком длинное или не похожее на идентификатор каталога значение описывается словами, а не возвращается обратно.

BC-0811-26: загрузка файла в приложение галактики отклоняется вместо записи на общий сервер

Поддержка старого формата до: 01.02.2027

Было

POST /v1/infra/servers/:id/upload принимал id приложения галактики (kind: GALAXY_APP) и записывал файл — но не в контейнер приложения, а на файловую систему общего сервера, где живут остальные приложения аккаунта. Ответ был 200, поэтому промах выглядел как успех.

Стало

Тот же вызов отвечает 400 GALAXY_APP_USE_GALAXY_ROUTE — как это уже делают exec, logs и deploy для приложений галактики. Ответ называет причину: запись шла на общий сервер, а не в контейнер.

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

Файлы в приложение галактики доставляются пересборкой образа из исходников — source в теле POST /v1/infra/servers/:id/deploy. Загрузка в отдельный сервер (kind: STANDALONE) не изменилась.

FIX-0811-27: приложение из каталога Битрикс24 открывается сотруднику без учётной записи Вайбкод

Было

Приложение, открытое из раздела «Битрикс24.Вайбкод», запускалось только у тех сотрудников, у кого уже была личная учётная запись Вайбкод. Остальные получали экран «войдите в VibeCode и подключите этот портал» — даже когда приложение было выдано всему порталу. Из-за этого администратор, у которого учётная запись есть, видел рабочее приложение, а рядовые сотрудники — нет.

Стало

Учётная запись больше не является условием доступа. Приложение с политикой «весь портал» (а также «любой авторизованный» и «публичный доступ») открывается всем сотрудникам портала: членство подтверждает подписанная порталом форма, а платформа дополнительно спрашивает у Битрикс24, что это активный сотрудник, а не уволенный и не внешний гость. Именные политики (только владелец, конкретные пользователи, отделы) этим путём по-прежнему не открываются — они решают по конкретному человеку, поэтому там остаётся прежний экран со входом.

Что учесть при разработке приложения: у сотрудника без учётной записи заголовок X-Vibe-User-Role всегда приходит MEMBER, даже если на портале он администратор, а X-Vibe-User-Name — Unknown. Не завязывайте на эти заголовки необратимые решения; права проверяйте вызовом к Битрикс24.

BC-0811-28: у AI-запроса появился срок обслуживания: вместо зависания приходит отказ 429

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

Было

Запрос к POST /v1/chat/completions, POST /v1/embeddings и их псевдонимам /v1/ai/* не имел объявленного верхнего срока. Обычный ответ упирался во внутренний предел ожидания и приходил обрывом соединения без тела, а у потокового ответа общего ограничения по времени не было вовсе: если кластер переставал присылать фрагменты, соединение висело до таймаута самого клиента. Отличить «ещё работает» от «уже не ответит» было нечем.

Стало

У запроса есть срок обслуживания. Не уложились — приходит 429 с телом {"error":{"code":"ai_deadline_exceeded","type":"rate_limit_exceeded","retryAfter":<секунды>}} и заголовками Retry-After и X-AI-Deadline-Ms (фактический бюджет запроса в миллисекундах). В потоковом ответе, где статус уже отправлен, то же тело приходит отдельным событием потока, за которым следует data: [DONE].

Клиент может попросить себе более короткий бюджет заголовком запроса X-AI-Deadline-Ms — значение в миллисекундах. Оно только сокращает срок: больше платформенного не выдаётся, и там, где срок отключён, заголовок его не включает. Нечисловое или неположительное значение считается неуказанным и вызов не отклоняет.

Срок применяется и к повторной попытке на резервной модели: отсчёт идёт от прихода запроса, а не от начала попытки.

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

Обрабатывайте 429 с кодом ai_deadline_exceeded как приглашение повторить: подождите указанное в Retry-After число секунд и отправьте запрос заново. Для потоковых вызовов добавьте разбор события с полем error — раньше поток такого события по этой причине не присылал. Если у вашего клиента свой предел ожидания, передавайте его в X-AI-Deadline-Ms: тогда отказ придёт от нас с объяснением, а не оборвётся у вас по таймауту.

FIX-0811-29: каталог регионов сервера на международной версии больше не отдаёт зоны недоступных регионов

Было

GET /v1/infra/providers/{providerId}/regions на международной версии платформы возвращал в списке региональные зоны, которые в этом сегменте недоступны для размещения, — они попадали в ответ вместе с доступными.

Стало

Список фильтруется по сегменту: на международной версии в ответе остаются только зоны, доступные для размещения в этом сегменте. Клиенту менять ничего не нужно — ответ стал корректным. На основной версии платформы список не изменился.