# Изменения API: 3 октября 2026

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

### BC-1003-1: адреса и бронирования перестали молча терять условие фильтра

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

**Было**

`GET /v1/addresses` и `GET /v1/bookings` принимали фильтр, который не мог быть применён, и отвечали `200`. У адресов запрос вида `?filter[city]=Москва&filter=` возвращал **всю адресную книгу портала**: при разборе строки запроса одно написание уничтожает другое, условие исчезало, и ответ выглядел отфильтрованным. Запись `?filter={"city":"Москва"}&filter=` теряла условие так же, без единой скобки. У бронирований любой ключ конверта, кроме `dateFrom` и `dateTo`, не доезжал до Битрикс24 и ответ приходил по всему интервалу, а уничтоженный конверт отвечал `MISSING_REQUIRED_PARAMS` — «передайте `dateFrom` и `dateTo`» тому, кто их и передал. То же теряло условие и на `POST /v1/bookings/search`: тело `{"filter":{"status":"CONFIRMED"}}` уходило в Битрикс24 без этого ключа, и ответ приходил по всему интервалу.

**Стало**

Оба маршрута проверяют конверт `filter` до обращения к Битрикс24. Если хотя бы одно написанное условие не доехало — смешаны обе формы, одно имя написано на двух разных уровнях вложенности (`?filter[a]=1&filter[a][b]=2`), вложенность глубже двух уровней — приходит `400 INVALID_FILTER`, и сообщение называет, какой именно случай. У бронирований ключ, кроме `dateFrom` и `dateTo`, а также `filter`, пришедший строкой, JSON-объектом или массивом, дают `400 UNSUPPORTED_FILTER` с перечислением принимаемых ключей. На `POST /v1/bookings/search` тот же отказ: в теле разбирается только `filter.within` с ключами `dateFrom` и `dateTo`, любой другой ключ — `400 UNSUPPORTED_FILTER` до обращения к Битрикс24.

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

Передавайте весь фильтр **одной формой** — либо скобочная запись `?filter[поле]=значение` по всему запросу, либо один JSON-объект `?filter={…}`, который несёт все условия. На `GET /v1/bookings` сужайте выборку только по `dateFrom` и `dateTo` (плоскими параметрами или ключами `filter[dateFrom]` / `filter[dateTo]`), на `POST /v1/bookings/search` — верхнеуровневой парой или `filter.within`; остальное отбирайте на своей стороне. Пустое `?filter=` по-прежнему означает «без фильтра» и ничего менять в таких запросах не нужно. Запрос, который получал `200` с лишними записями, теперь получит `400`, и это и есть исправление: прежний ответ содержал данные, которых вы не запрашивали.

### FIX-1003-2: CRM-формы больше не скрывают обычный текст формы

**Было**

[GET /v1/crm-forms](/docs/entities/crm-forms/list) и [GET /v1/crm-forms/:id](/docs/entities/crm-forms/get) иногда заменяли на `[redacted]` обычный текст формы. Слово, которое оканчивается на «key», принималось за имя учётных данных: подпись `Monkey: Banana` возвращалась как `[redacted]`. Закодированный адрес вида `%2Frest%2F1%2Fhelp` принимался за адрес входящего вебхука и тоже скрывался.

**Стало**

Обычный текст формы возвращается как есть. Учётные данные в тексте по-прежнему скрываются: пары вида `apiKey: …`, `api_key=…`, `x-api-key: …`, `token=…` и адреса входящих вебхуков, в том числе закодированные. Ответ остаётся HTTP 200, поля ответа не изменились.

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

Действий не требуется. В названиях, подписях полей и текстах результата формы стало меньше ложных `[redacted]`.

### FIX-1003-3: удаление заблокированного ключа подтверждает отзыв его токенов

**Было**

[DELETE /v1/keys/:id](/docs/management-keys) мог подтвердить удаление заблокированного ключа до того, как выписанные им токены доступа переставали приниматься.

**Стало**

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

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

Запрос менять не нужно. Повторяйте удаление после временного отказа.

### FIX-1003-4: удалённое приложение авторизации больше не описывает карточку приложения

**Было**

У приложения, чей ключ авторизации удалили до исправления FIX-0922-6, привязка к удалённому
приложению авторизации сохранялась до первой выдачи нового ключа, и карточка продолжала
описывать удалённое приложение:

- `GET /v1/applications` и `GET /v1/applications/{id}` отдавали `isEmbedded: true`, если у
  удалённого приложения были размещения, а блок `key` показывал маску его ключа, если тот был
  заблокирован (`status: BLOCKED`);
- `POST /v1/cowork/applications/{id}/key` возвращал в `warningCodes` значение
  `APPLICATION_HAS_AUTH_KEY`, а блок `key` в карточке ответа показывал ту же маску.

**Стало**

Привязка к удалённому приложению авторизации читается как «ключа авторизации нет» на всех
этих эндпоинтах: `isEmbedded` равен `false`, блок `key` показывает личный ключ (`slot: "api"`)
или пустой слот, а `APPLICATION_HAS_AUTH_KEY` в `warningCodes` не приходит. Успешные ответы
сохраняются: `HTTP 200` у обоих `GET` и `HTTP 201` у выдачи ключа. Живое приложение авторизации
описывается, как и раньше, — в том числе его заблокированный ключ.

### BC-1003-5: static-деплой использует платформенный веб-сервер

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

**Было**

Для `runtime: "static"` поле `start` было обязательным, а переданная команда
управляла процессом приложения.

**Стало**

Для `runtime: "static"` поле `start` необязательно и игнорируется. Платформа
раздаёт готовую статическую сборку из `extractTo` на указанном `port` и
поддерживает SPA-маршруты через `index.html`.

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

Удалите `start` из static-деплоев и убедитесь, что архив содержит готовую сборку
непосредственно в `extractTo`. Если приложению нужна собственная команда запуска,
выберите подходящий нестатический runtime; для ручного существующего unit на
отдельной виртуальной машине используйте `systemd: false`.
