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

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

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

FIX-0803-1: переоткрытие архивированного тикета тоже очищает штамп решения

Было

Переоткрытие тикета из статуса ARCHIVED в активный (NEW/REVIEWING/AWAITING_USER/NEEDS_REVIEW) — через PATCH /v1/feedback/:id или POST /v1/feedback/:id/comments — не сбрасывало resolvedAt/resolvedBy, если тикет ранее был решён и затем заархивирован. На чтении (GET /v1/feedback/:id) такой тикет выглядел активным и решённым разом. Сброс срабатывал только для источников RESOLVED/WITHDRAWN.

Стало

ARCHIVED присоединён к RESOLVED/WITHDRAWN: переоткрытие из любого закрытого статуса в активный очищает resolvedAt/resolvedBy. На PATCH-пути очищается и resolution (в том числе причина архива) — активный тикет решения не несёт; явный resolution в том же запросе имеет приоритет. На пути комментария resolution равен телу коммента. Переход в ARCHIVED штамп по-прежнему сохраняет (архивирование хранит историю решения).

FIX-0803-2: пропавшие байты вложения отдаются как 404, а не как оборванный ответ

GET /v1/feedback/{id}/attachments/{attId}/file и .../thumb теперь проверяют наличие байтов до отправки заголовков. Если запись о вложении есть, а самих байтов в хранилище нет (последствие ручной уборки или каскадного удаления), ответом будет обычный 404 NOT_FOUND.

Было

Ответ начинался как 200, а затем обрывался посреди тела: клиент получал усечённую картинку или пустой поток с уже отправленным успешным статусом, и отличить это от медленной сети было нечем.

Стало

404 { "success": false, "error": { "code": "NOT_FOUND", "message": "Not found" } } — тот же код, что и для чужого или удалённого вложения. Клиентам, которые уже обрабатывают 404 на этих маршрутах, менять ничего не нужно.

Формат ответов и адреса маршрутов не изменились.

FIX-0803-3: создание сервера честно сообщает, что вернуло уже существующий сервер приложения

Если ключ вызова принадлежит приложению, у которого слот сервера уже занят, POST /v1/infra/servers возвращает этот сервер вместо создания нового. Так было и раньше, но узнать об этом из ответа было почти нечем: единственным признаком было недокументированное поле reused, а имя в ответе принадлежало существующему серверу, а не запрошенному.

Теперь такой ответ несёт полное раскрытие: data.reusedReason со значением APPLICATION_ALREADY_HAS_SERVER, data.requestedName с эхом переданного вами name (всегда, даже если оно совпадает с именем существующего сервера) и массив warnings рядом с data минимум с одной записью — она называет существующий сервер и предупреждает, что деплой заменит работающий на нём код. Поля reused и deploying теперь описаны в схеме и в документации.

Точно так же раскрывается и вторая молчаливая потеря: переданные displayName и description переиспользование не применяет — сервер сохраняет собственные имя и описание. Теперь это видно по data.metaIgnored и отдельному предупреждению; переименовать сервер можно осознанно через PATCH /v1/infra/servers/:id.

Если в запросе был передан source, а развернуть его в переиспользуемый сервер нельзя (у galaxy-приложения уже есть работающий контейнер, либо это отдельная виртуальная машина), архив отбрасывается — и теперь ответ говорит об этом полем data.sourceIgnored и отдельным предупреждением. Раньше архив отбрасывался молча.

data.next в reuse-ответе теперь приходит только тогда, когда перезаписывать нечего. Раньше поле приходило на любом двухшаговом reuse — в том числе когда возвращённый сервер уже выполнял чужой код, и машинное «следующий шаг — деплой» противоречило подсказке в том же теле. Если сервер может выполнять код, next отсутствует намеренно: сначала убедитесь, что сервер тот. Отсутствие next — не ошибка.

Два прежних поля изменились по смыслу, хотя менять клиентский код не нужно: data.hint на reuse-ответе переписан целиком — вместо «задеплойте сюда» он теперь начинается с REUSED — no new server was created и объясняет, чем это чревато; а описание data.next в схеме исправлено — раньше оно называло единственной причиной появления поля пустой galaxy-слот, хотя next приходит и на reuse-ответе. Прежние поля и коды не изменились, менять ничего не нужно. Но перед вызовом POST /v1/infra/servers/:id/deploy читайте reused: деплой заменяет то, что уже работает на сервере.

NEW-0803-4: справочник значений списочных свойств каталога

Появилась сущность catalog-product-property-enums — все возможные варианты свойства-списка торгового каталога: GET /v1/catalog-product-property-enums, GET /v1/catalog-product-property-enums/:id, POST /v1/catalog-product-property-enums/search и GET /v1/catalog-product-property-enums/fields. Сущность только для чтения: записывающие операции и агрегация не зарегистрированы и отвечают 404, а data.batch приходит пустым массивом.

Раньше значение списочного свойства у товара можно было получить только как идентификатор варианта: семейство /v1/products отдаёт в PROPERTY_<N> объект с числовым value, а GET /v1/products/fields описывает свойство только именем — развернуть идентификатор в текст было нечем. Теперь список вариантов запрашивается напрямую: GET /v1/catalog-product-property-enums?filter[propertyId]=166&limit=1000 возвращает пары «идентификатор — читаемый текст», по которым строится карта String(id) → value.

Фильтр filter[propertyId] обязателен: справочник читается по одному свойству за раз, запрос без него отклоняется с 400 MISSING_REQUIRED_FILTER до обращения к Битрикс24 — на списке и поиске. Проверка смотрит на наличие ключа и не распространяется на подвызовы пакетного запроса. Перечисление есть только у свойств с propertyType: "L" — у свойства любого другого типа ответ будет пустым списком, а не ошибкой. Пагинация обычная: limit + offset, конец выборки — по meta.hasMore. Потолок — 5000 записей за вызов. Нужен скоуп catalog.

Заодно уточнены существующие страницы. GET /v1/catalog-products/:id теперь показывает захваченный ответ со списочным свойством и разбор тройки value / valueEnum / valueId, а также форму значения при listType: "C" — голый скаляр "Y"/"N", то есть состояние галочки, а не id варианта. GET /v1/products/:id объясняет, что пустое значение свойства означает либо незаполненное свойство, либо свойство, обслуживаемое только каталожным семейством, и как различить эти случаи одним перекрёстным вызовом. GET /v1/products/fields прямо говорит, что дескриптор PROPERTY_<N> несёт только название и куда идти за значениями. В справочнике ошибок исправлен перечень сущностей с обязательным фильтром.

FIX-0803-5: Обращения в поддержку работают при заморозке баланса

Было

На аккаунте, замороженном из-за баланса, все ручки /v1/feedback возвращали 402 ACCOUNT_FROZEN — сообщить о проблеме из продукта было нельзя ровно в тот момент, когда это нужнее всего.

Стало

По ключу доступна вся переписка: POST /v1/feedback (создать), GET /v1/feedback (список), GET /v1/feedback/{id} (открыть обращение) и POST /v1/feedback/{id}/comments (ответить команде). Все четыре читают и пишут только ваши же данные. Запись вложений (POST /v1/feedback/attachments), их скачивание и PATCH /v1/feedback/{id} остаются под гейтом заморозки, как и остальные /v1-эндпоинты.

FIX-0803-6: include возвращает полную связанную запись, а не только метаданные

Было

При ?include=<relation> во вложенном объекте приходили только метаданные связи — без id и полей связанной записи.

Стало

include возвращает полную связанную запись (id + поля), как и описано в контракте — отдельный запрос за связанной сущностью больше не нужен.

FIX-0803-7: методы дашборда Открытых линий в раскатке возвращают METHOD_NOT_YET_AVAILABLE

Было

На портале, куда обновление ещё не приехало, методы дашборда Открытых линий отдавали сырой 422 BITRIX_ERROR — по нему нельзя было отличить «метод раскатывается» от реальной ошибки интеграции.

Стало

Такой ответ распознаётся и возвращается как 422 METHOD_NOT_YET_AVAILABLE с версией релиза — понятный сигнал, что метод пока не доступен на этом портале, а не сбой интеграции. Ответ не меняется и при регулярном опросе: такие вызовы больше не засчитываются в защиту от петли ошибок, поэтому вместо понятного 422 не приходит 429 ERROR_LOOP_DETECTED (для методов, которые не раскатываются, защита работает как раньше).

FIX-0803-8: запись исходников в хранилище возвращает точные коды ошибок вместо общего 500

Было

Клиентские сбои записи в хранилище исходников маскировались общим 500 SOURCE_STORAGE_ERROR — по нему нельзя было понять, что делать.

Стало

Причина различима: при недостатке средств на балансе — 402 BILLING_INSUFFICIENT, при временном сбое выдачи ключей доступа к хранилищу — 503 STORAGE_STS_UNAVAILABLE (можно повторить запрос). Таблица кодов на странице source-storage дополнена.

FIX-0803-9: список значений в фильтре statuses отклоняется чистым 400, а не 500

Было

GET /v1/statuses со списком значений в фильтре ({поле: {$in: [...]}} или массив) уходил в Bitrix24, и метод справочника отвечал по-разному в зависимости от поля: по id и name — внутренней ошибкой, которая доезжала до клиента как 502 BITRIX_UNAVAILABLE, по entityId, statusId, semantics и sort — ошибкой «значение должно быть строкой», а по categoryId — успешным ответом с записями чужой воронки.

Стало

Список значений отклоняется до вызова Bitrix24 с 400 UNSUPPORTED_FILTER по любому полю фильтра: метод справочника не поддерживает его нигде. Принимается одно точное значение ({поле: значение}); несколько значений запрашивайте отдельными вызовами или через POST /v1/batch.

FIX-0803-10: /v1/tasks/:taskId/time принимает ключ со скоупом task

Было

Эндпоинт учёта времени задачи возвращал 403 INSUFFICIENT_SCOPE ключу со скоупом task — работал только tasks, хотя это алиасы одного разрешения.

Стало

task и tasks трактуются как алиасы (как на всех остальных task-эндпоинтах) — ключ с любым из них проходит.

NEW-0803-11: одношаговое создание galaxy-приложения принимает `healthPath`

Тело POST /v1/infra/servers с полем source теперь принимает необязательное поле healthPath — путь, по которому проверяется готовность приложения внутри контейнера. Валидация та же, что у POST /v1/infra/servers/{id}/deploy: строка до 500 символов, начинается со /. Значение по умолчанию — /.

Раньше healthPath был объявлен только в теле деплоя, поэтому одношаговый вызов, который платформа сама рекомендует в GET /v1/me, отвечал 400 UNKNOWN_PARAM — а описание в /v1/me при этом называло healthPath поддерживаемым на галактическом пути. Поле принято именно там, где рекомендация его обещает; на создании отдельного сервера оно игнорируется.

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

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

FIX-0803-12: `/start` и `/wake` у galaxy-приложения объясняют, почему они не применимы

Было

POST /v1/infra/servers/{id}/start и POST /v1/infra/servers/{id}/wake проверяли статус раньше типа сервера, поэтому galaxy-приложение вне списка разрешённых статусов (например RUNNING, ERROR или STOPPED) получало текст про standalone-сервер: «Server is RUNNING; /start requires one of SLEEPING, ERROR, PROVISIONING». Формально верно и бесполезно: перечисленные статусы тоже не помогли бы, а о том, что у приложения-контейнера вообще нет облачной машины, не говорилось ничего.

Стало

Проверка типа идёт первой — как в /reboot. Для galaxy-приложения в таком статусе message называет причину («это galaxy-приложение, у него нет облачной машины»), а userMessage называет операции, которые действительно работают: POST /v1/infra/servers/{id}/deploy (годится в любом из этих статусов) и POST /v1/infra/servers/{id}/reboot (только для запущенного или упавшего приложения). Код ошибки не меняется — по-прежнему SERVER_WRONG_STATE (422) с полями currentState и availableActions.

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

Ничего менять не нужно: HTTP-статус и код те же, изменился только текст. Ответ для статусов ИЗ списка разрешённых остался прежним побайтово — в частности, /start и /wake для спящего galaxy-приложения по-прежнему отвечают задокументированным VM_MISSING.

FIX-0803-13: причина падения galaxy-приложения называется прямо в `provisionError`

Было

Когда приложение собиралось, запускалось и тут же падало, provisionError содержал только обобщённый вывод: «приложение не удержалось, смотрите логи» или, если сработал признак нехватки памяти, «вероятно, превышен лимит памяти галактики». Настоящая причина — например TypeError: webidl.util.markAsUncloneable is not a function из-за несовместимой версии среды — лежала в buildLog, а в списке серверов виден только provisionError. Поэтому по короткому тексту нельзя было понять, дело в памяти или в коде, и совет «перейдите на отдельный сервер» отправлял по ложному пути.

Стало

К той же формулировке дописывается строка из логов контейнера: … Actual cause from the container logs: <строка>. Строка выбирается из хвоста, который платформа снимает при отказе: сначала типизированное исключение или код ошибки (TypeError: …, EADDRINUSE, FATAL ERROR: … heap out of memory), затем известные причины сборки, затем последняя строка с признаком ошибки. Хвост проходит ту же очистку, что и buildLog — внутренние пути хоста заменяются на <build-context>. Если полезной строки в хвосте нет, текст остаётся прежним. Формулировка про память сохраняется и дополняется причиной: признак oom иногда срабатывает и там, где память ни при чём, и тогда приклеенная строка — единственная правда, которую видит читатель.

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

Ничего менять не нужно. Прежние подстроки в тексте сохранены, поэтому клиент, который сопоставлял их, продолжает работать; появился только дописанный хвост. Полный лог по-прежнему доступен в buildLog (GET /v1/infra/servers/{id}).

FIX-0803-14: `/reboot` спящего galaxy-приложения запускает починку хоста и говорит об этом

Было

У спящего galaxy-приложения, чей хост потерял туннель, не было пути обратно. Задокументированный способ разбудить приложение — деплой, а деплой на недостижимый хост падает. Починка туннеля хоста при этом уже запускалась из перезапуска приложения, но запуск лежал ЗА проверкой статуса, которая спящее приложение отклоняет, — то есть до починки дело не доходило.

Стало

Перед тем же отказом 422 SERVER_WRONG_STATE платформа запускает фоновую починку туннеля хоста и, если починка действительно началась, добавляет в ответ необязательный объект hint с полями reason, recovery (какую операцию повторить) и retryAfterSeconds (нижняя граница ожидания, не обещание). Если починка не началась — сработал рубильник, туннель на самом деле жив, ремонт уже идёт или машина заблокирована для пробуждения, — hint отсутствует: сообщать о запуске, которого не было, нельзя.

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

Ничего менять не нужно: код и HTTP-статус те же, hint аддитивен. Клиенту, который читает hint, достаточно повторить POST /v1/infra/servers/{id}/deploy через названное время.

FIX-0803-15: zip-архив в исходниках galaxy-приложения больше не падает на распаковке

Было

Платформа определяет формат архива по его первым байтам и заявляет .zip поддерживаемым, но на галактическом пути (POST /v1/infra/servers с полем source и POST /v1/infra/servers/{id}/deploy для galaxy-приложения) архив передавался на распаковку без подготовки хоста. Если распаковщик на хосте отсутствовал, деплой падал с текстом вида exec: "unzip": executable file not found in $PATH — из него не следовало ни что делать, ни что тот же архив в .tar.gz прошёл бы.

Стало

Перед загрузкой zip-архива платформа доустанавливает распаковщик на хосте (тот же шаг уже выполнялся на отдельном сервере). Шаг идемпотентен: если распаковщик уже есть, он ничего не делает, и на повторных деплоях времени не занимает. Если установить не удалось, архив не загружается вообще, а деплой завершается отказом с честной причиной и подсказкой прислать тот же исходник как .tar.gz; текст доступен в buildLog и в provisionError.

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

Ничего менять не нужно. Деплои с .tar.gz идут прежним путём без изменений.

NEW-0803-16: Версия исходников принимает до 500 МБ, а деплой по нашей ссылке линкуется к версии на любом ключе

Было

Архив можно было сохранить версией только до 200 МБ, при том что тот же архив разрешалось передать прямо в теле деплоя до 500 МБ. Крупный проект деплоился единственным способом — целиком в теле запроса.

Отдельно: деплой формы {"source": {"url": "…"}} по ссылке, полученной из GET /v1/infra/servers/:id/sources/:versionId/download, не связывался с версией, если сервер принадлежит персональному ключу vibe_api_*. В ответе приходило data.source.autoSaved: false и skippedReason: "external-url-or-toggles-off", а у версии оставались пустыми linkedDeployId и deployStatus.

Стало

Потолок версии исходников — 500 МБ на обоих приёмных эндпоинтах: POST /v1/infra/servers/:id/sources и POST /v1/apps/:id/sources. Тело по-прежнему принимается потоком, поэтому размер архива не влияет на скорость приёма. Заявленная в Content-Length длина сверх потолка отбивается кодом 413 до чтения тела. Значение публикуется в capabilities.apps.sourceStorage.limits.maxBlobBytes у GET /v1/me — теперь 524288000.

Деплой по нашей ссылке связывается с версией независимо от типа ключа-владельца сервера: ответ несёт data.source.autoSaved: true и savedVersionId, а у версии заполняются linkedDeployId и deployStatus.

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

FIX-0803-17: отзыв доступа гасит все ключи связки, а не только последний

Было

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

Стало

Отзыв доступа гасит все ключи, которые пользователь выдал приложению для этого портала, включая ключи прежних авторизаций. Ключ, переживавший отзыв, теперь отвечает 401 KEY_INACTIVE. Ключи других сотрудников того же портала не затрагиваются. Партнёру достаточно штатной обработки 401 KEY_INACTIVE — предложить пользователю повторно авторизоваться.