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

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

### NEW-0807-1: импорт записей CRM: автор и даты из внешней системы, без запуска автоматизации

Перенести уже существующую базу в CRM теперь можно одним запросом на сущность: `POST /v1/leads/import` и такие же маршруты у сделок, контактов, компаний, предложений, счетов и элементов смарт-процессов. До ста записей за раз, в теле — массив `items`, поля записи те же, что у обычного создания.

Импорт отличается от создания тремя вещами, и все три — свойства самой операции в Битрикс24, а не наши параметры. Он проверяет отдельное право «импорт», которое администратор портала выдаёт явно. Он **не запускает** роботов, триггеры и бизнес-процессы, настроенные на создание элемента. И он принимает служебные поля, которые обычное создание молча игнорирует: кто создал (`createdBy`), кто изменил (`updatedBy`), кто перевёл на стадию (`movedBy`) и соответствующие даты. Проставить их может только администратор портала — обычному пользователю Битрикс24 ответит отказом по такой записи, остальные записи пакета при этом создадутся. Набор доступных служебных полей у объектов разный; точный перечень отдаёт `GET /v1/leads/fields` — там они помечены `importable`.

У даты создания есть окно, которое задаёт Битрикс24: не позже текущего момента и не раньше, чем у самой свежей уже существующей записи этого объекта. То есть историю целиком получится перенести в пустую CRM или в такую, где всё старше переносимого; «подложить» записи задним числом в наполненную CRM Битрикс24 не даст. Если история не нужна, даты можно не передавать — автор проставляется и без них.

Ответ приходит со статусом `200` даже когда часть записей не прошла: импорт не транзакционен, поэтому исход читается по каждой записи в `results[]`, а сводка лежит в `summary`. Всегда проверяйте `summary.failed` — статус говорит «запрос обработан», а не «всё создано». Повторный импорт создаёт дубли; если повторы возможны, записывайте идентификатор из внешней системы в `originatorId` и `originId`.

Маршрут ограничен по темпу на портал, чтобы массовая заливка не блокировала другие интеграции аккаунта. Импортируйте в один поток: внутри запроса порядок гарантирован, между параллельными запросами — нет, а Битрикс24 требует неубывающих дат создания.

Подробности, коды ошибок и примеры — на странице [Импорт записей CRM](/docs/import).

### FIX-0807-2: версия исходников выкладывается по номеру на своём сервере

**Было**

Версия, сохранённая через [POST /v1/infra/servers/:id/sources](/docs/source-storage), не выкладывалась на том же сервере: [POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) с телом `{ "source": { "versionId": "v1" } }` отвечал `400 SOURCE_VERSION_REQUIRES_APP`, если ключ-владелец сервера не привязан к приложению — то есть на личном ключе `vibe_api_*`. Обойти можно было только вручную: скачать архив по ссылке и выложить его формой `{ "source": { "url": … } }`.

**Стало**

Если сервер принадлежит тому же ключу, которым идёт вызов, версия ищется в контексте этого сервера, и выкладка по `versionId` работает, включая личный ключ. Не нашлась на сервере, а ключ-владелец привязан к приложению — поиск повторяется в контексте приложения, как раньше. Не нашлась нигде — `404 SOURCE_VERSION_NOT_FOUND`; текст ошибки теперь называет сервер и путь сохранения вместо приложения.

Код `SOURCE_VERSION_REQUIRES_APP` не удалён, а сузился: он приходит только там, где сервер принадлежит НЕ вызывающему ключу — менеджмент-ключ и доступ через карточку приложения. Если вы ветвитесь на этот код, ветку оставьте.

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

Менять ничего не нужно. Вызов, который раньше отбивался, теперь проходит; поле `sha256` в ответе сохранено.

Одно исключение, редкое: если на сервере и на его приложении лежат версии с ОДНИМ номером — так бывает, когда версия сохранена до перепривязки сервера на другой ключ, — теперь берётся версия сервера, а не приложения. Проверить, какая именно версия уехала, можно по полю `sha256` в ответе.

### FIX-0807-3: чтение и правка несуществующего дела отвечают 404, а не 422

**Было**

`GET /v1/activities/{id}` и `PATCH /v1/activities/{id}` с идентификатором, которого
на портале нет, отвечали `422` с кодом `BITRIX_ERROR` и текстом вида
`Bitrix24 API error: 400`. Причина внешняя: на этих двух методах Битрикс24 отдаёт
отказ, в котором и код ошибки, и описание пустые, — распознать «записи нет» было
не по чему. При этом `DELETE /v1/activities/{id}` на тот же идентификатор уже
отвечал `404`, потому что там портал текст ошибки присылает. Один и тот же
несуществующий идентификатор давал два разных ответа в зависимости от глагола,
и оба раздела документации — [get](/docs/entities/activities/get) и
[update](/docs/entities/activities/update) — обещали `404`.

**Стало**

Оба метода отвечают `404` с кодом `ENTITY_NOT_FOUND` и сообщением
`Activity is not found.` — тем же, что и `DELETE`. Правило привязано к этим двум
методам и срабатывает только когда портал не прислал ни кода, ни текста: отказ с
любым кодом или сообщением (в том числе ошибка валидации при обновлении) остаётся
как был. Список ошибок в документации не менялся — изменился ответ, который теперь
ему соответствует.

### FIX-0807-4: запрос без тела доходит до обработчика, а не падает на разборе

Часть HTTP-клиентов (axios, PowerShell `Invoke-RestMethod`, некоторые обёртки над fetch)
подставляет `Content-Type: application/x-www-form-urlencoded` в каждый POST, PATCH и DELETE —
даже когда тело не отправляется вовсе. Ещё часть не ставит `Content-Type` совсем. Обе формы
до этой правки не доходили до обработчика.

**Было**

[POST /v1/deals](/docs/entities/deals/create) без тела и без заголовка `Content-Type` отвечал
`500 INTERNAL_ERROR` — обработчик падал на пустом теле раньше, чем успевал проверить, что
создавать нечего. Тот же вызов с пустым телом и заголовком
`application/x-www-form-urlencoded` отвечал `415 Unsupported Media Type` ещё до проверки
ключа. [POST /v1/chats/events/subscribe](/docs/chats/events/subscribe) — тело которому не
нужно вовсе — отвечал `415` с формовым заголовком и `400` с пустым телом под
`application/json`.

**Стало**

Пустое тело принимается независимо от заголовка: `POST /v1/deals` без тела отвечает
`400 EMPTY_CREATE_BODY` — тем же ответом, что и `POST /v1/deals` с телом `{}`;
`POST /v1/chats/events/subscribe` без тела отрабатывает штатно.

Заголовок `Content-Type` с пустым телом теперь не мешает нигде на сущностях
(`/v1/deals`, `/v1/contacts`, `/v1/tasks` и остальные генерируемые маршруты, включая
пакетные и агрегирующие), в чатах (`/v1/chats/*`), в пользовательских полях
(`/v1/userfields/*`, `/v1/items/:entityTypeId/userfields`), в базе знаний (`/v1/note/*`) и в
ключах (`/v1/portals`, `/v1/keys`). Отдельный случай «заголовка нет совсем» — это другая
поломка, и она закрыта на сущностях: там запрос без тела и без заголовка теперь получает
обычный ответ проверки полей вместо `500`.

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

Менять ничего не нужно: запрос, который работал, работает так же. Непустое тело под
незнакомым `Content-Type` по-прежнему отклоняется с `415` — тем же кодом, что и раньше; `413`
приходит только если тело действительно больше допустимого размера. Тело с битым JSON под
`application/json` теперь отвечает `400 INVALID_JSON_BODY` на всех перечисленных маршрутах
(раньше на чатах приходил код разборщика Fastify).

### BC-0807-5: дополнение своего обращения больше не выглядит ответом платформы

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

**Было**

Автором обращения считался конкретный ключ, которым оно создано. Комментарий, отправленный другим ключом того же владельца (или обращение, заведённое из кабинета и дополняемое ключом), уходил в платформенную ветку: записывался как `authorType: PLATFORM`, переводил обращение в `AWAITING_USER` и перезаписывал `Feedback.resolution` своим телом. Тем ключом, которым обращение создано, дополнить решённое обращение было нельзя — [POST /v1/feedback/:id/comments](/docs/feedback/comments) отвечал `409 FEEDBACK_CLOSED`. Единственным обходом было сменить статус через [PATCH /v1/feedback/:id](/docs/feedback/update).

Кроме того, `Feedback.resolution` работал зеркалом последней реплики команды: любой комментарий со скоупом `vibe:feedback` перезаписывал текст решения, и вернуть прежнее значение было нечем. Лимита темпа у операции комментирования не было вовсе.

**Стало**

Автором считается владелец ключа. Обращение, созданное другим вашим личным ключом или заведённое из кабинета, для вас своё: комментарий записывается как `authorType: USER`, поле `resolution` не переписывается, а переданный `status` игнорируется. Одно условие: такому ключу нужен скоуп `vibe:feedback` — без скоупа своим считается только тот ключ, которым обращение и создано. Правило не распространяется на ключи приложений и управляющие ключи — там владелец ключа и тот, кто пишет, разные лица.

Комментарий автора к обращению в статусе `RESOLVED` возвращает его в работу (`NEEDS_REVIEW`) и снимает `resolvedAt` / `resolvedBy`; текст решения при этом сохраняется. Статусы `ARCHIVED` и `WITHDRAWN` остаются закрытыми и по-прежнему отвечают `409 FEEDBACK_CLOSED`.

Поле `resolution` заполняет только комментарий, закрывающий обращение (целевой статус `RESOLVED` или `ARCHIVED`). При любом другом статусе поле не меняется, а текст комментария по-прежнему доходит до автора письмом и виден в ленте.

У операции комментирования появился лимит темпа — 20 комментариев в минуту, как у той же операции в кабинете. Счётчик общий на ВЛАДЕЛЬЦА ключа: несколько своих ключей делят один бюджет. Превышение — `429 RATE_LIMITED` с заголовком `Retry-After`.

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

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

1. **Обработчик `409 FEEDBACK_CLOSED`.** На решённом обращении теперь приходит `201`, и обращение возвращается в работу. Если по этому коду вы решали «обращение закрыто, дальше не пишем», проверку надо перевести на статус из ответа: закрытыми остались только `ARCHIVED` и `WITHDRAWN`.
2. **Ветвление по `authorType`.** Для второго ключа того же владельца значение сменилось с `PLATFORM` на `USER`. Код, который по `PLATFORM` рисует реплику как «ответ поддержки», начнёт показывать её как сообщение пользователя — и это верно, но если у вас на этой ветке висела логика, её надо пересмотреть.
3. **Чтение `resolution`.** Как «последняя реплика команды» поле больше не работает: там лежит вердикт последнего закрытия, а на обращении, которое ни разу не закрывали, поле пустое. За последним ответом команды идите в ленту комментариев — последний элемент с `authorType: PLATFORM`.
4. **Закрытие своего обращения комментарием.** Если вы закрывали своё обращение через `POST /comments` с полем `status`, этот способ больше не работает: у автора `status` игнорируется молча, ответ приходит `201`, а статус остаётся прежним. Отзыв обращения — через [PATCH /v1/feedback/:id](/docs/feedback/update) с `status: WITHDRAWN`.
5. **Обработка `429` на комментариях.** Операция получила лимит темпа, которого у неё не было. Если ваш код шлёт комментарии пачкой или в цикле — добавьте обработку `429 RATE_LIMITED` с паузой по заголовку `Retry-After`. Бюджет общий на владельца ключа, поэтому выпуском второго ключа его не расширить.

Параллельная поддержка прежнего поведения не предусмотрена: прежнее заполнение `resolution` и было тем дефектом, ради которого правка сделана, — сохранять было бы нечего.

**Затронутые эндпоинты:** [POST /v1/feedback/:id/comments](/docs/feedback/comments), [GET /v1/feedback/:id](/docs/feedback/get), [GET /v1/feedback](/docs/feedback/list)

### BC-0807-6: сервер AI-агента больше не принимает выкладку приложения

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

**Было**

`POST /v1/infra/servers/{id}/deploy` принимал архив на сервер, принадлежащий
AI-агенту. Выкладка проходила, код агента затирался чужим приложением, и агент
переставал отвечать. Той же машиной агент числился рабочим — ни в ответе, ни в
интерфейсе следов не оставалось. По этой же причине сервер агента мог быть
переиспользован под приложение при создании нового сервера с тем же именем и
при повторной привязке приложения.

**Стало**

Выкладка в такой сервер отбивается `403` с кодом `AGENT_SLOT_DEPLOY_FORBIDDEN`;
текст ошибки называет рабочую альтернативу — кнопку «Повторить» на карточке
агента или создание отдельного сервера под приложение. Пути повторного
использования сервер агента больше не выбирают: вместо перезаписи создаётся
новый. Управляемые ботов это не касается — они выкладывают свой код через тот
же вызов штатно.

Выписка ключа обслуживания на агента, чей сервер снесён, теперь отвечает `409`
с кодом `AGENT_SERVER_GONE` вместо выдачи ключа, которым некуда идти. Чтение
состояния ключа осталось `200`, в теле появилось поле `reason` со значением
`SERVER_GONE`.

### NEW-0807-7: `GET /v1/cowork/state` сообщает о запланированном понижении тарифа

**Было**

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

**Стало**

Понижение планируется на конец оплаченного периода, и объект `subscription` получил
поле `pendingTier` — код тарифа, на который сиденье перейдёт при следующем списании,
либо `null`. Дата перехода — уже имеющееся поле `currentPeriodEnd`.

Поле аддитивное: клиенты, которые его не читают, работают как раньше. Отменённая
подписка всегда отдаёт `null` — отмена сильнее плана, и обещать тариф закрывающемуся
сиденью нельзя.

### FIX-0807-8: архив исходников галактического приложения добывает сама машина

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

Коды отказа и поля ответа прежние; добавился `UPLOAD_NO_SPACE` для нехватки места на диске. Неизвестный формат архива и ссылки, присланные в теле запроса, идут прежним путём. Затронуто [POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy).

Отдельно: `extractTo` теперь проверяется на стороне платформы, а не только на машине. Набор допустимых путей не изменился ни на [POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy), ни на [POST /v1/infra/servers/:id/upload](/docs/infra/deploy/upload), где своей проверки не было вовсе — отвергается то же, что и раньше, но сразу и с внятным кодом `INVALID_EXTRACT_TO`.

### FIX-0807-9: деплой больше не падает на остановке медленного приложения

**Было**

Повторный `POST /v1/infra/servers/:id/deploy` поверх работающего приложения, которое не
завершается сразу по SIGTERM, падал на шаге `stop_existing` через ~45 секунд:
`DEPLOY_TIMEOUT`, `Deploy step timed out: GATEWAY_TIMEOUT: no response within 45s`. Новая
версия не выкатывалась. Платформа отводила остановке 15 секунд, а операционная система на
сервере — до 90, поэтому приложение, которому на завершение нужно от 45 до 90 секунд,
роняло обновление гарантированно. Подсказка при этом советовала ремонтировать туннель —
ложный след.

**Стало**

Шаг `stop_existing` ждёт остановку столько, сколько ей отведено на сервере (лимит шага —
105 секунд), и больше не прерывает деплой: если остановку не удалось
подтвердить — результат не пришёл ЛИБО сервер ответил, что остановить не смог, — шаг
возвращает `warning` с честным текстом «исход неизвестен» и деплой идёт дальше.
Раньше второй случай не показывался вообще: шаг отдавал `ok`, и о том, что остановка
не удалась, узнать было негде. Сюда же попал соседний шаг очистки каталога: он тоже мог отдать
`ok`, ничего не удалив, если сервер команду не выполнял, — и деплой падал двумя шагами
позже с сообщением, которое причины не называло. Теперь такой случай останавливает деплой
сразу и говорит причину. Когда одновременно занят порт, в
предупреждении остаются оба факта. Ответ по-прежнему `success: true`, статус шага виден в
`data.steps[]`.

### FIX-0807-10: переименование поля шаблона реквизитов проверяется до записи

**Было**

`PATCH /v1/requisite-presets/:presetId/fields/:id` с полем `fieldName`, которого нет
среди доступных, отвечал `200` и `{"updated": true}`, а несуществующее имя реально
сохранялось в строке шаблона. Метод обновления в Битрикс24, в отличие от метода
добавления, не проверяет имя и принимает любую строку — поэтому строка шаблона
оставалась с именем, за которым нет поля, и переставала отображать данные.

**Стало**

Если `fieldName` в теле запроса отличается от имени, которое строка уже несёт, имя
сверяется со списком [GET /v1/requisite-presets/:presetId/fields/available](/docs/entities/requisite-presets/preset-fields/available)
до записи. Имя вне списка — `400` с кодом `INVALID_FIELD_NAME`, обновление не
выполняется; ни одно поле строки не меняется. Имя, занятое другой строкой того же
шаблона, в списке доступных отсутствует и тоже отклоняется. Переименование в
свободное имя проходит как раньше, а регистр имени приводится к написанию, которое
вернул Битрикс24.

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

Изменились три ответа. Мусорное имя вместо `200` даёт `400`: прежний `200` записывал
имя, за которым нет поля, поэтому терялись и остальные поля того же запроса — просто
молча. `fieldName`, переданный не строкой, тоже даёт `400 INVALID_FIELD_NAME`: раньше
такое значение уходило в Битрикс24 и оседало в строке словом `Array`. Запрос с
`fieldName` на несуществующую строку отвечает `404` до записи, а не ответом Битрикс24.

Запрос без `fieldName` работает как раньше. Запрос с тем же именем, что уже стоит в
строке, тоже проходит, но стоит на один вызов к Битрикс24 дороже: чтобы понять, что
имя не меняется, платформа сперва читает строку.

### NEW-0807-11: справочник полей учёта времени задач

Добавлен `GET /v1/task-time/fields` — программный состав полей записи учёта времени. Для каждого из десяти полей отдаются тип, признак «только чтение», подпись и описание. Раньше состав полей был описан только текстом в документации, и клиент не мог получить его вызовом.

Схема одинакова для всех задач, поэтому путь плоский. Вложенный `GET /v1/tasks/:taskId/time/fields` по-прежнему возвращает `400 WRONG_PATH`, но теперь называет в тексте ошибки правильный путь. Запрос требует скоуп `task` и не обращается к Битрикс24.

Числовые по смыслу поля — `id`, `taskId`, `userId`, `seconds`, `minutes`, `source` — объявлены строками, потому что именно строками они и приходят в ответах. Поле `userId` помечено `createOnly`: оно принимается при создании и отклоняется при обновлении.

Затронутые эндпоинты: [GET /v1/task-time](/docs/entities/tasks/time), `GET /v1/task-time/fields`.

### FIX-0807-12: подписи и описания полей daysBeforeClose, fm и FILES в ответе /fields

**Было**

Три поля, которые Битрикс24 отдаёт живьём, приходили без пояснения, а два из них — ещё и с неудобной подписью. [GET /v1/smart-processes/fields](/docs/entities/smart-processes/fields) отдавал `daysBeforeClose` с подписью длиной в предложение вместо краткого названия. [GET /v1/leads/fields](/docs/entities/leads/fields) отдавал `fm` с технической подписью «FM». [GET /v1/timelines/fields](/docs/entities/timelines/fields) отдавал `FILES` с подписью, но без описания, поэтому формат вложений приходилось искать на странице создания комментария.

**Стало**

У всех трёх полей есть `description`. У `daysBeforeClose` подпись сокращена до краткого названия, а прежний длинный текст перенесён в описание. У `fm` подпись заменена на понятную человеку, а описание отправляет к плоским полям `phone` и `email`, через которые те же данные удобнее читать и писать. У `FILES` подпись осталась той, которую прислал Битрикс24, — она зависит от языка портала, — а описание называет формат вложений на запись и на чтение.

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

Менять ничего не нужно: тип поля (`type`) и признак «только для чтения» (`readonly`) по-прежнему приходят от Битрикс24 и не изменились. Если ваш код показывает пользователю значение `label` этих полей, текст станет другим — он берётся из ответа, а не хранится у вас.

### FIX-0807-13: список обращений понимает фильтр в скобочной форме

**Было**

`GET /v1/feedback?filter[status]=RESOLVED` возвращал `200` и весь доступный список: скобочная форма фильтра разбиралась, но не читалась, поэтому и записи, и `total` приходили без фильтра. То же самое с `filter[category]`. Работала только плоская форма — `?status=RESOLVED`.

**Стало**

Обе формы работают одинаково. [GET /v1/feedback](/docs/feedback/list) применяет `filter[status]` и `filter[category]` с той же проверкой, что и плоские параметры: регистр не важен, неизвестное значение отдаёт `400 INVALID_FILTER_VALUE` вместо тихой выдачи всего списка. Если присланы обе формы, побеждает плоская — ответы на запросы, которые работали раньше, не меняются. Значение, которое не является одиночным (`filter[status][]=NEW`), тоже отклоняется с `400 INVALID_FILTER_VALUE`.

### FIX-0807-14: обновление заказа больше не теряет сумму, пометку и её причину молча

**Было**

[PATCH /v1/orders/:id](/docs/entities/orders/update) принимал `price`, `marked` и `reasonMarked` и отвечал `200`, но Битрикс24 эти поля на обновлении не сохраняет. У `marked` и `reasonMarked` значение просто пропадало. У `price` было хуже: сумма пересчитывается из позиций корзины, поэтому запрос с ручной суммой её не менял, а при пустой корзине сохранённая сумма становилась `0` — то есть обновление, посланное с любым другим полем, обнуляло цену заказа. Ответ об этом не сообщал.

**Стало**

Все три поля отклоняются на обновлении с `400 READONLY_FIELD` до обращения к Битрикс24 — на всех трёх поверхностях записи: одиночный `PATCH`, [POST /v1/orders/batch](/docs/batch) с `action: "update"` и [POST /v1/batch](/docs/batch) с `action: "update"`. Создание не изменилось: [POST /v1/orders](/docs/entities/orders/create) и оба батч-создания по-прежнему принимают эти поля и передают их значения. В ответе [GET /v1/orders/fields](/docs/entities/orders/fields) такое поле помечено `readonlyOnUpdate: true`, чтобы отличать его от `readonly` (нельзя и при создании) и от `createOnly` (значение неизменно после создания — про сумму заказа это неверно, её пересчитывает Битрикс24).

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

Параллельная поддержка прежнего поведения не предусмотрена: прежнее поведение состояло в том, что значение молча терялось. Если запрос на обновление посылал эти поля — уберите их из тела, иначе он начнёт отвечать `400`. Чаще всего так делают клиенты, читающие заказ целиком и отправляющие объект обратно: из такого тела нужно убрать `price`, `marked` и `reasonMarked`. Чтобы изменить сумму заказа, меняйте [позиции корзины](/docs/entities/basket-items/create).

### NEW-0807-15: деплой сообщает, что не применил displayName или description

Поля `displayName` и `description` деплой **заполняет, но не переименовывает**: `displayName` записывается, только пока он ещё равен техническому идентификатору сервера, `description` — только пока оно пусто. Раньше присланное значение, конфликтующее с уже заданным, отбрасывалось молча — ответ приходил со статусом 200 и без единого признака, что поле не записано.

Теперь такой ответ несёт дополнительную запись в `warnings[]`: она называет отброшенные поля, подтверждает, что сам деплой прошёл, и предупреждает, что повтор ничего не изменит. Там же — готовое тело запроса к [PATCH /v1/infra/servers/{id}](/docs/infra/servers/update) с уже подставленным текущим именем: у этой ручки `displayName` обязателен, поэтому образец избавляет от случайной перезаписи имени при правке одного описания. Запись добавляется в конец массива, поведение записи в базу не изменилось.

Заодно операция переименования появилась в машинном описании API (`GET /v1/openapi.json`) — раньше схема утверждала, что переименования в этом API нет.

**Затронутые эндпоинты:** [POST /v1/infra/servers/{id}/deploy](/docs/infra/deploy/deploy), [PATCH /v1/infra/servers/{id}](/docs/infra/servers/update)

### FIX-0807-16: переоткрытие обращения больше не стирает текст резолюции

**Было**

`PATCH /v1/feedback/:id` с одним только статусом — например `{"status":"REVIEWING"}` — при возврате обращения из `RESOLVED`, `WITHDRAWN` или `ARCHIVED` обнулял поле `resolution`, хотя в теле запроса его не было. Ответ приходил `200`, о потере в нём ничего не говорилось. Если текст ответа команды не был продублирован комментарием, восстановить его было нечем.

**Стало**

Возврат в активный статус обнуляет только `resolvedAt` и `resolvedBy`. Поле `resolution` не меняется, если вы его не передали: у обращения, возвращённого из `ARCHIVED`, сохраняется и причина архивации. Чтобы заменить текст — передайте `resolution` в том же запросе, чтобы очистить поле — передайте `"resolution": null`. Путь с комментарием (`POST /v1/feedback/:id/comments`) `resolution` не трогал и раньше — теперь обе поверхности ведут себя одинаково.

### BC-0807-17: агрегации дел нужен сужающий фильтр

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

**Было**

`POST /v1/activities/aggregate` принимал запрос без фильтра. На небольшом аккаунте он отвечал за секунду, на большом — не отвечал никогда: первое же обращение к Битрикс24 (подсчёт всех дел аккаунта) не укладывалось в отведённое на вызов время, и клиент получал `503 BITRIX_TIMEOUT` с заголовком `Retry-After` и подсказкой «чтения можно повторять». Повтор давал тот же результат, потому что причина не была временной. Документация при этом прямо предлагала `{}` как «самый быстрый запрос».

`meta.truncated` означало ровно одно: «под фильтр попало больше 5000 записей». Если часть страниц записей до нас не дошла, ответ приходил с `truncated: false` — то есть числовые агрегации и группы были посчитаны по части записей, а ответ этого не сообщал.

**Стало**

Агрегация дел требует одного сужения из трёх: пара `ownerTypeId` + `ownerId`, либо `responsibleId`, либо граница по дате на `createdAt` / `updatedAt` / `deadline`. Требование включается платформой отдельно на каждый аккаунт. Пока оно выключено, поведение прежнее; после включения запрос без сужения получает `400 MISSING_REQUIRED_FILTER` — в `message` перечислены допустимые сужения и готовый пример тела, обращения к Битрикс24 не происходит.

Независимо от этого переключателя запрос **без** сужения, на который Битрикс24 не ответил за отведённое время, теперь возвращает `422 AGGREGATION_LIMIT_EXCEEDED` вместо `503`: отказ терминальный, заголовка `Retry-After` нет, в тексте — что сделать вместо повтора. Запрос **с** сужением по-прежнему получает на таймауте `503` с `Retry-After`: там повтор — честный совет, потому что причину замедления мы не знаем.

Оба ответа приходят и на устаревший `GET /v1/activities/aggregate` — правило нельзя обойти, вызвав его.

`meta.truncated` теперь означает «часть записей до нас не дошла» и в прежнем случае (выборка шире 5000), и в новом (обработано меньше записей, чем всего под фильтр). Во втором случае рядом приходит `meta.recordsShortfall` — сколько записей не хватило. `count` и `meta.totalRecords` при этом остаются полными: неполны только `data.groups` и числовые агрегации. ⚠️ Эта половина изменения касается агрегации ЛЮБОЙ сущности, а не только дел: раньше в таком ответе приходило `truncated: false`, то есть неполнота не сообщалась нигде.

Список допустимых сужений и то, включено ли требование на аккаунте прямо сейчас, приходят в `data.aggregateFilterRequirement` ответа [GET /v1/activities/fields](/docs/entities/activities/fields): поле `anchors` — сужения, поле `enforcement` — `enforced` либо `advisory`. Статические сужения без состояния аккаунта есть и в `GET /v1/guide`.

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

Добавить в агрегацию дел одно из сужений — этого достаточно и до, и после включения требования. Если сегодня в коде есть ветка на `503` для этого эндпоинта, добавить ветку на `422` и не повторять запрос по ней. Если код читает `meta.truncated`, учесть, что теперь он поднимается и при потере записей, и посмотреть на `meta.recordsShortfall`.

### FIX-0807-18: файл в поле CRM больше не упирается в 1 МБ, а код отказа стал понятным

**Было**

Значение пользовательского поля типа «Файл» едет в теле запроса как base64, а тело было ограничено 1 МБ на всех методах. Практический потолок одного файла — около 750 КБ: `PATCH /v1/deals/{id}` с файлом крупнее отвечал `413` и кодом `FST_ERR_CTP_BODY_TOO_LARGE`, которого нет ни в одной странице документации. Тот же потолок бил по загрузке файлов ботам и в чаты.

**Стало**

Тело ограничено 40 МиБ на создании и обновлении записей (`POST /v1/{entity}`, `PATCH /v1/{entity}/{id}`, включая `POST /v1/items/{entityTypeId}`), а также на `POST /v1/bots/{botId}/files` и `POST /v1/chats/{chatId}/files` — это чуть меньше 30 МиБ исходного файла после base64. Остальные методы сохраняют прежний потолок 1 МБ: поиск (`POST /v1/{entity}/search`), пакетные вызовы, служебные методы.

Код отказа `413` теперь `PAYLOAD_TOO_LARGE` на всех методах `/v1/`, кроме маршрутов AI (`/v1/ai/*`, `/v1/chat/*`, `/v1/audio/*`, `/v1/models`) — там сохраняется конверт ошибки, совместимый с OpenAI. Это тот же код, что уже возвращает пограничный слой на своём пороге. Замена затрагивает и потоковую загрузку исходников приложений (`POST /v1/apps/{id}/sources`) и серверов (`POST /v1/infra/servers/{id}/sources`), и отказ `413` на неверном `Content-Type` у публикации приложения, привязки мест встраивания и создания шаблона документа. Прежний внутренний код в ответах больше не встречается.

Порядок проверок изменился в пользу безопасности: на записи сущностей и на загрузке файлов ботам и в чаты ключ проверяется до чтения тела. Запрос без ключа или с неверным ключом теперь получает `401` там, где раньше мог получить `400` о неразобранном JSON или `413` о размере.

Появился новый отказ `429` с кодом `LARGE_BODY_BACKEND_BUSY` и заголовком `Retry-After: 5`: одновременно обрабатываемых тел крупнее 1 МБ ограниченное число. Он защищает память сервера — поднятый потолок сам по себе ничем не ограничен, а каждый ожидающий очереди вызов удерживает своё тело. Обычный клиент его не увидит; массовая заливка в несколько потоков — увидит, и правильная реакция на него та же, что на любой `429`: подождать и повторить.

Учтите время: вызов в Битрикс24 ограничен 15 секундами и не повторяется, поэтому файл у самой границы на медленном аккаунте может отказать с `BITRIX_TIMEOUT`. Оставляйте запас или переносите крупные файлы в поле «Файл (диск)» через `POST /v1/files/upload`.
