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

[← Журнал изменений](/docs/changelog) · [Август 2026](/docs/changelog/2026-08)

### BC-0824-1: тип дела нельзя изменить после создания

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

**Было**

`PATCH /v1/activities/:id` принимал поле `typeId`. Значение до записи не доходило: тип дела фиксирован при создании, поэтому оно отбрасывалось. Запрос, в котором `typeId` был единственным полем, оставался с пустым набором полей и возвращал невнятный отказ «Fields is not specified.» — по нему нельзя понять, что причина именно в неизменяемости типа. Запрос, где рядом было хотя бы одно изменяемое поле, отвечал успехом, и вызывающая сторона считала, что тип сменился.

**Стало**

`typeId` объявлен полем, которое задаётся только при создании. `PATCH /v1/activities/:id` с этим полем возвращает `400 READONLY_FIELD` и называет поле. Так же отвечают обе пакетные операции обновления. `POST /v1/activities` поле принимает как раньше — там он обязателен. В выдаче `GET /v1/activities/fields` у `typeId` теперь стоит признак `createOnly`.

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

Уберите `typeId` из тела `PATCH /v1/activities/:id`. Если тип действительно нужно поменять, создайте дело с нужным типом и удалите прежнее — изменить тип существующего дела нельзя. Признак `createOnly` в ответе `GET /v1/activities/fields` позволяет отличать такие поля до отправки запроса.

### FIX-0824-2: платный портал больше не получает отказ с предложением оплатить тариф повторно

**Было**

[POST /v1/apps](/docs/apps/create) мог вернуть платному порталу `403` с предложением оплатить тариф, если установка приложения через Битрикс24 завершалась отказом.

**Стало**

Если Битрикс24 подтверждает оплату тарифа, метод возвращает технический отказ `502 CONNECTOR_REST_UNAVAILABLE` с безопасной причиной и без предложения повторной оплаты. Подтверждённое отсутствие оплаты по-прежнему возвращает тарифный отказ `403`.

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

Менять запросы не нужно. Технический отказ можно повторить, тарифный требует оплаты.

### BC-0824-3: блок deployment у аккаунтов Беларуси меняет форму вместе с моделью доступа

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

**Было**

Аккаунт Беларуси попадал в бакет ограниченного доступа при трёх условиях сразу: есть
демо-подписка, нет платной подписки и нет истории коммерческих оплат. Тариф Битрикс24 —
платный он или бесплатный — на попадание в бакет не влиял, а вот аккаунт, который платил
когда-либо раньше, в бакет не попадал вовсе. В
[`GET /v1/me`](/docs/keys-auth/me) такой аккаунт получал блок `deployment` без под-блока
`galaxyApp`, с `primary` = `standalone` и с полем `placementNote`, объяснявшим, что своя
галактика ему не создаётся и разворачивать приложение нужно в два шага. Одношаговое
создание с полем `source` отвечало `400 SOURCE_AT_CREATE_GALAXY_ONLY`.

**Стало**

На тарифной модели бакета ограниченного доступа нет вовсе, поэтому аккаунт Беларуси выходит
из него в обе стороны сразу: на платном или демо-тарифе Битрикс24 он получает полный доступ,
на бесплатном — отказ. В обоих случаях форма блока `deployment` меняется одинаково — при
условии, что режим галактик аккаунту открыт и своей галактики у него ещё нет (оба карв-аута
названы ниже): под-блок
`deployment.galaxyApp` появляется, поле `deployment.placementNote` исчезает, а
`deployment.primary` переключается со `standalone` на `galaxyApp`. У аккаунта с полным
доступом одношаговое создание с полем `source` при этом начинает работать.

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

Определяйте модель размещения по НАЛИЧИЮ под-блока `deployment.galaxyApp`, как и предписывает
описание ответа. Ветку, привязанную к присутствию `placementNote` или к значению `primary`,
перепишите: оба поля меняются вместе с моделью доступа аккаунта, а не только с его тарифом.
Разрешение на создание сервера читайте отдельно — в `capabilities.servers.create`: блок
`deployment` описывает КОНТРАКТ размещения и у аккаунта без доступа тоже присутствует, а
[`POST /v1/infra/servers`](/docs/infra/servers/create) такому аккаунту ответит `402`.
Два карв-аута, у которых форма ответа не меняется вовсе. Первый — аккаунт с выключенным
режимом галактик: обоих полей у него нет ни до, ни после. Второй — аккаунт, у которого
галактика УЖЕ есть: `placementNote` объяснял отсутствие собственной галактики, поэтому
владелец живого galaxy-хоста и в бакете получал `galaxyApp` и не получал `placementNote`.
Изменение приходит к аккаунту в момент перевода его на тарифную модель, поэтому обе формы
ответа встречаются одновременно у разных аккаунтов.

### NEW-0824-4: новый код отказа доступа для аккаунтов Беларуси

В Беларуси доступ к инфраструктуре Вайбкод открывает платный тариф Битрикс24, демо-тариф
Битрикс24 ИЛИ платная подписка Битрикс24 Маркет Плюс — достаточно любого одного из трёх.
Аккаунт, у которого нет ни одного, получает `402` с `error.code` = `BY_PAID_ONLY` вместо
прежнего `MARKETPLACE_REQUIRED`. Тот же код приходит на создание сервера
([`POST /v1/infra/servers`](/docs/infra/servers/create)), на публикацию приложения, на
пробуждение уснувшей машины и на выписку нового ключа, а в
[`GET /v1/me`](/docs/keys-auth/me) он же приезжает в `capabilities.servers.create.reason`.

Изменение аддитивное: форма тела ответа прежняя, прочие ветки отказа не тронуты. Разбирайте
новый код так же, как остальные отказы `402`, — читайте `error.code`, показывайте
`error.userMessage`, ведите человека по `details.upgradeUrl`. Если разбор кодов у вас
исчерпывающий, заведите ветку `BY_PAID_ONLY`: без неё отказ провалится в `default`.

Переход поэтапный. Код появляется у аккаунта не раньше, чем платформа переведёт его на
тарифную модель доступа; до перевода тот же аккаунт получает прежний
`MARKETPLACE_REQUIRED`. Планировать разбор поэтому нужно на оба кода сразу, а не на один.

### FIX-0824-5: подсказка о создании серверов в ответе о ключе перестала звать в тупик

**Было**

Аккаунт, которому доступ открывает тариф Битрикс24, а не подписка, получал в
[`GET /v1/me`](/docs/keys-auth/me) слот `capabilities.servers.create` с общей формулировкой:
серверы доступны на коммерческих тарифах или во время активного пробного периода. Она врала
дважды. Пробный период такому аккаунту не положен — право на него считается по подписочной
модели, — а адрес, по которому тариф выбирается, в тексте не назывался вовсе. Отдельно у
аккаунтов Беларуси поле `alternatives[].url` вело на кассу подписки внутри самого аккаунта
и продолжало бы вести туда и после перевода аккаунта на тарифную модель, где отказ подпиской
не лечится.

**Стало**

Слот называет рабочие пути и адрес: платный или демо-тариф Битрикс24, а для Беларуси ещё и
платная подписка. Текст в `capabilities.servers.create.userMessage` теперь совпадает с телом
`402`, которое вернёт [`POST /v1/infra/servers`](/docs/infra/servers/create) на том же
аккаунте, — один код отказа больше не говорит на двух поверхностях разное. У аккаунтов
Беларуси, переведённых на тарифную модель, `alternatives[].url` ведёт на страницу выбора
тарифа, а не на кассу подписки.

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

Действий не требует: изменились значения текстового поля и адреса, структура ответа прежняя.
Правка касается Казахстана и Узбекистана сразу, Беларуси — по мере перевода аккаунта на
тарифную модель. Если вы показываете пользователю собственный текст вместо
`userMessage`, сверьте его: обещание пробного периода на этих аккаунтах неверно.

### FIX-0824-6: отказ по тарифу в Казахстане и Узбекистане больше не зовёт оформить подписку

**Было**

Портал из Казахстана или Узбекистана на бесплатном тарифе получал в теле `402` код
`MARKETPLACE_REQUIRED`, а поле `error.userMessage` звало подключить подписку. В этих
странах подписка не продаётся, поэтому названное действие клиент выполнить не мог:
текст вёл в тупик, а платный и демо-тариф Битрикс24 — рабочие пути к доступу — в нём
не назывались вовсе.

**Стало**

Такой портал получает код `KZ_PAID_ONLY` или `UZ_PAID_ONLY`, а текст называет оба
рабочих пути — платный или демо-тариф Битрикс24 — и адрес, где тариф выбирается.
Бренда подписки в тексте больше нет.

Новый код приходит на всех поверхностях, где отказ в доступе виден клиенту: создание
сервера ([`POST /v1/infra/servers`](/docs/infra/servers/create)), публикация приложения,
пробуждение уснувшей машины и выписка нового ключа. В [`GET /v1/me`](/docs/keys-auth/me)
он же приезжает в `capabilities.servers.create.reason`.

Код в теле ошибки для этих порталов сменился с `MARKETPLACE_REQUIRED` на
`KZ_PAID_ONLY` / `UZ_PAID_ONLY`. Действий на стороне клиента это не требует: обе
ветки уже были в контракте и отдавались в других сценариях, структура тела не
изменилась. Проверьте только, что разбор кодов не падает в `default` — если у вас
исчерпывающий `switch`, ветка `*_PAID_ONLY` в нём уже есть.

### BC-0824-7: повторная авторизация бота стала безопасной и явной

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

**Было**

`POST /v1/bots/:botId/reauth` мог снять любое отключение бота, а ответ `410 BOT_DISABLED` не сообщал клиенту, допустимо ли автоматическое восстановление.

**Стало**

`410 BOT_DISABLED` содержит boolean `error.details.reauthAllowed`. Вызывайте `POST /v1/bots/:botId/reauth` автоматически только при `reauthAllowed=true`; сервер выдаёт этот сигнал только для доступного на запись бота, отключённого из-за ошибок авторизации, и включает его поэтапно. Ручной вызов также остаётся проверкой учётных данных активного бота после переноса владения. Для остальных отключённых состояний endpoint сразу отвечает `409 BOT_REAUTH_NOT_ALLOWED`; при параллельном изменении состояния — `409 BOT_REAUTH_STATE_CHANGED`. Обновите клиентов, которые вызывали повторную авторизацию для любого `BOT_DISABLED`.

### FIX-0824-8: деплой galaxy-приложения предупреждает о сбросе переменных окружения

**Было**

Успешный `/deploy` без пользовательского `env` пересоздавал galaxy-приложение без прежних переменных, но не сообщал об этом в ответе.

**Стало**

Ответ содержит строку в `warnings[]`, которая просит передавать полный `env` при каждом деплое. Деплой участника команды разработки, где переменные владельца сохраняются, ложного предупреждения не получает.

**Влияние**

Статус и поведение деплоя не изменились; клиентам следует читать существующий массив `warnings[]`.

### NEW-0824-9: связи задач стали доступны через API

**Было**

Карточка задачи в Битрикс24 показывает блок «Связанные задачи», а через API их получить было нечем: полей связей нет ни в списке задач, ни в записи по идентификатору, в описании полей задачи они не описаны, отдельного эндпоинта не существовало. Дашборд, которому нужен граф зависимостей, собрать его не мог.

**Стало**

Появились два эндпоинта только для чтения. `GET /v1/tasks/:taskId/dependencies` отдаёт связи одной задачи массивом пар «идентификатор и название», отсортированным по идентификатору. `POST /v1/tasks/dependencies/bulk` принимает до 50 задач и отвечает по каждой отдельно: успешные в `results`, отказавшие в `errors`, счётчики в `meta`.

Пакетный вызов отвечает `200` даже тогда, когда отказали все подвызовы — частичный отказ и есть его смысл, поэтому смотреть надо `errors`, а не только `results`. Дубли в списке идентификаторов схлопываются молча, и счётчик запрошенных считает уникальные, поэтому «запрошено» всегда равно сумме «успешно» и «отказано».

**Границы, названные явно**

Отдаются только предшественники — задачи, от которых зависит запрошенная. Обратного направления Битрикс24 в API не отдаёт, и дашборд строит его инверсией собранных пар. Тип связи не читается ни одним методом портала, поэтому в ответе его нет вовсе: пустое или угаданное значение в контракте хуже, чем отсутствие поля.

Связи, добавленные через диаграмму Ганта, этими эндпоинтами не видны: портал хранит их отдельно и не возвращает ни одним методом чтения. Отличить «связей нет» от «связи есть, но в невидимом хранилище» нельзя ни здесь, ни в сыром REST.

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

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

Ломающих изменений нет — оба маршрута новые. Запись связей отдельного эндпоинта не получила: набор по-прежнему меняется полем `DEPENDS_ON` при обновлении задачи, и семантика там — полная замена набора, а не добавление.

### FIX-0824-10: опрос ботов останавливается при неактивной подписке Маркетплейса

**Было**

Маршруты существующего бота повторяли запросы в Битрикс24 после истечения
подписки Маркетплейса и возвращали общий `403 BITRIX_ACCESS_DENIED` на каждый
вызов. Цикл polling не получал однозначного сигнала остановки.

**Стало**

Первый подтверждённый отказ паркует бота. Следующие вызовы отвечают локально
HTTP 403 с кодом `B24_MARKET_SUBSCRIPTION_REQUIRED`, заголовком
`Retry-After: 3600` и `error.details.retryable:false`, не обращаясь в Битрикс24.
После продления `GET /v1/me?refresh=tariff` автоматически восстанавливает всех
ботов аккаунта.

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

Остановите polling при этом коде. После продления обновите тариф указанным
вызовом и только затем запустите цикл снова.

### BC-0824-11: открытие рабочего дня больше не подтверждает истёкшее состояние

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

**Было**

`POST /v1/workday/open` отвечал `200 success:true`, когда Битрикс24 оставлял
рабочий день в статусе `EXPIRED`. Новый день при этом не открывался.

**Стало**

Неизменившийся статус `EXPIRED` возвращается как HTTP 409 с `success:false` и
кодом `WORKDAY_EXPIRED`. Инструкция предлагает прочитать статус того же
сотрудника, закрыть истёкший день с датой его `timeStart` и отчётом, затем
повторить открытие.

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

Обрабатывайте `success:false` и HTTP 409 как явный признак, что день не открыт;
сначала разрешите состояние прежнего дня по подсказке ответа.

### NEW-0824-12: события календаря связываются с элементами CRM

У события календаря появилось поле `crmFields` — привязка встречи к элементам CRM: сделкам, лидам, контактам и компаниям. Поле читается и записывается, объявлено в [GET /v1/calendar-events/fields](/docs/entities/calendar-events/fields) и доступно в `select`.

Значение — массив типизированных ссылок: `D_<id>` сделка, `C_<id>` контакт, `L_<id>` лид, `CO_<id>` компания. На создании и обновлении значение обязано быть массивом; `[]` снимает все привязки, а отсутствие поля в теле сохраняет уже записанные. Очистка пустым массивом работает на `POST` и `PATCH`; в батч-запросе пустой массив отклоняется вместо тихого успеха — подкоманда батча передать его не может. У `POST /v1/batch` это `INVALID_PARAMS` в `data.errors` под `id` вызова, у `POST /v1/calendar-events/batch` — `400 BATCH_ITEM_VALIDATION` на весь пакет, где имя `INVALID_PARAMS` и индекс элемента приходят внутри `message`. Событие без привязок читается как `[]` — пустое значение никогда не приходит как `null` или пустая строка, поэтому проверка `crmFields.length` безопасна всегда. Неизвестный префикс или ссылка на несуществующую запись отклоняются.

**Затронутые эндпоинты:** [GET /v1/calendar-events](/docs/entities/calendar-events/list), [GET /v1/calendar-events/:id](/docs/entities/calendar-events/get), [POST /v1/calendar-events/search](/docs/entities/calendar-events/search), [POST /v1/calendar-events](/docs/entities/calendar-events/create), [PATCH /v1/calendar-events/:id](/docs/entities/calendar-events/update), [GET /v1/calendar-events/fields](/docs/entities/calendar-events/fields).

### FIX-0824-13: приложение на незагружающемся galaxy-хосте удаляется без живого туннеля

**Было**

`DELETE /v1/infra/servers/{id}` по galaxy-приложению отвечал `502` с кодом
`GALAXY_HOST_UNREACHABLE`, если хост был не на связи, — независимо от причины. Когда гостевая
операционная система хоста не загружается вовсе (поле `provisionErrorCode` карточки сервера равно
`GUEST_NOT_BOOTING`), туннель не появится уже никогда, поэтому повтор запроса не помогал ни через
минуту, ни через сутки. Удалить сам хост тоже было нельзя: он отвечал `409` с кодом
`GALAXY_HAS_APPS`, потому что приложения на нём формально оставались живыми. Владелец оказывался в
замкнутом круге и продолжал занимать слот квоты машиной, которая уже не работает.

**Стало**

Если платформа доказала, что гостевая операционная система хоста не загружается, приложение на нём
удаляется без обращения к хосту: `DELETE /v1/infra/servers/{id}` отвечает `200`, запись приложения
закрывается, освобождаются его токены доступа, домен и карточка в каталоге. Удалив приложения по
одному, владелец затем удаляет и сам хост обычным вызовом — отказ `GALAXY_HAS_APPS` больше не
возникает. Код `GALAXY_HOST_UNREACHABLE` сохраняет прежний смысл для всех остальных случаев: хост
временно не на связи, повтор осмыслен. ⚠️ Метка «не загружается» сама по себе `200` не
гарантирует: перед удалением без обращения к хосту платформа ещё и убеждается через шлюз,
что живого туннеля нет. Проверка fail-safe — если шлюз недоступен, ответил без списка
соединений или хост тем временем поднялся, ответ остаётся `502`. Клиентам менять ничего не нужно — цикл повторов для этого
состояния просто перестаёт быть нужным.

### BC-0824-14: незнакомое имя поля в select отклоняется с 400 почти на всех сущностях

> Поддержка старого формата до: 18.02.2027

> До сих пор такой запрос отвечал `200`, а запрошенного поля в записи просто не было — то есть «старый формат» здесь означает неполный ответ, а не рабочий.

**Было**

Имя поля, которого у сущности нет, уходило в отбор молча. Запрос выполнялся, поле в записях
отсутствовало, а объяснение лежало в `meta.warnings` — там, куда обычно не смотрят. Опечатка
в `select` поэтому выглядела как успешный запрос с загадочно неполными записями:

```
GET /v1/deals?select=id,titel      →  200, в записях только id
```

Ошибкой такое имя отвечали только [события календаря](/docs/entities/calendar-events/list).

**Стало**

Запрос отклоняется до вызова Битрикс24 — `400` с кодом `UNKNOWN_SELECT_FIELD` и списком
допустимых имён в сообщении. Этот список и есть точный ответ на вопрос «что можно запрашивать».

Действует на сущностях, у которых набор полей выверен по Битрикс24: сделки, контакты, компании,
лиды, предложения, дела, адреса, смарт-процессы, товары и разделы товаров, каталоги и их товары
и разделы, заказы и статусы заказов, статусы, валюты, разделы календаря, файлы, папки,
хранилища, подразделения, рабочие группы, шаблоны документов. На остальных
поведение прежнее — предупреждение в `meta.warnings`.

Отдельный класс — имя, которое у сущности ЕСТЬ, но никогда не возвращается: `GET
/v1/{entity}/fields` показывает такое поле с `notReturned: true`. В когорте это, например,
`currencyId` у товаров и `sort` у разделов товаров. Оно тоже отклоняется `400`, но СВОИМ кодом
`SELECT_FIELD_NOT_RETURNED` и сообщением, которое называет причину. Код отдельный намеренно:
`UNKNOWN_SELECT_FIELD` утверждает «такого имени нет», а справочник сущности это имя публикует —
клиент, честно взявший имя оттуда, иначе читал бы ответ как «справочник врёт».

Проверяется только имя. Пользовательские поля (`UF_*`, `ufCrm*`) принимаются как раньше и на
любой сущности; свойства товаров принимаются каждое на СВОЕЙ сущности: `PROPERTY_295` — на товарах,
`property295` — на товарах каталога, где их номера назначает портал; чужое написание метод не
понимает, и его гейт отклоняет. Значение `*` (и `UF_*`) по-прежнему означает
«вернуть все поля», и опечатка рядом с ним отклонения не вызывает — приходит предупреждение.
Отбор полей в обоих пакетных вызовах — и в общем, и в пакете по одной сущности — отклоняет
только свой подвызов, соседние выполняются.

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

Сверьте имена полей в своих `select` со списком из сообщения об ошибке или со схемой
`GET /v1/{entity}/fields`. Запрос, который раньше «работал», но возвращал записи без части
запрошенных полей, теперь ответит `400` с точным указанием, какое имя не найдено — это и есть
его исходная ошибка.

### FIX-0824-15: схема поля `datePeriod` теперь видна в `GET /v1/bookings/fields`

**Было**

Поле `datePeriod` описывалось как `"type": "object"` без вложенной схемы. Форму объекта нельзя было узнать из самого контракта — клиент отправлял `{}` или строку с датой и получал `422 BITRIX_ERROR`, и только по тексту ошибки догадывался о нужных ключах.

**Стало**

У полей типа `object` с известной вложенной формой ответ несёт ключ `properties` с рекурсивной схемой вложенных ключей. Для `datePeriod` это `from` и `to`, у каждого `timestamp` (number, Unix-секунды) и `timezone` (string, зона в формате IANA). Тот же ключ появился у `requisiteLink` в `GET /v1/orders/fields` и на обеих поверхностях сразу — в `fieldsDetailed` у `GET /v1/guide` тоже, поэтому форму видно и без токенов портала. Массивы объектов схему элемента по-прежнему не несут. Изменение аддитивное: прежние ключи описаний полей остались на месте, проверка данных при создании не ужесточалась.

### NEW-0824-16: этапы Scrum-канбана и список спринтов в API

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

[GET /v1/scrum/sprints](/docs/scrum/stages) возвращает спринты проекта — это единственный способ получить `sprintId`, который нужен остальным трём операциям; без параметра `groupId` придут все спринты, доступные ключу.

[GET /v1/scrum/sprints/:sprintId/stages](/docs/scrum/stages/list) отдаёт колонки спринта, приводя `id`, `sort` и `sprintId` к числам. [POST /v1/scrum/sprints/:sprintId/stages](/docs/scrum/stages/create) создаёт колонку и возвращает её перечитанной целиком, вместе с подставленными значениями по умолчанию. [PATCH /v1/scrum/stages/:stageId](/docs/scrum/stages/update) переименовывает, перекрашивает и переставляет колонку.

Проверки на стороне платформы Вайбкод закрывают места, где Битрикс24 отвечает успехом и сохраняет другое значение: имя длиннее 255 символов, цвет длиннее шести символов и значение `type` вне набора `NEW`, `WORK`, `FINISH` теперь получают понятный отказ вместо тихой подмены. Цвет можно передавать и с ведущим `#` — он будет срезан.

Перенос колонки в другой спринт не выставлен: `sprintId` в теле запроса отклоняется. Обновление несуществующей или недоступной колонки отвечает кодом `STAGE_NOT_FOUND_OR_NO_ACCESS`; различить эти два случая нельзя, потому что Битрикс24 отвечает на них одинаково.

### FIX-0824-17: код ACCOUNT_FROZEN описан в спеке создания сервера

Ответ `402` у [POST /v1/infra/servers](/docs/infra/servers/create) перечислял только отказы по тарифу, пробному периоду и подписке Маркетплейса. Кода `ACCOUNT_FROZEN`, которым платформа отвечает порталу с замороженным кошельком, в перечислении не было, хотя ручка отдавала его и раньше: проверка баланса срабатывает до обработчика, и создание сервера под неё подпадает.

Из-за пропуска клиент, сгенерированный по `/v1/openapi.json`, считал этот код невозможным и терял отказ, у которого есть понятное действие — пополнить баланс. Поведение ручки не менялось, изменилось только описание.
