Для AI-агентов: markdown этой страницы — /docs-content/changelog/2026-08-07.md индекс документации — /llms.txt
Изменения API: 7 августа 2026
← Журнал изменений · Август 2026
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.
FIX-0807-2: версия исходников выкладывается по номеру на своём сервере
Было
Версия, сохранённая через POST /v1/infra/servers/:id/sources, не выкладывалась на том же сервере: POST /v1/infra/servers/:id/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 и
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 без тела и без заголовка Content-Type отвечал
500 INTERNAL_ERROR — обработчик падал на пустом теле раньше, чем успевал проверить, что
создавать нечего. Тот же вызов с пустым телом и заголовком
application/x-www-form-urlencoded отвечал 415 Unsupported Media Type ещё до проверки
ключа. POST /v1/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 отвечал 409 FEEDBACK_CLOSED. Единственным обходом было сменить статус через PATCH /v1/feedback/:id.
Кроме того, 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.
Что делать интеграторам
Правок требуют пять мест, и найти их в своём коде стоит до обновления.
- Обработчик
409 FEEDBACK_CLOSED. На решённом обращении теперь приходит201, и обращение возвращается в работу. Если по этому коду вы решали «обращение закрыто, дальше не пишем», проверку надо перевести на статус из ответа: закрытыми остались толькоARCHIVEDиWITHDRAWN. - Ветвление по
authorType. Для второго ключа того же владельца значение сменилось сPLATFORMнаUSER. Код, который поPLATFORMрисует реплику как «ответ поддержки», начнёт показывать её как сообщение пользователя — и это верно, но если у вас на этой ветке висела логика, её надо пересмотреть. - Чтение
resolution. Как «последняя реплика команды» поле больше не работает: там лежит вердикт последнего закрытия, а на обращении, которое ни разу не закрывали, поле пустое. За последним ответом команды идите в ленту комментариев — последний элемент сauthorType: PLATFORM. - Закрытие своего обращения комментарием. Если вы закрывали своё обращение через
POST /commentsс полемstatus, этот способ больше не работает: у автораstatusигнорируется молча, ответ приходит201, а статус остаётся прежним. Отзыв обращения — через PATCH /v1/feedback/:id сstatus: WITHDRAWN. - Обработка
429на комментариях. Операция получила лимит темпа, которого у неё не было. Если ваш код шлёт комментарии пачкой или в цикле — добавьте обработку429 RATE_LIMITEDс паузой по заголовкуRetry-After. Бюджет общий на владельца ключа, поэтому выпуском второго ключа его не расширить.
Параллельная поддержка прежнего поведения не предусмотрена: прежнее заполнение resolution и было тем дефектом, ради которого правка сделана, — сохранять было бы нечего.
Затронутые эндпоинты: POST /v1/feedback/:id/comments, GET /v1/feedback/:id, GET /v1/feedback
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.
Отдельно: extractTo теперь проверяется на стороне платформы, а не только на машине. Набор допустимых путей не изменился ни на POST /v1/infra/servers/:id/deploy, ни на POST /v1/infra/servers/:id/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
до записи. Имя вне списка — 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, GET /v1/task-time/fields.
FIX-0807-12: подписи и описания полей daysBeforeClose, fm и FILES в ответе /fields
Было
Три поля, которые Битрикс24 отдаёт живьём, приходили без пояснения, а два из них — ещё и с неудобной подписью. GET /v1/smart-processes/fields отдавал daysBeforeClose с подписью длиной в предложение вместо краткого названия. GET /v1/leads/fields отдавал fm с технической подписью «FM». GET /v1/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 применяет filter[status] и filter[category] с той же проверкой, что и плоские параметры: регистр не важен, неизвестное значение отдаёт 400 INVALID_FILTER_VALUE вместо тихой выдачи всего списка. Если присланы обе формы, побеждает плоская — ответы на запросы, которые работали раньше, не меняются. Значение, которое не является одиночным (filter[status][]=NEW), тоже отклоняется с 400 INVALID_FILTER_VALUE.
FIX-0807-14: обновление заказа больше не теряет сумму, пометку и её причину молча
Было
PATCH /v1/orders/:id принимал price, marked и reasonMarked и отвечал 200, но Битрикс24 эти поля на обновлении не сохраняет. У marked и reasonMarked значение просто пропадало. У price было хуже: сумма пересчитывается из позиций корзины, поэтому запрос с ручной суммой её не менял, а при пустой корзине сохранённая сумма становилась 0 — то есть обновление, посланное с любым другим полем, обнуляло цену заказа. Ответ об этом не сообщал.
Стало
Все три поля отклоняются на обновлении с 400 READONLY_FIELD до обращения к Битрикс24 — на всех трёх поверхностях записи: одиночный PATCH, POST /v1/orders/batch с action: "update" и POST /v1/batch с action: "update". Создание не изменилось: POST /v1/orders и оба батч-создания по-прежнему принимают эти поля и передают их значения. В ответе GET /v1/orders/fields такое поле помечено readonlyOnUpdate: true, чтобы отличать его от readonly (нельзя и при создании) и от createOnly (значение неизменно после создания — про сумму заказа это неверно, её пересчитывает Битрикс24).
Влияние на интеграторов
Параллельная поддержка прежнего поведения не предусмотрена: прежнее поведение состояло в том, что значение молча терялось. Если запрос на обновление посылал эти поля — уберите их из тела, иначе он начнёт отвечать 400. Чаще всего так делают клиенты, читающие заказ целиком и отправляющие объект обратно: из такого тела нужно убрать price, marked и reasonMarked. Чтобы изменить сумму заказа, меняйте позиции корзины.
NEW-0807-15: деплой сообщает, что не применил displayName или description
Поля displayName и description деплой заполняет, но не переименовывает: displayName записывается, только пока он ещё равен техническому идентификатору сервера, description — только пока оно пусто. Раньше присланное значение, конфликтующее с уже заданным, отбрасывалось молча — ответ приходил со статусом 200 и без единого признака, что поле не записано.
Теперь такой ответ несёт дополнительную запись в warnings[]: она называет отброшенные поля, подтверждает, что сам деплой прошёл, и предупреждает, что повтор ничего не изменит. Там же — готовое тело запроса к PATCH /v1/infra/servers/{id} с уже подставленным текущим именем: у этой ручки displayName обязателен, поэтому образец избавляет от случайной перезаписи имени при правке одного описания. Запись добавляется в конец массива, поведение записи в базу не изменилось.
Заодно операция переименования появилась в машинном описании API (GET /v1/openapi.json) — раньше схема утверждала, что переименования в этом API нет.
Затронутые эндпоинты: POST /v1/infra/servers/{id}/deploy, PATCH /v1/infra/servers/{id}
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: поле 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.