# Изменения API: 9 июля 2026

[← Журнал изменений](/docs/changelog) · [Июль 2026](/docs/changelog/2026-07)

### FIX-0709-1: транзиентная перегрузка БД теперь отдаёт 503 с Retry-After вместо 500

**Было**

В редкой форме кратковременной перегрузки БД (исчерпание коннектов) часть запросов (включая `POST /v1/infra/servers`) возвращала `500`.

**Стало**

Такие запросы возвращают `503` с кодом `POOL_EXHAUSTED` и заголовком `Retry-After`. Ошибка транзиентная — повтори запрос с задержкой (backoff).

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

Клиенты, повторяющие запросы при 5xx, теперь должны обрабатывать `503` и уважать `Retry-After`. `POST /v1/infra/servers` неидемпотентен — повтор может создать дубль сервера, поэтому повторяйте с backoff, а не немедленно.

### FIX-0709-2: placements/bind честнее сообщает о необходимости подписки Маркетплейса

**Было**

При привязке плейсмента через ключ приложения на портале без активной подписки «BitrixGPT + Маркетплейс» Bitrix24 отвечал отказом доступа, а `POST /v1/placements/bind` возвращал непрозрачный `502 BITRIX_UNAVAILABLE` без указания причины. Подписка требуется на пути через ключ разработчика независимо от коммерческого тарифа, но `GET /v1/me` не сообщал об этом предусловии заранее.

**Стало**

Отказ по подписке теперь классифицируется: `POST /v1/placements/bind` возвращает `403` с кодом `B24_MARKET_SUBSCRIPTION_REQUIRED` (или `B24_MARKET_TRIAL_USED`, если демо уже использован), понятным `userMessage` и ссылкой на оформление в `details.upgradeUrl`. У ключа приложения в `GET /v1/me` добавлен блок `placements.bindPrerequisite` — он заранее описывает предусловие Bitrix24 (путь через ключ разработчика требует активной подписки Маркетплейса, устаревший OAuth-путь — коммерческого тарифа) и перечисляет коды ошибок. Прочие отказы привязки (неизвестный clientId, устаревший embedding) по-прежнему возвращают `502 BITRIX_UNAVAILABLE`.

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

Менять ничего не нужно, успешные вызовы не затронуты. Тем, кто обрабатывал `502 BITRIX_UNAVAILABLE` при привязке, стоит дополнительно ловить `403 B24_MARKET_SUBSCRIPTION_REQUIRED` / `B24_MARKET_TRIAL_USED` и подсказывать пользователю оформить подписку на портале.

### FIX-0709-3: bindPrerequisite в GET /v1/me учитывает регион портала

**Было**

Блок `placements.bindPrerequisite` у ключа приложения описывал предусловие привязки одинаково для всех порталов: `subscriptionRequired: true`, рецепт «попросите администратора активировать подписку Маркетплейса» и список кодов с `B24_MARKET_SUBSCRIPTION_REQUIRED` / `B24_MARKET_TRIAL_USED`. На порталах с тарифной моделью доступа отказ привязки приходит с кодом `INT_TARIFF_REQUIRED`, а подписки там нет — предложенный рецепт был невыполним.

**Стало**

Блок зависит от региона портала. На порталах с подписочной моделью доступа он прежний. На порталах с тарифной моделью `subscriptionRequired` равен `false`, текст `note` описывает требование коммерческого тарифа Битрикс24, а `errorCodes` содержит `INT_TARIFF_REQUIRED` и `BITRIX_UNAVAILABLE` — только те коды, которые портал действительно может получить.

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

Успешные вызовы не затронуты. Если вы читали `errorCodes` из `bindPrerequisite` как полный перечень, учтите, что теперь он сужен до достижимых на конкретном портале кодов. Сами коды и поведение `POST /v1/placements/bind` не менялись.

### BC-0709-4: Поля CRM, задач и лендингов приведены к реальному контракту Битрикс24

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

**Было**

`GET /v1/deal-categories` возвращал `isLocked` строкой `"Y"`/`"N"`, а `GET /v1/payments` — `paySystemIsCash` строкой `"Y"`/`"N"`. `GET /v1/leads` в каждом ответе отдавал служебное поле `searchContent` (внутренний полнотекстовый индекс Битрикс24). Поля `paySystemXmlId`, `dateMarked`, `dateResponsibleId` у платежей приходили как есть, без нормализации даты.

**Стало**

`isLocked` (воронки) и `paySystemIsCash` (платежи) теперь имеют тип boolean (`true`/`false`). `searchContent` в ответах `GET /v1/leads` больше не отдаётся. У платежей добавлены задекларированные поля `paySystemXmlId` (строка), `dateMarked` и `dateResponsibleId` (даты нормализованы в единый формат ISO с суффиксом `Z`). У задач добавлены `changedBy`/`closedBy`/`statusChangedBy` (только для чтения — попытка записать возвращает `400 READONLY_FIELD`). `GET /v1/currencies/fields` отдаёт человекочитаемые `label` для полей и поле `lang`; `GET /v1/deal-categories/fields` — `label` для полей; `GET /v1/sites/fields` — флаг `nullable` у полей, которые могут прийти пустыми.

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

Читать `isLocked` и `paySystemIsCash` как boolean, а не сравнивать со строкой `"Y"`. Если код опирался на поле `searchContent` у лидов — перестать: оно было служебным и не задокументированным.

### FIX-0709-5: создание сущности с пустым телом отклоняется явной ошибкой

**Было**

Создание сущности с пустым телом (или вовсе без тела, но с заголовком `Content-Type: application/json`) доходило до Битрикс24 и молча создавало сущность со значениями по умолчанию — включая сделки, лиды, контакты, компании, счета и смарт-процессы. Повторный вызов или клиент без тела так плодил мусорные записи в CRM. Это касалось всех трёх поверхностей создания: одиночного `POST /v1/{entity}`, пакетного `POST /v1/{entity}/batch` и общего `POST /v1/batch`.

**Стало**

Такой запрос возвращает `400 EMPTY_CREATE_BODY` (в пакетных вызовах — ошибку элемента) до обращения к Битрикс24, на всех трёх поверхностях. Осмысленное создание всегда несёт хотя бы одно поле — передайте нужные поля в теле запроса. Сущности, у которых уже есть проверка обязательных полей, ведут себя как прежде.

### FIX-0709-6: снятие блокировки сервера принимает пустое тело JSON

**Было**

[DELETE /v1/infra/servers/:id/lock](/docs/infra) с заголовком `Content-Type: application/json` и пустым телом возвращал `400` (пустое JSON-тело). Чтобы снять зависшую блокировку, приходилось слать явное `{}` — не зная этого, клиент упирался в тупик.

**Стало**

Пустое тело при этом заголовке принимается как `{}`; запрос без тела отрабатывает штатно и снимает блокировку. Явное `{}` по-прежнему работает.

### FIX-0709-7: события портала теперь будят спящее galaxy-приложение

**Было**

Событие Битрикса, отправленное на подписку спящего galaxy-приложения, не будило его — доставка
уходила в повторные попытки и после их исчерпания терялась.

**Стало**

Платформа будит спящее galaxy-приложение при доставке события и доставляет его после подъёма —
как для обычного сервера.

### NEW-0709-8: camelCase-ключи внутри communications при создании дела

[POST /v1/activities](/docs/entities/activities/create) теперь принимает вложенные ключи элементов `communications` в camelCase (`type`, `value`, `entityTypeId`, `entityId`) — единообразно с остальным API. Раньше вложенные ключи принимались только в ВЕРХНЕМ регистре Bitrix24 (`TYPE`, `VALUE`, `ENTITY_TYPE_ID`, `ENTITY_ID`), а camelCase-форма молча отбрасывалась — `communications: [{ "type": …, "value": … }]` возвращал `422` «COMMUNICATIONS is not defined or invalid», тогда как `[{ "TYPE": …, "VALUE": … }]` создавал дело. ВЕРХНИЙ регистр по-прежнему работает; если в одном объекте заданы обе формы одного ключа, приоритет у ВЕРХНЕГО регистра.

### FIX-0709-9: снятие с публикации убирает вкладку по всем обработчикам приложения

**Было**

[POST /v1/apps/:id/unpublish](/docs/apps/unpublish) снимал placement только по обработчику, совпадающему с ожидаемым платформенным адресом. Если вкладка была привязана к техническому адресу самого приложения, Битрикс24 не находил её и не удалял — вкладка оставалась висеть в карточке CRM, и через API её уже нельзя было убрать.

**Стало**

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

### NEW-0709-10: Самоописание ключей в GET /v1/guide

Ответ `GET /v1/guide` дополнен блоком `data.keysAuth`. Он описывает два эндпоинта самоописания — `GET /v1/me` и `GET /v1/guide` — и содержит ссылки на документацию: контракт ответа каждого из них, режим доступа ключа и общее описание типов ключей.

Оба эндпоинта работают по одному заголовку `X-Api-Key`, токен сессии для них не нужен.

Поле аддитивное: существующие клиенты не затронуты.

**Затронутые эндпоинты:** [GET /v1/guide](/docs/keys-auth/guide)

### FIX-0709-11: GET /v1/{entity}/:id теперь учитывает ?select=

Проекция полей `?select=` на чтении одной записи по id раньше игнорировалась: ответ всегда приходил со всеми полями, хотя `/v1/me` заявляет, что `?select=` работает «на списке, чтении по id и POST /search». Теперь чтение по id проецирует ответ так же, как список и поиск, — приводя поведение в соответствие с задокументированным.

**Было**

`GET /v1/leads/42?select=id,title` возвращал полную запись (все поля).

**Стало**

`GET /v1/leads/42?select=id,title` возвращает только `id` и `title`. Поддерживаются формы через запятую (`?select=id,title`), массивом (`?select[]=id&select[]=title`) и с индексами (`?select[0]=id&select[1]=title`); `id` включается в ответ всегда. Неизвестное имя поля молча пропускается — это не ошибка. При одновременном `?select=` и `?include=` связанная сущность в ответе сохраняется. Индексная форма (`?select[0]=…`) раньше возвращала 500 и на списке `GET /v1/{entity}` — теперь тоже проецирует корректно.

### FIX-0709-12: /fields сущностей заказов, позиций корзины, пресетов реквизитов и шаблонов документов приведены к реальному контракту B24

**Было**

`GET /:entity/fields` (и генерируемая по нему OpenAPI-схема) объявлял поля, которые Bitrix24 не возвращает: `provider` у шаблонов документов; `reserved`, `sumPaid`, `dateBill`, `datePayBefore`, `datePaid`, `empPaidId`, `userEmail`, `userName` на верхнем уровне заказа; `module`, `fUserId`, `lid`, `dateRefresh`, `subscribe`, `reserved`, `reserveQuantity` у позиций корзины; `originatorId` у пресетов реквизитов. Фильтрация и сортировка по этим полям молча не срабатывали. При этом реально приходящие поля не были объявлены: `requisiteLink` у заказа, `type`/`properties`/`reservations` у позиции корзины. Пресеты реквизитов принимали `countryId`/`entityTypeId` на обновление, где Bitrix24 их молча игнорирует.

**Стало**

Несуществующие поля убраны из `/fields` и OpenAPI. Реально приходящие поля объявлены: у заказа — `requisiteLink` (объект `requisiteId`/`bankDetailId`/`mcRequisiteId`/`mcBankDetailId`, только чтение); у позиции корзины — `type`, `properties`, `reservations` (только чтение). У пресетов реквизитов `countryId` и `entityTypeId` помечены как задаваемые только при создании: обновление возвращает `400 READONLY_FIELD` вместо тихого игнорирования.

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

Ответы list/get не меняются — убранные поля и так никогда не приходили. Если запрос фильтровал или сортировал по убранному полю, теперь он вернёт `400` — используйте реальные поля из `/fields` (например, даты и суммы оплаты у заказа лежат внутри массива `payments`, а не на верхнем уровне). Обновление `countryId`/`entityTypeId` у пресета реквизитов теперь явно отклоняется — задавайте эти поля только при создании.

**Затронутые эндпоинты:** [GET /v1/orders/fields](/docs/entities/orders/fields), [GET /v1/basket-items/fields](/docs/entities/basket-items/fields), [GET /v1/requisite-presets/fields](/docs/entities/requisite-presets/fields), [GET /v1/doc-templates/fields](/docs/entities/doc-templates/fields)

### NEW-0709-13: GET /:entity/fields отдаёт человекочитаемые label и описания для сделок, лидов, счетов, дел, справочников и комментариев таймлайна

Ответ `GET /v1/deals/fields`, `/v1/leads/fields`, `/v1/invoices/fields`, `/v1/activities/fields`, `/v1/statuses/fields` и `/v1/timelines/fields` теперь несёт по каждому полю человекочитаемые `label` и `description` по-русски. У полей со служебными кодами добавлены словари `enum`: у сделок — `stageSemanticId` (P — в работе, S — успех, F — провал); у дел — `typeId`, `direction`, `priority`, `status`, `notifyType` и `descriptionType`. Прежние вызовы работают без изменений — это дополнительные поля метаданных, форма ответа не меняется.

### FIX-0709-14: POST /v1/batch — единый формат ошибок под-вызовов и totals только для list/search

**Было**

Ошибка Bitrix24 внутри успешного 200-ответа [POST /v1/batch](/docs/batch) (например, `get` несуществующего элемента) попадала в `data.errors[<id>]` в исходной форме Bitrix24 `{ error, error_description }` — не в общем для V1 конверте `{ code, message }`, который используют ошибки валидации и любой другой ответ API. Поле `data.totals[<id>]` при этом заполнялось для любого действия, включая `get`/`create`/`update`/`delete`, где одиночное число рядом с единственной записью не имеет смысла.

**Стало**

Ошибка под-вызова приводится к `{ code, message }` (`error` → `code`, `error_description` → `message`), как у остальных ошибок. `data.totals[<id>]` заполняется только для действий `list` и `search` — там, где счётчик совпадений реально имеет смысл.

### FIX-0709-15: GET /v1/openline-configs — нормализация пустых значений в ответе

**Было**

Ответы [GET /v1/openline-configs](/docs/openlines/config/list) и [GET /v1/openline-configs/:id](/docs/openlines/config/get) отдавали служебные поля в неудобных для клиента формах: `KPI_FIRST_ANSWER_LIST`, `KPI_FURTHER_ANSWER_LIST`, `DEFAULT_OPERATOR_DATA` приходили как `null` (на них падал `.map`/`.length`); `AUTO_CLOSE_TEXT` для незаданного значения приходил как `""` в карточке и как `null` в списке; `WORKTIME_HOLIDAYS`/`WORKTIME_DAYOFF` для пустого набора приходили как `[""]` (массив с одной пустой строкой).

**Стало**

Списки нормализованы: `null` → `[]`. `AUTO_CLOSE_TEXT` приведён к единому `null` для пустого значения и в списке, и в карточке. `WORKTIME_HOLIDAYS`/`WORKTIME_DAYOFF` для пустого набора приходят как `[]`. Список и карточка теперь отдают одинаковую форму этих полей.

### FIX-0709-16: GET /v1/users/fields отдаёт возможные значения (items) для UF-полей-перечислений

**Было**

Пользовательское поле-перечисление (`UF_USR_*` типа «список») приходило в `GET /v1/users/fields` как `{ "type": "string", "label": "…" }` — без списка возможных значений. Причина: метод `user.fields` возвращает у UF-полей только подпись, без типа и вариантов, поэтому перечисление было неотличимо от строки.

**Стало**

Такое поле приходит с настоящим типом и списком вариантов: `{ "type": "enumeration", "label": "…", "items": [ { "ID": "…", "VALUE": "…", "DEF": "…", "XML_ID": "…" }, … ] }`. Значения дочитываются из `user.userfield.list` — для этого у ключа должен быть скоуп `user.userfield`; если он не выдан, поле по-прежнему отдаётся с подписью, но без `items` (мягкая деградация). Заодно у остальных UF-полей (`money`, `date` и т. п.) в ответе появляется их настоящий тип вместо `string`.

### FIX-0709-17: подсказка hint при пустой очереди событий появляется по факту устойчивой пустоты

**Было**

[GET /v1/bots/:botId/events](/docs/bots/events/polling) увеличивал счётчик пустых ответов ровно на каждый запрос, и поле `hint` появлялось строго после пятого подряд пустого ответа. Число в тексте подсказки совпадало с количеством сделанных запросов.

**Стало**

Счётчик пустых ответов обновляется периодически, а не на каждый запрос, поэтому `hint` появляется после устойчивой пустоты очереди — при рекомендованном интервале опроса 2–5 секунд спустя примерно пару минут непрерывно пустого опроса. Число N в тексте отражает количество зафиксированных периодов пустоты, а не точное количество сделанных запросов. Правило «доставлено событие → счётчик и подсказка сбрасываются» не изменилось.

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

Менять код не нужно. Если вы опирались на появление `hint` строго на пятом запросе или трактовали N как точное число запросов — используйте `persisted` и наличие событий как основной сигнал, а `hint` как диагностическую подсказку.
