Для 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.
Ручка работает и при нулевом балансе, и при исчерпанной суточной квоте: аварийный выход не запирается.