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

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

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

FIX-0819-1: отправка сообщений ботом принимает верхнеуровневый dialogId

Было

При отправке сообщения ботом через MCP верхнеуровневый dialogId не попадал в запрос POST /v1/bots/:botId/messages, а запрос без адресата возвращал ошибку платформы.

Стало

Верхнеуровневый dialogId передаётся как канонический адресат, а прежний body.dialogId остаётся совместимым запасным форматом. Запрос без непустой строки dialogId возвращает MISSING_PARAMS до отправки сообщения.

FIX-0819-2: заголовок `X-Tariff-Checked-At` отдаётся только после удачной сверки тарифа

Было

Отметка ставилась после ЛЮБОЙ попытки сверки тарифа с Битрикс24, включая неудачную: портал, у которого сверка упала по таймауту или по нехватке прав ключа, всё равно получал свежий X-Tariff-Checked-At. Отличить «тариф прочитан час назад» от «час назад попытались и не смогли» по заголовкам было нельзя.

Стало

Заголовок отдаётся, только когда последняя сверка действительно прочитала тариф. Неудачная попытка заголовок не выставляет вовсе — его отсутствие теперь значит «достоверной сверки нет», а не «портал никогда не проверяли». Заголовок X-Tariff-Is-Commercial не изменился и приходит как раньше.

FIX-0819-3: уточнено встраивание личным ключом и обработан OAuth без state

Было

GET /v1/me ошибочно утверждал, что личный ключ вообще не может опубликовать встроенное приложение. Если Битрикс24 возвращал OAuth-код без state, /v1/bitrix-handler оставался на промежуточной странице.

Стало

portalEmbedding описывает рабочий цикл POST /v1/apps → OAuth-авторизация → POST /v1/apps/:id/publish и отдельно предупреждает, что личный ключ не вызывает placements/bind напрямую и сам не даёт transparent auth. OAuth-callback без state безопасно перенаправляется на контролируемую страницу ошибки без передачи кода.

BC-0819-5: поле freshnessWindowMinutes больше не приходит в ответах

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

Было

GET /v1/me отдавал в блоке capabilities.apps.sourceStorage поле freshnessWindowMinutes со значением 10, а отказ 409 SNAPSHOT_REQUIRED у POST /v1/apps/:id/publish нёс то же поле внутри hint. Поле называло окно в минутах, в пределах которого сохранённый снапшот исходников считался пригодным для публикации.

Стало

Поля нет ни в описании возможностей, ни в подсказке отказа. Оно приходит, только когда публикация проверяет возраст снапшота, а сейчас она его не проверяет — публиковать можно снапшот любой давности. Отдельного null вместо поля не появляется: поле просто отсутствует. Остальной состав блока capabilities.apps.sourceStorage и остальные поля hint не менялись.

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

Читайте freshnessWindowMinutes как необязательное поле: если ваш код требует его наличия, приводит к числу без проверки или строит на нём таймер повторного сохранения — уберите эту зависимость. Отсутствие поля трактуйте как «возраст снапшота не проверяется». Поле вернётся только в том случае, если публикация снова начнёт проверять возраст, и тогда его значение снова будет осмысленным. Полная схема подсказки — Хранилище исходников.

BC-0819-6: публикация отказывает, если файлы сохранённой версии исходников удалены

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

Было

POST /v1/apps/:id/publish выбирал сохранённую версию исходников по записи о ней, не проверяя, живы ли её файлы. Поэтому версия, у которой файлы уже вычищены из хранилища или помечены на удаление, годилась для публикации: запрос отвечал 200, приложение получало статус PUBLISHED, а скачивание опубликованной версии затем отвечало 410 SOURCE_VERSION_BYTES_PURGED. Опубликованными оказывались исходники, которых нет.

Стало

Версии без файлов публикация не выбирает вовсе. Если других сохранённых версий у приложения или у сервера нет, ответ — 409 SNAPSHOT_REQUIRED с hint.reason = app_snapshot_missing или server_snapshot_missing: файлов нет, значит и снапшота нет. Если такая версия передана явным sourceVersionId, ответ тот же 409, а hint.lastSnapshot приходит как null. Это изменение не связано с проверкой возраста снапшота и действует всегда.

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

Проверяйте ответ публикации на 409 SNAPSHOT_REQUIRED и в том сценарии, где раньше он приходить не мог, — у приложения, чьи файлы исходников удалены из хранилища или помечены на удаление. Восстановление одно: сохраните архив заново через POST /v1/apps/:id/sources или POST /v1/infra/servers/:id/sources и повторите публикацию. Срок хранения и удаление файлов описаны в разделе Хранилище исходников.

FIX-0819-7: публикация приложения больше не отказывает из-за возраста сохранённых исходников

Было

POST /v1/apps/:id/publish отвечал 409 SNAPSHOT_REQUIRED, если сохранённый снапшот исходников был старше десяти минут, даже когда сам код не менялся. Проверка измеряла не соответствие исходников, а время с последнего сохранения, поэтому обычный порядок «деплой, затем авторизация приложения на портале, затем публикация» упирался в отказ: шаг авторизации выполняет человек, и он легко занимает больше окна. Чтобы пройти дальше, приходилось повторно сохранять тот же самый архив через POST /v1/apps/:id/sources или POST /v1/infra/servers/:id/sources. В подсказке отказа приходило hint.reason со значением app_snapshot_stale или server_snapshot_stale.

Стало

Возраст сохранённых исходников публикацию не ограничивает: подойдёт снапшот любой давности. Отказ 409 SNAPSHOT_REQUIRED остаётся только тогда, когда пригодного снапшота нет вовсе, и в этом случае hint.reason содержит app_snapshot_missing или server_snapshot_missing. Значения app_snapshot_stale и server_snapshot_stale в ответе больше не встречаются — они возвращаются, только если публикация снова начнёт проверять возраст снапшота.

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

Менять ничего не нужно: у публикации просто исчез один из поводов для отказа. Повторное сохранение неизменившегося архива перед публикацией теперь лишнее — его можно убрать из сценария. Если ваш код разбирает hint.reason, ветки под значения app_snapshot_stale и server_snapshot_stale перестанут срабатывать, но остаются валидными: набор значений поля не менялся.

FIX-0819-8: Публикация приложения больше не помечает версию исходников как успешно задеплоенную

Было

После успешной публикации платформа записывала на выбранную версию исходников статус деплоя success — независимо от того, чем деплой этой версии закончился и был ли он вообще. В списке версий (GET /v1/infra/servers/:id/sources), в файле описи и в реестре источников версия неудачного деплоя после публикации выглядела успешной, а версия, сохранённая вручную, получала статус деплоя, которого не было.

Стало

Публикация записывает только отметку о себе — linkedDeployId вида publish:<время>. Поле deployStatus остаётся тем, чем его сделал деплой: success, failed либо пусто у версий, сохранённых вручную.

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

Менять ничего не нужно. Если вы читали deployStatus как признак «эта версия опубликована» — это никогда не было его смыслом; признак публикации несут пометка published в tags и префикс publish: в linkedDeployId.

BC-0819-9: промокод на закрытом рабочем месте: код отказа `COUPON_SEAT_CANCELLED` больше не возвращается

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

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

Из-за этого пропал код отказа COUPON_SEAT_CANCELLED: возвращать его больше нечему. Если ваш код разбирает причины отказа списком, уберите его — ветка стала недостижимой.

Один отказ на закрытом месте остался, но с другим кодом. Место, закрытое досрочно при неистёкшем оплаченном сроке, отвечает COUPON_SEAT_ALREADY_PAID_LONGER: погашение перезаписало бы оплаченный срок подарочным, и купленные месяцы исчезли бы со строки, по которой считается возврат.

Затронутые эндпоинты: POST /v1/cowork/coupon/preview, POST /v1/cowork/coupon/redeem

FIX-0819-10: промокод больше не съедает оплаченный срок на понижённом месте

Было

Если место понижали с предоплаченного тарифа, на строке оставался оплаченный срок (дата окончания в будущем и цена купленного месяца), но списание уже не планировалось. Погашение промокода на таком месте проходило: POST /v1/cowork/coupon/redeem отвечал успехом, а выданный подарок переписывал дату окончания оплаченного срока на срок подарка. Купленные месяцы исчезали со строки, по которой считается возврат.

Стало

Такое погашение отклоняется кодом COUPON_SEAT_PAID_TERM_ACTIVE — новым в наборе отказов POST /v1/cowork/coupon/redeem. Оплаченный срок на месте не меняется, промокод остаётся у человека и гасится после окончания срока. Прочие отказы набора и их условия прежние.

BC-0819-11: отвязка мест встраивания, которую не удалось подтвердить, больше не выглядит успехом

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

Было

POST /v1/apps/{id}/unpublish отвечал 200 и очищал placements независимо от того, сняла ли платформа привязки на Битрикс24. POST /v1/apps/{id}/publish и PATCH /v1/apps/{id} с изменённым набором мест встраивания отвечали 200, даже если снять лишние места не удалось. POST /v1/placements/unbind удалял место встраивания из списка приложения, не дождавшись подтверждения от аккаунта.

Стало

Снятие с публикации по-прежнему отвечает 200 и переводит приложение в UNPUBLISHED, но placements теперь содержит коды, снять которые не удалось, а warnings — причину по каждому. Публикация и PATCH при неподтверждённом снятии отвечают 502 с кодом PLACEMENT_UNBIND_FAILED и списком кодов в error.placements; приложение при этом не публикуется и метаданные каталога не сохраняются. Отвязка одного места встраивания при неподтверждённом ответе аккаунта отвечает 502 с кодом BITRIX_UNAVAILABLE и оставляет место в списке приложения.

Отдельно: POST /v1/apps/{id}/publish и PATCH /v1/apps/{id} начали отвечать 503 с кодом NETWORK_DEVKEY_REQUIRED, если аккаунт переведён на транспорт ключа разработчика, а у автора приложения такого ключа нет. Раньше этот код у обеих ручек не встречался.

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

Возможность раскатывается постепенно и включается по аккаунтам: до включения на вашем аккаунте все четыре эндпоинта ведут себя как прежде, неподтверждённое снятие по-прежнему выглядит успехом, а коды PLACEMENT_UNBIND_FAILED и NETWORK_DEVKEY_REQUIRED не встречаются вовсе. Код BITRIX_UNAVAILABLE на отвязке одного места был и до включения — меняется только его условие: после включения им же отвечает неподтверждённое снятие. После включения проверяйте placements в ответе снятия с публикации: пустой список означает, что снято всё. На 502 с кодом PLACEMENT_UNBIND_FAILED повторите запрос — перечисленные места встраивания на аккаунте остались. Если сценарий полагался на 200 как на признак снятия, замените проверку на пустоту placements. На 503 с кодом NETWORK_DEVKEY_REQUIRED повтор не поможет: попросите автора приложения переподключить аккаунт.

Затронутые эндпоинты: POST /v1/apps/{id}/publish, POST /v1/apps/{id}/unpublish, PATCH /v1/apps/{id}, POST /v1/placements/unbind

NEW-0819-12: коробочный портал может подключить демо Маркетплейса

Было

POST /v1/portals/{id}/activate-market-trial и POST /v1/cowork/activate-market-trial отказывали коробочному порталу всегда: 409 TRIAL_ACTIVATION_UNAVAILABLE, причина недоступности в /v1/cowork/state — not_cloud. Демо Маркетплейса было доступно только облачным порталам.

Стало

Коробочный портал активирует демо через те же ручки. Доступность решает Битрикс24 по лицензии коробки, поэтому причина отказа стала точнее: demo_used, когда демо выдать нельзя, и not_supported, пока доступность ещё не прочитана. Ответы и коды ошибок не менялись.

Возможность включается постепенно и по умолчанию выключена.

BC-0819-13: разбор тела запроса у POST /v1/cowork/deploy-key

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

Было

Запрос с заголовком Content-Type: application/json и пустым телом отвечал 400. Запрос с заголовком Content-Type: text/plain и непустым телом принимался.

Стало

Пустое тело принимается с любым заголовком: ручка тело не читает. Непустое тело неизвестного типа отвечает 415.

Что делать

Убрать Content-Type: text/plain из вызова либо не передавать тело. Прежнее поведение снимается в момент выката, окна поддержки нет.

NEW-0819-14: отзыв ключа устройства Cowork/Code самим ключом

Было

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

Стало

Появился DELETE /v1/cowork/key. Ручка гасит предъявленный ключ — идентификатор не передаётся, поэтому отозвать чужой ключ нельзя. Нужны скоуп vibe:cowork и ключ класса десктопа Cowork/Code, иначе 403 COWORK_DESKTOP_KEY_REQUIRED; без скоупа — 403 INSUFFICIENT_SCOPE. Повторный вызов тем же секретом отвечает 401 KEY_INACTIVE. Темп — 5 запросов в минуту на ключ, сверх лимита 429 RATE_LIMITED.

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