# Изменения API: 23 сентября 2026

[← Журнал изменений](/docs/changelog) · [Сентябрь 2026](/docs/changelog/2026-09)

### NEW-0923-2: выключение и включение уведомлений чата

Новый эндпоинт [POST /v1/chats/:chatId/mute](/docs/chats/management/mute) выключает (`"mute": true`) или включает обратно (`"mute": false`) уведомления из чата. Настройка личная: она меняется у того пользователя, от имени которого идёт вызов. Чтобы поменять её сотруднику, открывшему ваше приложение, вызывайте эндпоинт с ключом приложения и сессией этого сотрудника. Поле `mute` обязательно, запрос без него отклоняется кодом `400 MISSING_PARAMS` до обращения в Битрикс24.

### BC-0923-3: создание сделки или лида со стадией не из справочника больше не отвечает успехом

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

**Было**

[POST /v1/deals](/docs/entities/deals/create) и [POST /v1/leads](/docs/entities/leads/create) со стадией, которой нет в справочнике аккаунта, отвечали `201`: Битрикс24 принимал запись и молча клал её на стадию по умолчанию. Так вели себя опечатка в `stageId`, другой регистр букв, лишние пробелы, стадия другой воронки без её `categoryId` и стадия сделки в `statusId` лида. Клиент видел успех, а запись лежала не там, куда просили. Остальные двери — `PATCH`, `/move`, пакетные записи и импорт — такую стадию уже отклоняли.

**Стало**

Перед записью стадия сверяется со справочником аккаунта буквально, как её сверяет сам Битрикс24: у сделки — со стадиями воронки из `categoryId` (без него — основной, `DEAL_STAGE`, для другой воронки — `DEAL_STAGE_{categoryId}` со стадиями вида `C{categoryId}:NEW`), у лида — со статусами `STATUS`. Стадии в справочнике нет — ответ `400 UNKNOWN_STAGE`, запись не создаётся. `message` называет ключ и справочник и подсказывает ближайшее точное написание либо `categoryId`, который нужно передать вместе со стадией другой воронки; `details.knownStages` перечисляет стадии справочника (до пятидесяти), `details.entityId` — какой справочник смотреть через `GET /v1/statuses?filter[entityId]=…`. Любое написание ключа, которое Битрикс24 читает как `STAGE_ID` или `CATEGORY_ID` (сырое `STAGE_ID`, `stage_id`, `StageId`), проверяется так же; при нескольких написаниях в теле действует последнее, и ошибка называет его в `details.field`. Список или объект вместо названия стадии под сырым написанием ключа — тоже `400 UNKNOWN_STAGE`, потому что Битрикс24 кладёт такую запись на стадию по умолчанию (под `stageId` / `statusId` его раньше отклоняет проверка формы — `400 INVALID_PARAMS`); отказ выносится без чтения справочника: `details.knownStages` пуст, `details.stageId` называет форму значения. Пустая стадия (`""`, `null`) по-прежнему не проверяется — запись ложится на стадию по умолчанию. Справочник читается один раз на аккаунт и воронку и хранится пять минут, поэтому обычное создание не стало дороже; если справочник прочитать не удалось или он пришёл неполным, запись выполняется как прежде. Стадия из справочника отвечает как раньше.

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

Проверьте, что стадии в ваших запросах совпадают со справочником буква в букву: `GET /v1/statuses?filter[entityId]=DEAL_STAGE` для основной воронки сделок, `DEAL_STAGE_{categoryId}` для остальных, `STATUS` для лидов. Стадию другой воронки передавайте вместе с её `categoryId`. Обрабатывайте `400 UNKNOWN_STAGE` — повторять запрос с той же стадией бессмысленно, выберите одну из `details.knownStages`.

### BC-0923-4: CRM_CREATE в конфигурациях открытых линий теперь принимает только поддерживаемые значения

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

**Было**

[POST /v1/openline-configs](/docs/openlines/config/create) и [PATCH /v1/openline-configs/:id](/docs/openlines/config/update) возвращали `200` для значений `contact`, `company` и других неподдерживаемых значений `crmCreate`, после чего Битрикс24 сохранял режим как `lead`.

**Стало**

Для `crmCreate` и его вариантов написания принимаются только точные строки `none`, `lead`, `deal`. Любое другое значение возвращает HTTP `400` с кодом `VALIDATION_ERROR` и сообщением с полем и полным списком допустимых значений. Запрос отклоняется до изменения конфигурации.

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

Передавайте только `none`, `lead` или `deal`. Клиентам, которые отправляли `contact` или `company`, нужно выбрать поддерживаемый режим и обрабатывать `400 VALIDATION_ERROR`.

### FIX-0923-5: Проверка имён полей при чтении реквизитов

**Было**

Некоторые несуществующие имена полей, включая `constructor`, `__proto__` и `toString`, ошибочно проходили проверку фильтрации и сортировки реквизитов.

**Стало**

Проверка полей теперь отклоняет унаследованные имена до обращения к Битрикс24: с `400 UNKNOWN_FILTER_FIELD` для фильтра и `400 UNKNOWN_SORT_FIELD` для сортировки. Порядок обработки запроса не меняется: разбор тела может отказать раньше проверки полей, а объект `order` по-прежнему имеет приоритет над `sort`. Допустимые поля и их поддерживаемые алиасы работают как прежде.

**Затронутый эндпоинт:** [GET /v1/requisite-presets/:presetId/fields](/docs/entities/requisite-presets/preset-fields/list).

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

Запросы с допустимыми именами полей менять не требуется.

### FIX-0923-6: Повторное использование сервера после перепривязки ключа

**Было**

Для приложений с ранее утраченной привязкой ключа повторный `POST /v1/infra/servers` мог пытаться создать ещё один сервер. При конфликте перепривязки сервер и карточка могли остаться связаны с разными ключами.

**Стало**

Конфликт перепривязки сохраняет прежнюю связь сервера и карточки целиком. Создание распознаёт единственный подходящий сервер приложения, уже управляемый текущим ключом, и восстанавливает пустую привязку. Ответ при повторном использовании остаётся HTTP 201 с `reused: true`. При конкурентном изменении привязки возвращается HTTP 409 `APPLICATION_REUSE_CONFLICT` с `retryable: true`; запрос можно повторить. `GET /v1/me` показывает необязательный `deployment.standalone.reuseTarget` и checklist для существующего сервера, не меняя привязки. `TRIAL_PORTAL_LIMIT` содержит `retryable: false` и подсказку без повторного создания.

### FIX-0923-7: Скобочная форма `order` и `scope` больше не даёт внутреннюю ошибку

**Было**

Запрос с параметром в скобочной форме, например `?order[x]=1` к [GET /v1/tasks/:taskId/history](/docs/task-history) или `?scope[x]=1` к `POST /v1/pages/:id/publication`, отвечал `500` вместо штатного ответа.

**Стало**

[GET /v1/tasks/:taskId/history](/docs/task-history) считает такой `order` неизвестным значением и сортирует по возрастанию, как без параметра; ответ остаётся HTTP 200. `POST /v1/pages/:id/publication` отклоняет такой `scope` с `400 INVALID_SCOPE` и показывает полученное значение в тексте ошибки, как для любого другого недопустимого `scope`.

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

Запросы со строковыми `order` и `scope` менять не требуется.

### FIX-0923-8: диагностика galaxy-приложения проверяет публичный адрес

**Было**

Блок `reachability` в ответе `GET /v1/infra/servers/:id` собирал вердикт `effectiveStatus` только
из состояния контейнера и маршрутизации на самой галактике. Оба факта измеряются на хосте, а
последний участок пути до `https://app-XXXX.vibecode.bitrix24.tech` — это туннель приложения на
шлюзе, и на хосте его не видно: запущенный юнит маршрутизации означает, что его запустили, а не
что он дозвонился до шлюза. Приложение, чей публичный адрес снаружи не отвечал, поэтому могло
приходить как `"effectiveStatus": "running"`.

**Стало**

Вердикт учитывает публичный вход, и рядом приходит новое поле `reachability.publicEntry` —
`live`, если у шлюза есть живой туннель на поддомен приложения, `no-tunnel`, если туннеля нет, и
`unknown`, если состояние шлюза узнать не удалось. Приложение с живым контейнером и активной
маршрутизацией, но без туннеля, отвечает `"effectiveStatus": "unreachable"`. Значение `unknown`
вердикт не ухудшает: «не смогли посмотреть» — это не «ничего не работает». Остальные значения
`effectiveStatus` и все прежние поля блока не изменились, запросы править не нужно. Описание
значений — [Сон и пробуждение Galaxy-приложения](/docs/infra/galaxy-sleep).

### FIX-0923-9: снятие доступа к серверу прекращает уже открытые сессии

**Было**

Пользователь, открывший приложение обычным путём, получал сессию браузера, и дальше она жила
сама по себе: снятие его записи из списка доступа
([DELETE /v1/infra/servers/{id}/access/{accessId}](/docs/infra/access/access-delete)) на неё не влияло. Та
же вкладка продолжала открывать приложение, а при активности пользователя срок сессии
продлевался — то есть доступ сохранялся неограниченно долго. Отказ приходил только новым входом.

**Стало**

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

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

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

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

### FIX-0923-10: Устаревшие GET-агрегаты сообщают о неполных данных

**Было**

`GET /v1/{entity}/aggregate` мог вернуть HTTP 200 с числами по части записей без признака неполноты.

**Стало**

Ответ остаётся HTTP 200. Прежние числовые поля и группировка сохраняются. В `data.meta` всегда присутствуют `recordsProcessed` и `truncated`. При известном общем числе записей добавляется `totalRecords`, при положительном недоборе — `recordsShortfall`, при ошибке страницы — безопасный образец `pageErrorSample` с `code` и `message`.

Частичный результат содержит `truncated: true` в `data`, каждом элементе `data.groups` и `data.total`, если есть группировка. Пометка группы означает неполноту общей выборки, а не доказанную потерю строк именно в этой группе. Добавляется `data.meta.warnings` с кодом `AGGREGATE_TRUNCATED`. В полном ответе условные пометки и предупреждение отсутствуют, а `data.meta.truncated` равно `false`.

Если общее число неизвестно, `totalRecords` и `recordsShortfall` отсутствуют. Явный признак неполноты сохраняется даже без количественной оценки потери. Операция `count` на этом GET-пути также считает прочитанные строки и может быть частичной. Прежний отказ HTTP 422 при превышении лимита в 10 000 записей и заголовки устаревания сохраняются.

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

Проверяйте `data.meta.truncated`, прежде чем считать числа окончательными. При частичном результате сузьте фильтр. Контракт POST-агрегации не изменился.

### BC-0923-11: fieldName при создании пользовательского поля проверяется до обращения к Битрикс24

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

**Было**

[POST /v1/userfields/:entity](/docs/userfields/crm/create) отправлял `fieldName` в Битрикс24 каким получил, не проверяя его. Пустая строка, `null`, число, массив или объект доезжали до портала, и что с ними будет, решала уже та сторона: пустое имя возвращалось ошибкой без кода — наружу `422 BITRIX_ERROR` с `b24Code: "0"`, по которому нельзя понять, что именно в запросе не принято, — а не-строковое значение могло быть приведено к строке и создать поле с мусорным именем под успешным ответом.

**Стало**

Значение проверяется до обращения к порталу: оно обязано быть строкой, в которой есть хотя бы один непробельный символ, иначе отказ `400 INVALID_FIELD_NAME`. Проверяется именно то значение, которое уедет в Битрикс24, — если тело несёт оба написания, `fieldName` и прямой аналог `FIELD_NAME`, в портал уходит последнее из них, его и судит проверка. То же правило распространилось на обязательный `userTypeId`, и для тел с ОДНИМ написанием не изменилось ничего: пропущенный или пустой тип, как и прежде, отбивается `400 MISSING_FIELD`. Разница только там, где тело несёт оба написания сразу — прежде судилось первое непустое, теперь то, которое уезжает в Битрикс24. Тело `{"userTypeId": "string", "USER_TYPE_ID": ""}` раньше доезжало до портала и возвращало его непрозрачный ответ, а теперь получает `400 MISSING_FIELD`; обратное тело `{"userTypeId": "", "USER_TYPE_ID": "string"}` раньше отбивалось `400 MISSING_FIELD`, а теперь создаёт поле с типом `string`. Формат имени по-прежнему за Битрикс24: префикс `UF_CRM_`, длину и набор символов проверяет он.

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

Вызовы с корректным `fieldName` не затронуты, как и вызовы вообще без этого ключа — там имя поля генерирует Битрикс24. Менять код нужно тем, кто подставлял в `fieldName` не строку, пустую строку или строку из одних пробелов: такой вызов теперь отвечает `400 INVALID_FIELD_NAME` вместо прежнего ответа. Под это попадает и имя из необрезанного пользовательского ввода или из ячейки выгрузки — обрезайте пробелы на своей стороне. Чтобы имя сгенерировала платформа, ключ не передают вовсе: пустая строка и `null` для этого не годятся.

### NEW-0923-12: карточка сервера отдаёт команду запуска, установки и порт последнего деплоя

Ответ [GET /v1/infra/servers/:id](/docs/infra/servers/get) дополнен тремя полями: `startCommand`, `installCommand`,
`deployPort` — снимок `start`/`install`/`port` из тела последнего УСПЕШНОГО
[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy). Для серверов без единого успешного деплоя все три
поля возвращают `null`. Участник команды разработки (`access.via: "collaborator"`) получает эти поля так же, как владелец.

### NEW-0923-13: в отказе по активным серверам приложения появился владелец сервера

В ответе `409 APP_HAS_ACTIVE_SERVERS` на [DELETE /v1/apps/:id](/docs/apps/delete) каждый элемент `details.servers` получил необязательное поле `ownerName` — имя владельца сервера либо `null`, если владельца у сервера нет. Раньше по такому ответу нельзя было понять, чей именно сервер мешает удалить приложение, и владельца искали вручную. Остальные поля элемента и код ошибки прежние, запросы старых клиентов работают как работали.

### BC-0923-14: повтор создания приложения Коворка после сетевого сбоя возвращает исход первой попытки — если он ещё свежий

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

**Было**

[POST /v1/cowork/applications](/docs/cowork/applications-create) после отказа при выписке ключа (например, недоступность Битрикс24 Нетворк на стадии обращения к порталу) навсегда занимал ключ идемпотентности: повтор с тем же `Idempotency-Key` отвечал общим `409 IDEMPOTENCY_KEY_ALREADY_USED` независимо от причины первого отказа, и восстановить заготовку было нельзя — но повтор тем же ключом гарантированно никогда не создавал дубликат: он либо реплеился в 409, либо не проходил вовсе.

**Стало**

Такой повтор в течение 20 минут после первого отказа получает ТОТ ЖЕ ответ, что и первая попытка — тот же HTTP-статус, тот же `error.code`, то же тело — с добавленным заголовком `Idempotent-Replayed: true`. Спустя 20 минут ключ идемпотентности забывается, и повтор с ним выполняется как совершенно новая попытка со всеми проверками заново. Если первый отказ произошёл ПОСЛЕ обращения к порталу (например, `502 BITRIX_UNAVAILABLE`), портал мог уже получить вебхук от первой попытки; повтор тем же ключом спустя 20 минут этого не проверяет и может выписать ВТОРОЙ ключ и создать вторую заявку поверх первой. `409 IDEMPOTENCY_KEY_ALREADY_USED` теперь означает только «ключ принадлежит приложению, которое с тех пор удалили» — постоянный отказ, как и раньше.

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

Код `IDEMPOTENCY_KEY_ALREADY_USED` для сценария «первая попытка дошла до Битрикс24 и там не удалась» клиенты больше не увидят: вместо него в окне 20 минут приходит исходный отказ (например, `502 BITRIX_UNAVAILABLE`) с заголовком `Idempotent-Replayed: true`. Повторяйте тем же `Idempotency-Key` только ВНУТРИ этого окна — там реплей детерминирован и безопасен. Спустя 20 минут после первого отказа смена значения `Idempotency-Key` от дубля не защищает: что старым, что новым ключом повтор выполняется как совершенно новая попытка, и если первый отказ случился после обращения к порталу, она может выписать второй ключ поверх первого. На платформе при этом, как правило, нечего проверить — заявка на бронь удаляется вместе с исходом отказа, а ключ на большинстве стадий отказа не чеканится вовсе; возможный дубль в этом случае ищите в самом портале Битрикс24, если это возможно, и считайте риск частью цены повтора спустя окно. Исключение — `500 APPLICATION_CREATE_FAILED`: если ключ уже выписан, а карточку записать не удалось, лишний ключ можно найти и отозвать в разделе ключей кабинета платформы; пустой список значит, что чистить нечего. Ветвление по `error.code` менять не нужно; полагаться на постоянство `IDEMPOTENCY_KEY_ALREADY_USED` для отказов ПОСЛЕ обращения к порталу больше нельзя.
