Для AI-агентов: markdown этой страницы — /docs-content/changelog/2026-08-18.md индекс документации — /llms.txt
Изменения API: 18 августа 2026
← Журнал изменений · Август 2026
BC-0818-1: контракт управления приложениями и исходниками уточнён
Поддержка старого формата до: не предусмотрена
Было
OpenAPI не описывал точные успешные ответы, лимиты метаданных и часть кодов ошибок для операций хранилища исходников приложений. OAuth-ключ одного приложения мог изменить другое приложение, а также читать и изменять исходники сервера того же автора, принадлежавшего другому ключу. Лимит примечания считал UTF-16 code units, поэтому часть допустимых строк с Unicode отклонялась. Временная ссылка на скачивание могла сохраняться промежуточным кешем.
Стало
Контракт восьми операций описывает фактические схемы ответов, лимиты, коды ошибок и матрицу доступа. OAuth-ключ приложения теперь может напрямую управлять только своим приложением и обращаться к исходникам сервера, принадлежащего этому же ключу. При публикации собственного приложения явный sourceServerId может выбрать сервер того же автора под личным ключом, но не сервер другого OAuth-приложения. Личные ключи автора и ключи администратора сохраняют доступ. Лимит примечания считается по Unicode code points. Ответы с временными ссылками приложения и сервера помечены Cache-Control: private, no-store, а ссылка и содержащийся в ней путь хранилища явно обозначены как краткоживущий bearer credential.
Переходное окно не предоставляется: прежний доступ OAuth-ключа приложения к ресурсам другого ключа был дефектом разграничения доступа.
FIX-0818-2: `?refresh=tariff` у коробочного портала освежает и состояние подписки Маркетплейса
Было
GET /v1/me?refresh=tariff у коробочного портала перепроверял тариф, но состояние подписки Маркетплейса отдавал из прошлого снимка. Клиент, оплативший подписку прямо перед вызовом, продолжал получать прежний ответ, пока состояние не обновит фоновая проверка.
Стало
Запрос перепроверяет и это состояние, а ответ собирается уже по свежим данным. Оплата, прошедшая перед вызовом, видна сразу.
NEW-0818-3: состав рабочей группы с ролями участников
Появился эндпоинт GET /v1/workgroups/:groupId/users — он возвращает участников рабочей группы вместе с их ролью в ней. Раньше фасад /v1/workgroups отдавал только владельца и число участников, поэтому приложение, которому нужно различать руководителя, модератора и рядового участника, сделать это не могло.
Каждая строка ответа несёт userId и role. Поле role содержит букву Битрикс24 как есть: A — владелец, E — модератор, K — участник. Незнакомая буква проходит насквозь, а не приводится к известной и не отбрасывается, поэтому проверяйте те значения, которые знаете, а всё остальное трактуйте как отсутствие прав.
Параметров постраничной выдачи у операции нет, состав возвращается целиком, и meta.total всегда равен числу строк в data. Пустой состав — обычный ответ, а владелец группы не обязательно присутствует среди строк: его идентификатор берите из GET /v1/workgroups/:id. Ответ 404 означает, что группы нет либо она не видна той учётной записи Битрикс24, от имени которой действует ключ, — Битрикс24 не различает эти случаи.
Эндпоинт отдаёт данные о составе, а не решение о доступе: что именно он покажет, зависит от личности за ключом, а признак администратора портала — отдельный факт, его отдаёт GET /v1/users/me. Вложенные ресурсы недоступны через POST /v1/batch, поэтому операция вызывается только по своему пути. Нужен скоуп sonet_group.
FIX-0818-4: сделки: семь полей из GET /v1/deals/fields теперь принимаются в фильтре
Было
GET /v1/deals/fields перечислял поля, которые фильтр не принимал. Запрос
POST /v1/deals/search с filter[leadId], filter[quoteId], filter[taxValue],
filter[originId], filter[originatorId], filter[additionalInfo] или
filter[lastActivityBy] отклонялся с 400 UNKNOWN_FILTER_FIELD ещё до обращения к Битрикс24, хотя Битрикс24 эти поля
в фильтре принимает. Отчёт, отбирающий сделки по лиду, построить было нельзя.
Стало
Все семь полей объявлены в схеме сделок и принимаются в filter — и в
GET /v1/deals, и в POST /v1/deals/search, и в POST /v1/deals/aggregate.
В select они принимались и раньше, но с предупреждением
UNKNOWN_SELECT_FIELD — теперь предупреждения нет. Сортировка по ним работала
и до этого изменения и не менялась. Имена полей в ответах прежние. Набор осей
группировки groupBy не менялся.
Два уточнения по значениям. У leadId, quoteId, originId, originatorId
и additionalInfo в GET /v1/deals/fields и в OpenAPI теперь стоит
nullable — эти поля возвращают null у сделки, которая не создавалась из
лида, из предложения или импортом. Раньше их в спецификации не было вовсе,
так что клиент, сгенерированный по ней, обязан быть готов к null. И у трёх
строковых полей (originId, originatorId, additionalInfo) пустая строка
от Битрикс24 приводится к null — так же, как у всех остальных строковых
полей API. На замере 300 сделок пустая строка не встретилась ни разу, Битрикс24
отдаёт по этим полям null, поэтому смены поведения на реальных данных мы не
ожидаем; но если ваш код сравнивает такое поле с "", сравнивайте с пустым
значением.
Шесть полей — utmSource, utmMedium, utmCampaign, utmContent, utmTerm
и contacts — по-прежнему отклоняются в фильтре и сортировке: Битрикс24 сам их
там не поддерживает. Отказ оставлен намеренно, иначе выборка была бы молча
неверной. Теперь причина видна заранее — GET /v1/deals/fields описывает её в
поле description. Для контактов фильтруйте по contactId (основной контакт) или по contactIds (любой из привязанных).
У лидов, предложений и элементов смарт-процессов пять UTM-полей остаются
доступны в ответах, но больше не проходят локальную проверку фильтра и
сортировки: Битрикс24 не принимает их в crm.item.list. Вместо ошибки
Битрикс24 422 запрос теперь заранее получает 400 UNKNOWN_FILTER_FIELD или
400 UNKNOWN_SORT_FIELD, не обращаясь к Битрикс24. Остальные операции с этими
полями не изменились.
FIX-0818-5: пустой результат методов рабочего дня возвращается как null
Было
При пустом успешном результате Битрикс24 поле data могло содержать служебную оболочку с полями result, total и next вместо значения результата.
Стало
POST /v1/workday/open, POST /v1/workday/close, POST /v1/workday/pause, GET /v1/workday/status, GET /v1/workday/settings и GET /v1/workday/schedule возвращают data: null, если успешный результат пуст.
Влияние на интеграторов
Клиентам не требуется извлекать пустое значение из служебной оболочки ответа Битрикс24.
NEW-0818-6: справочник полей заказов и статусов заказа отдаёт названия и пояснения
Было
GET /v1/orders/fields и GET /v1/order-statuses/fields отвечали на каждое поле только типом и флагом только-для-чтения. Ни человекочитаемого названия, ни пояснения не было — всего 54 поля, по которым клиент мог опираться только на имя поля. Сгенерировать по такой схеме форму или типизированную модель было нечем: имя вроде recountFlag или empStatusId само по себе ничего не объясняет.
Стало
Каждое поле обеих сущностей несёт label (короткое название) и description (пояснение) на языке сегмента. Пояснение говорит то, чего не передаёт тип: почему price принимается только при создании (Битрикс24 пересчитывает сумму из позиций корзины), что requisiteLink приходит пустым массивом, когда связь не задана, что clients, payments, basketItems и propertyValues возвращаются только в карточке заказа, и что Битрикс24 требует поле type при каждом обновлении статуса. Ответ вырос, набор полей и их типы не изменились — старые запросы работают как прежде.
NEW-0818-9: промокод в приложении Cowork/Код: проверка кода и погашение по ключу десктопа
Приложение Cowork/Код теперь принимает промокод само, не отправляя человека в кабинет. Появились два метода: POST /v1/cowork/coupon/preview показывает, что даёт код (тариф, срок, название кампании), ничего не меняя, а POST /v1/cowork/coupon/redeem его гасит и включает подаренный тариф на срок, оплаченный платформой Вайбкод.
Оба метода требуют ключ десктопа Cowork/Код с доступом vibe:cowork. Агентский ключ с тем же доступом получит 403 COWORK_DESKTOP_KEY_REQUIRED: погашение необратимо и одноразово, а за таким ключом нет человека, который принимает решение.
Проверка отвечает 200 и в теле сообщает valid: false с причиной COUPON_INVALID, если код не годится. Причина одна на все случаи «код не подходит» — так метод не подсказывает подбирающему, чем именно отличается несуществующий код от отозванного. Годность здесь означает «код живой и кампания открыта»: условия самого рабочего места (уже оплачено, уже этот тариф) проверяются при погашении и могут дать отказ после успешной проверки.
Погашение возвращает выданный тариф, срок и поле accessGranted. false означает, что тариф выдан, но администратор портала ещё не открыл доступ к Cowork/Код — покажите это отдельно, иначе человек увидит успех и упрётся в закрытую дверь.
Затронутые эндпоинты: POST /v1/cowork/coupon/preview, POST /v1/cowork/coupon/redeem
NEW-0818-10: витрина приложений в API: список и карточка
В API Вайбкод появилось семейство приложений: GET /v1/applications отдаёт список, GET /v1/applications/:id — одну карточку. Выборка идёт по владельцу ключа, а не по самому ключу, поэтому в список попадают и приложения, созданные в кабинете, — их серверы привязаны к другим ключам того же человека и в GET /v1/infra/servers не видны.
Параметр scope принимает mine (свои), shared (доступные вам чужие — как открытые лично вам, так и открытые всему порталу) и feed (общий список, значение по умолчанию), плюс постраничные page и limit. Карточка доступна и получателю доступа, а не только владельцу; отношение зрителя к приложению приходит в поле viewerState.
Рядом с total в ответе списка приходит truncated. У скоупа feed порядок приложений считает платформа, поэтому выборка ограничена сверху: при truncated: true значение total — это тот предел, а не полное число приложений, и страниц за ним нет. Считать число страниц как total / limit можно, только когда truncated равно false; при true за остатком следует идти в скоупы mine и shared, у которых предела нет.
Каждая карточка несёт два дополнительных блока. sources сообщает, есть ли сохранённые версии исходников, и отдаёт идентификатор последней в том же виде, который принимает скачивание версии, — обращаться за списком версий заранее не нужно. activeOperation показывает идущую операцию: вид, шаг и время старта; значение unknown означает, что операция начиналась, но её исход неизвестен. Оба блока наполняются только для того, кто приложением управляет: у зрителя, которому приложение просто открыли, sources приходит пустым (hasVersions: false, оба поля null), а activeOperation — null. Форма ответа при этом не меняется, поэтому важно не сделать неверный вывод: пустой sources у чужого приложения означает «эти данные не отдаются», а не «версий нет».
Важная оговорка про activeOperation: null означает «операции с сохранённой записью нет», а не «с приложением ничего не происходит». Признак покрывает выкладку, починку, изменение тарифа сервера и перенос контейнера между галактиками — остальные действия платформа не журналирует и в этом поле не показывает.
Открывать приложение не нужно вычислять самому: карточка отдаёт готовую пару openUrl и openTarget. Значение openTarget сейчас одно — app, то есть открывается собственный адрес приложения; оба поля null, когда открывать нечего. Список значений закрытый и может пополниться, поэтому неизвестное значение стоит трактовать как «открывать нечем», а не как ошибку.
⚠️ У приложения, встроенного в Битрикс24, оба поля приходят null — платформа пока не знает адреса, по которому его открывают внутри портала. Собственный адрес такого приложения в openUrl намеренно НЕ подставляется: он ведёт на страницу входа шлюза, а не в приложение, и переход по нему выглядел бы удачным, не будучи им.
Различить эти два состояния — «встроено, открывается внутри Битрикс24» и «ещё не опубликовано» — позволяет поле isEmbedded: у обоих пара открытия пуста, а тексты для пользователя разные. Выводить встройку из наличия сервера НЕЛЬЗЯ: встроенное приложение без собственного сервера — штатное состояние (встройку сделали, код ещё не выкладывали), и признак от сервера не зависит вовсе. Поле приходит и владельцу, и тому, кому приложение открыли.
У сервера появился признак reachable — true, когда сервер и работает, и отвечает по сети. Отдельно от status, потому что это разные факты: сервер бывает поднят, а сетевой туннель до него не поднят, и по одному status такое приложение выглядит рабочим. Проверить это со стороны клиента нельзя, поэтому признак считает платформа.
Признак уже включает состояние RUNNING: истинным при другом состоянии сервера он не приходит, поэтому конъюнктить его со status не нужно. ⚠️ У приложения в галактике (server.kind: "GALAXY_APP") вторая половина признака берётся с ХОСТА галактики, а не с самого контейнера — связность держит хост, у контейнера своего туннеля нет по устройству. Отсюда следствие, о котором лучше знать заранее: только что созданный контейнер, ещё не дошедший до RUNNING (а доходит он лишь после первой загрузки исходников), приедет с reachable: false даже при полностью живом хосте. Это означает «контейнер пока не поднялся», а не «хост недоступен» — различить два случая по одному признаку нельзя, для этого есть status.
У сервера появилось поле lastDeployedAt — момент последней успешной выкладки. Это единственный в разделе признак того, что приложением живут: updatedAt двигает только правка карточки, а sources.latestSavedAt означает «код сохранён» и приходит лишь тому, кто приложением управляет. Отметку ставит сама выкладка в момент фиксации успеха, поэтому провалившаяся выкладка её не двигает. ⚠️ Истории у поля нет: у серверов, созданных до появления поля, оно приходит null до первой следующей выкладки — восстанавливать историю мы не стали, потому что доступный источник покрывает только один из трёх путей выкладки, и дата появилась бы у одних видов серверов и отсутствовала у других.
Ещё две вещи, о которых лучше знать заранее. id приложения из этого раздела и id из GET /v1/apps — разные значения разных сущностей: здесь карточка приложения, там регистрация приложения на портале Битрикс24. И одно и то же по смыслу название приходит в них под разными именами: name здесь и title там. Переносить одно в другое нельзя, поля не синхронизируются.
Порядок в списке назван прямо, чтобы постраничный обход был воспроизводимым. У скоупа feed: закреплённые вами → свои → чужие, внутри по updatedAt от свежих к старым, при равных метках — по id. У mine и shared: по createdAt от свежих к старым, при равных метках — по id. Вторичный ключ здесь не формальность: у приложений, созданных пакетно, метки времени совпадают, и без него две страницы одного обхода могли пересечься или пропустить приложение. ⚠️ updatedAt двигается только правкой карточки — выкладка её не трогает, поэтому «свежесть» в ленте означает «когда карточку меняли», а не «когда приложение выкладывали».