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

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

### NEW-0827-1: агрегация помечает неполную сумму рядом с самим числом

**Было**

`POST /v1/{entity}/aggregate` с `sum` / `avg` / `min` / `max` считает по первым 5000 записям под фильтр. Признак неполноты лежал только в `data.meta.truncated`, а `data.aggregates.amount` выглядел как `{ "sum": 1234567 }` — обычное число без пометок. Клиент, который читает только сумму, получал заниженный результат под кодом `200` и не имел, за что зацепиться: `data.count` при этом показывал полное количество записей.

**Стало**

Когда выборка усечена, каждый объект поля в `data.aggregates` и в `groups[].aggregates` дополнительно несёт `truncated: true` — `{ "sum": 1234567, "truncated": true }`. Тем же условием в `data.meta.warnings` добавляется предупреждение с кодом `AGGREGATE_TRUNCATED`. Значения `sum` / `avg` / `min` / `max` остаются числами, в объект их никто не оборачивает. На полной выборке ответ не меняется вовсе: ключа `truncated` в объекте поля нет, `meta.warnings` не появляется. Потолок 5000 и `data.count` работают как раньше.

У группировки добавилось ещё одно поле — `groups[].truncated`: при усечении сам объект группы несёт этот признак рядом со своим счётчиком. Признак говорит, что образцом является ответ; точен ли счётчик группы, показывает `meta.aggregatePath` — на обычном обходе `groups[].count` посчитан по прочитанному срезу, а в режиме счётчиков по стадиям (`meta.aggregatePath: "fanout"`) он берётся отдельной пробой и точен. На группировке с одним только `count` это единственная пометка у числа: у `count`-выражения объекта поля не возникает, и оба бэга `aggregates` приходят пустыми. `data.count` и `data.meta.totalRecords` остаются точными на выборке любого размера и признака не несут.

Вместе с признаком неполноты ответ теперь всегда сообщает размер нехватки. Раньше `meta.recordsShortfall` приходил только тогда, когда усечение случилось НЕ из-за потолка: на выборке больше 5000 записей ответ поднимал `truncated: true`, но поля с размером дыры не было вовсе. Именно этот случай — самый частый: на воронке в 20 000 сделок клиент видел «ответ является образцом» и ноль в качестве размера пропажи. Теперь на любой причине усечения рядом с признаком едет квантификатор — `meta.recordsShortfall` (сколько записей не доехало до чисел) либо `meta.pageErrorSample` (если срез оборвался ошибкой подстраницы). На полной выборке ни того, ни другого ключа в ответе по-прежнему нет.

Одновременно убрана ложная тревога. Признак усечения раньше поднимался по сравнению «всего записей больше 5000», а это лишь косвенная примета того, что чтение обрежут. На сущностях, где ограничение до Битрикс24 не доезжает — страницы и сайты (`landing.*`), настройки открытых линий, — обрезания не происходит и строки читаются все. Такой ответ всё равно объявлял себя образцом. Теперь признак ставится по факту: прочитано меньше, чем обещано, — тогда и только тогда. На полностью прочитанной выборке любого размера ответ снова считается полным.

Заодно закрыт разрыв на группировке сделок по стадиям: если обход стадии возвращал меньше строк, чем насчитала проба (обычно из-за прав доступа), ответ раньше приходил с `data.meta.truncated: false` и выглядел полным. Теперь такой ответ честно поднимает `truncated` — и вместе с ним получает и пометку у числа, и предупреждение.

### BC-0827-2: порядок установки среды выполнения и запуск nginx изменились

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

**Было**

При повторной выкладке среда выполнения устанавливалась после остановки прежней версии приложения. Сбой установки мог оставить приложение остановленным. Для `static`, `php83` и `php83-mysql` установка пакета могла неявно запустить и включить системный `nginx.service`, и запрос мог полагаться на этот процесс.

**Стало**

[`POST /v1/infra/servers/:id/deploy`](/docs/infra/deploy/deploy) устанавливает среду выполнения до остановки и замены файлов приложения. Если установка завершается ошибкой, прежнее приложение не останавливается. Установка nginx для `static`, `php83` и `php83-mysql` не запускает системный `nginx.service` и не оставляет его впервые включённым. Существующее состояние включения сервиса сохраняется.

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

Для `static`, `php83` и `php83-mysql` проверьте, что команда из поля `start` сама запускает нужный процесс, слушающий порт приложения внутри `app.service`. Не полагайтесь на неявный запуск системного `nginx.service`. Запросы с другими средами выполнения менять не нужно.

### FIX-0827-5: приглашение пользователей сохраняет все поля анкеты

**Было**

[POST /v1/users/invite](/docs/entities/users/invite) принимал десять записываемых полей анкеты в обычном формате API Вайбкод, но передавал их в Битрикс24 без преобразования. Сотрудник создавался, а фотография, внешний идентификатор, часовой пояс и личные данные оставались пустыми.

**Стало**

[POST /v1/users/invite](/docs/entities/users/invite) преобразует эти поля в формат Битрикс24. Клиенту не нужно менять запрос, а прежний формат полей Битрикс24 продолжает работать.

### FIX-0827-6: одиночное чтение находит комментарий при строковом идентификаторе

**Было**

[GET /v1/tasks/:taskId/comments/:id](/docs/entities/task-comments/get) мог отвечать `404 NOT_FOUND`, если Битрикс24 возвращал идентификатор найденного сообщения строкой. При этом тот же комментарий присутствовал в списке комментариев задачи.

**Стало**

Эндпоинт нормализует числовой идентификатор из ответа Битрикс24 и возвращает найденный комментарий с числовыми `id` и `authorId`.

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

Изменения в клиентах не нужны.

### FIX-0827-7: select контактов снова принимает типизированные email-адреса

**Было**

[POST /v1/contacts/search](/docs/entities/contacts/search) и подзапрос контактов в [POST /v1/batch](/docs/batch) отклоняли `emailWork`, `emailHome` и `emailMailing` с кодом `UNKNOWN_SELECT_FIELD`, хотя ответы контактов уже содержали эти значения. [GET /v1/contacts/fields](/docs/entities/contacts/fields) не перечислял эти имена.

**Стало**

Обе операции принимают три имени в `select` и возвращают успешный ответ с выбранными значениями. [GET /v1/contacts/fields](/docs/entities/contacts/fields) описывает их как nullable-поля только для чтения.

### FIX-0827-8: тарифные заголовки возвращаются для инфраструктурных запросов

**Было**

Ответы методов семейства `/v1/infra/*` не содержали `X-Tariff-Checked-At` и `X-Tariff-Is-Commercial`, даже когда сверка тарифа завершилась успешно.

**Стало**

Ответы `/v1/infra/*` содержат тарифные заголовки по тем же правилам, что и `/v1/me`: время последней успешной сверки и признак коммерческого тарифа возвращаются при наличии соответствующих данных портала. Статус и тело ответа не изменились.

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

Менять запросы не нужно. Отсутствие заголовка снова означает, что соответствующих данных проверки тарифа нет, а не то, что инфраструктурный маршрут был пропущен.

### NEW-0827-9: схема элементов массивов доступна в контрактах полей

[GET /v1/orders/fields](/docs/entities/orders/fields), [GET /v1/basket-items/fields](/docs/entities/basket-items/fields) и [GET /v1/guide](/docs/keys-auth/guide) теперь возвращают `itemSchema` для массивов с объявленной формой элемента. Схема рекурсивно описывает `type`, `readonly`, `nullable`, `properties` и вложенные `itemSchema`. Клиенты могут опционально читать новое поле, существующие интеграции продолжают работать без изменений. Отдельный ключ `items` по-прежнему содержит сырой справочник значений Битрикс24 у полей-перечислений.

### FIX-0827-10: списки без общего количества больше не выглядят завершёнными раньше времени

**Было**

Если Битрикс24 не возвращал общее количество записей, запрос списка с лимитом больше 50 останавливался после первой страницы. В окне до 50 записей полная страница тоже могла ошибочно выглядеть последней, потому что её размер принимался за размер всей коллекции.

**Стало**

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

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

Менять запросы не нужно. Запрошенные окна больше одной страницы больше не усекаются молча; у `GET /v1/mail/messages` теперь всегда есть булевый признак `truncated`, а неизвестный `total` отсутствует вместо `null`.

**Затронутые эндпоинты:** [GET /v1/humanresources/nodes](/docs/humanresources/nodes/list), [GET /v1/mail/mailboxes](/docs/mail/mailboxes/list), [GET /v1/mail/messages](/docs/mail/messages/list).

### NEW-0827-11: самоописание указывает на документацию промокодов Коворк/Код

Ответы `GET /v1/guide` и `GET /v1/me` теперь называют пару промокодов настольного приложения. В разделе `cowork` ответа `GET /v1/guide` появились указатели `docs.couponPreview` и `docs.couponRedeem` на страницы `POST /v1/cowork/coupon/preview` и `POST /v1/cowork/coupon/redeem`, а правила `/v1/me` получили пункт про них: какой класс ключа нужен, чем проверка отличается от погашения и почему `accessGranted: false` показывают отдельным экраном.

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

### FIX-0827-12: пределы частоты Коворк/Код больше не называются числом, которого клиент не получает

**Было**

Справочник `GET /v1/guide`, правила `GET /v1/me` и страницы документации раздела Коворк/Код называли пределы частоты конкретным числом: 20 запросов в минуту у `POST /v1/cowork/coupon/preview`, 10 у `POST /v1/cowork/coupon/redeem`, 30 у `GET /v1/cowork/subscription/preview`, 5 у `DELETE /v1/cowork/key`, 3 за пять минут у `POST /v1/cowork/deploy-key`, 30 у `GET /v1/cowork/applications/defaults` и 6 у `POST /v1/cowork/applications`. Ни одно из этих чисел клиенту не приходило: предел делится между процессами платформы, и заголовок `x-ratelimit-limit` отдавал соответственно 7, 4, 10, 2, 1, 10 и 2. У `deploy-key`, `key` и мастера создания приложения расходились между собой два канала одного эндпоинта — страница обещала одно, заголовок отдавал другое.

**Стало**

Справочник `GET /v1/guide`, правила `GET /v1/me` и страницы документации раздела называют источником действующего значения заголовок ответа `x-ratelimit-limit` и просят не закреплять число в клиентском коде. Поведение самих эндпоинтов не менялось, ответ остаётся прежним — исправлено описание, которое расходилось с ним. Клиент, читавший заголовок, не меняет ничего.

Что этой записью НЕ закрыто. Машинная схема `GET /v1/openapi.json` по-прежнему называет числа пяти операциям раздела — `subscription/preview`, `deploy-key`, `applications/defaults`, `applications` и `key`, — и эти числа расходятся с заголовком так же, как расходились остальные. Клиент, сгенерированный по схеме, пока обязан читать `x-ratelimit-limit`, а не значение из описания операции. Верно в схеме одно обещание — «три запроса в час» у `POST /v1/cowork/activate-market-trial`: там предел умножается на число процессов до деления.

### FIX-0827-13: создание линии телефонии возвращает рабочий ключ

**Было**

[POST /v1/telephony-lines](/docs/telephony/lines/create) возвращал внутренний числовой идентификатор. Его нельзя было использовать в адресе для изменения или удаления созданной линии.

**Стало**

Поле `data.id` содержит номер созданной линии. Это значение подходит для последующих запросов изменения и удаления.

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

Дополнительных действий не требуется. Новые ответы создания сразу содержат адресуемый ключ.

### NEW-0827-14: списки трудозатрат явно отклоняют неподдерживаемый filter

**Было**

Неподдерживаемый `filter` в запросах [GET /v1/task-time](/docs/entities/tasks/time/global-list) и [GET /v1/tasks/:taskId/time](/docs/entities/tasks/time/list) мог вернуть статус `200` и более широкую выборку, чем ожидал клиент.

**Стало**

Непустой, bracket-, JSON- или повторный `filter` возвращает `400 UNSUPPORTED_FILTER`. Для запросов с именованными параметрами `userId`, `taskId`, `from` и `to` ответ остаётся HTTP 200, их поведение не меняется.

### FIX-0827-15: файл robots.txt PUBLIC-приложения доступен роботам

**Было**

Точные `GET` и `HEAD` на `/robots.txt` всегда получали локальный запрет шлюза, даже если приложение имело `accessPolicy=PUBLIC`, работало и само отдавало файл.

**Стало**

При `accessPolicy=PUBLIC` и живом туннеле точные `GET` и `HEAD` на `/robots.txt` возвращают ответ приложения: `200 text/plain` с полным непустым GET-телом не более 1 MiB (HEAD — без тела) или `304`. Для остальных политик, недоступного приложения и любого некорректного ответа шлюз по-прежнему возвращает локальный `200 text/plain` с `Disallow: /`.

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

PUBLIC-приложение теперь может управлять индексацией через свой файл `/robots.txt`. Для непубличных приложений ничего менять не нужно: запрет остаётся закрытым по умолчанию.

### FIX-0827-16: фильтры сущностей больше не теряются при списочных вызовах

**Было**

`list_entities` мог передать фильтры как обычные параметры запроса. Из-за этого поле с именем `sort` конфликтовало с директивой сортировки, а `openline-configs` мог вернуть полный список вместо отфильтрованного. На envelope-сущностях фильтр также мог потеряться в `GET /v1/{entity}/aggregate`, `POST /v1/batch` и `POST /v1/{entity}/batch`.

**Стало**

`list_entities` передаёт поля через `filter[...]`, отдельно от сортировки. Все списочные V1-пути применяют объявленный сущностью envelope, поэтому непустой фильтр доходит до Битрикс24 и несовпадающий фильтр возвращает пустой результат, а не полную коллекцию. Ручной список бронирований принимает ту же bracket-форму для обязательного окна `dateFrom`/`dateTo` и сохраняет прежнюю плоскую форму.

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

Менять запросы не нужно. Ранее слишком широкие успешные ответы теперь соответствуют переданному фильтру.

### FIX-0827-17: список доступа к приложению содержит только сотрудников портала

**Было**

`GET /v1/infra/servers/{id}/access` отдавал в `users[]` каждую строку аудитории. Поле `id` элемента объявлено обязательным, но у записи, выданной человеку не из портала сервера, портального номера нет вовсе — такой элемент приезжал бы с пустым `id`, и клиент, читающий поле как обязательное, ломался бы на нём.

**Стало**

`users[]` содержит только записи с портальным номером. Записи, адресованные по сетевому идентификатору, из этого списка исключены — у них другое пространство идентификаторов, и смешивать его с портальным нельзя. На сегодняшних данных ответ не меняется: таких записей ещё не существует.

### FIX-0827-18: шаг `connect` в статусе ремонта больше не проваливается на подключившемся агенте

**Было**

Ремонт сервера засчитывал шаг `connect` только тогда, когда версия поднявшегося агента совпадала
с версией, которую ожидала платформа. Если агент подключался на другой версии, туннель
был поднят и `blackholeStatus` показывал `CONNECTED`, но `GET /v1/infra/servers/{id}/repair-status`
отдавал `status: failed`, `step: connect` и `error: "Agent did not connect"`.

**Стало**

Шаг `connect` завершается по факту подключения агента к Gateway — ровно так, как описан порядок
шагов в документации операции. Версия установленного агента по-прежнему возвращается в
`data.agentVersion` и на исход ремонта не влияет.
