# Изменения API: 4 сентября 2026

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

### NEW-0904-1: асинхронные вызовы инструментов 1С и статус операции

Появились `POST /v1/onec/tools/{method}/call` и `GET /v1/onec/operations/{operationId}`. Вызов инструмента создаёт долгоживущую операцию и отвечает `202` с `operationId`, `status` и `expiresAt`, а заголовок `Location` ведёт на адрес статуса. Статус проходит значения `pending`, `running`, `succeeded`, `failed`, `cancelled`, `expired`; у успешной операции есть `result`, у неуспешной — безопасный `error`. Результат хранится 24 часа, затем адрес статуса отвечает `410 ONEC_OPERATION_GONE`. Операция доступна только исходному порталу, пользователю и API-ключу. На порталах без включённого коннектора 1С оба адреса отвечают `404`.

В этом выпуске поверхность объявлена, но недоступна: механизма связи пользователя с пользователем 1С ещё нет, поэтому любой вызов инструмента отвечает `403 ONEC_USER_NOT_MAPPED`, операция не создаётся, и описанный цикл `202` → опрос статуса пройти нельзя. Он заработает с выпуском связывания пользователей; до него интегрировать вызов инструмента не нужно.

### NEW-0904-2: признак «Поддерживает BitrixMobile» при регистрации приложения

`POST /v1/apps` принимает необязательное поле `mobile: boolean`, по умолчанию `false`. При `true` платформа сообщает Битрикс24 признак «Поддерживает BitrixMobile» в момент регистрации приложения на аккаунте, и приложение становится видно в мобильном клиенте. Поле `mobile` появилось и в объекте приложения — в ответах создания, [данных приложения](/docs/apps/get), [списка](/docs/apps/list) и [перепривязки](/docs/apps/relink-oauth). У приложений, созданных раньше, значение `false`. Признак задаётся только при создании — `PATCH /v1/apps/:id` поле `mobile` не принимает. Если аккаунт регистрирует приложение способом, который признак не передаёт, приложение создаётся с `mobile: false`, а в `warnings` ответа создания приходит строка, начинающаяся с `mobile:`. Прежние запросы без `mobile` работают как раньше. Подробнее — [Создать приложение](/docs/apps/create).

### BC-0904-3: код отказа для коробок переименован в SELFHOSTED_NOT_AVAILABLE

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

**Было**

Отказ коробочному Битрикс24 на международной установке приходил кодом
`INT_BOX_PARTNER_REQUIRED`. Текст отказа объяснял, что доступ даёт партнёрская
лицензия, а по ключу партнёрская пометка не подтверждена, и предлагал
переподключить модуль на портале. Кнопка вела в документацию по подключению
коробки: `details.upgradeUrl` и `alternatives[0].url` содержали адрес страницы
`/docs/connect-self-hosted-bitrix24`.

**Стало**

Тот же отказ приходит кодом `SELFHOSTED_NOT_AVAILABLE`. Клиент, разбирающий
ответ по коду, обязан заменить строку — старый код больше не отдаётся ни на
одной поверхности.

Остальное в ответе не изменилось: статус по-прежнему HTTP 402, поле
`details.requiredTariffs` по-прежнему пустое (отказ не снимается покупкой
тарифа), набор `alternatives` тот же и в том же порядке.

Изменились текст и адрес кнопки. Текст больше не называет причину отказа и не
просит ничего делать на портале: коробка пока не поддерживается, доступ
открывается постепенно, серверы и данные портала сохраняются. `details.upgradeUrl`
и `alternatives[0].url` теперь содержат `mailto:` адреса поддержки — единственный
адрес, по которому вопрос решается.

### FIX-0904-4: подсказки о trial-развёртывании учитывают пригодность galaxy-хоста

**Было**

[GET /v1/me](/docs/keys-auth/me) обещал one-shot развёртывание при наличии любого запущенного или спящего galaxy-хоста. Если хост не мог принять приложение, [POST /v1/infra/servers](/docs/infra/servers/create) отказывал, а подсказка предлагала two-step создание, которое затем упиралось в лимит trial-портала.

**Стало**

[GET /v1/me](/docs/keys-auth/me) показывает one-shot путь только когда известный хост выглядит пригодным для размещения, и явно отмечает прогноз как рекомендательный. Авторитетным остаётся [POST /v1/infra/servers](/docs/infra/servers/create); если непригодный хост занимает trial-лимит и контроль ограничений включён, ответ больше не советует заведомо недоступное two-step создание.

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

Перед one-shot созданием проверяйте `deployment.galaxyApp`, а после отказа следуйте `error.hint`. Для двухшагового пути дополнительно проверяйте `capabilities.servers.create.available` и выбирайте план из `capabilities.servers.create.limits.allowedPlans` того же ответа.

### FIX-0904-5: карточка каталога не публикуется без привязки к порталу

**Было**

Публикация могла завершиться со значением `SYNCED` в `b24CatalogSync.status`, хотя карточка
каталога оставалась без привязки к отправителю. В таком состоянии уведомление о новой версии
приложения не приходило в чат, а причина не отображалась.

**Стало**

При вызове [POST /v1/infra/servers/:id/b24-catalog/publish](/docs/infra/servers/b24-catalog-publish)
такая карточка больше не создаётся. Для спаренного портала публикация завершается только после
подтверждения привязки карточки к отправителю. Пока подтверждение не получено,
`b24CatalogSync.status` остаётся не `SYNCED`, `pendingOp` остаётся `ADD`, а `lastError` называет
причину. Ответ по-прежнему HTTP 200, и успешная публикация возвращает то же самое, что и раньше.

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

Менять запросы не требуется. Если интеграция отслеживает асинхронный статус, сочетание
`pendingOp=ADD` со статусом, отличным от `SYNCED`, означает, что карточка ещё не опубликована.
Следует дождаться изменения статуса или показать пользователю значение `lastError`.

### FIX-0904-6: expiresAt предподписанных ссылок равен сроку их подписи

**Было**

[POST /v1/storage/objects/multipart/create](/docs/storage/upload/multipart-create) считал `parts[].expiresAt` от запрошенного срока — 24 часа для каждой части, а [GET /v1/apps/{id}/sources/{versionId}/download](/docs/source-storage/versions) и [GET /v1/infra/servers/{id}/sources/{versionId}/download](/docs/source-storage/servers) — от фиксированных 30 минут; ссылка из перенаправления [GET /v1/storage/objects/{key}](/docs/storage/objects/get) документировалась как действующая 10 минут. Отключённый сейчас [POST /v1/storage/objects](/docs/storage/upload/presigned) отвечает `503 STORAGE_PRESIGNED_UPLOAD_DISABLED` и считал `expiresAt` так же. Подпись ссылки могла истечь раньше, и хранилище отвечало `403`, пока `expiresAt` ещё оставался в будущем.

**Стало**

`expiresAt` в этих ответах берётся из подписи самой ссылки и равен её сроку. Он может быть короче 24 часов сессии составной загрузки и короче 30 минут для ссылок на скачивание; ссылка из перенаправления тоже может истечь раньше 10 минут. Для отключённого `POST /v1/storage/objects` ничего не меняется: он по-прежнему отвечает `503`, а после включения его `expiresAt` тоже будет браться из подписи. Ответ остаётся HTTP 200, формат полей не меняется.

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

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

### FIX-0904-7: латинская локаль называет пробный доступ Битрикс24 словом trial

**Было**

В латинских локалях пробный доступ Битрикс24 назывался demo, хотя сам Битрикс24 на международной установке называет его trial. Расхождение доходило и до контракта: [GET /v1/me](/docs/keys-auth/me) отдавал в `data.tariff.name` значение `Demo period`, а отказ `BY_PAID_ONLY` — текст `Paid or demo Bitrix24 plan required (Belarus)`. Внутри одного сценария активации соседние сообщения расходились между собой: одно говорило trial, другое demo про тот же самый доступ.

**Стало**

Значение тарифа и текст отказа в латинских локалях сведены к слову trial. `GET /v1/me` отдаёт для этого тарифа `Trial period`, отказ `BY_PAID_ONLY` — `Paid or trial Bitrix24 plan required (Belarus)`. Клиент, который сравнивает `data.tariff.name` или текст отказа со строкой, должен пересмотреть сравнение: сами коды, статусы и поля ответа не изменились, и успешный ответ остаётся успешным. Русская локаль по-прежнему говорит «демо».

Охват этой записи — контракт: значение тарифа и текст отказа. Подсказка возможности `apps.bindPlacements` того же эндпоинта и статьи документации на момент публикации ещё говорили demo, их перевод вышел позже — запись FIX-0907-11.

### FIX-0904-8: батч-подзапрос currencies больше не отдаёт meta.total 0 при непустом data

**Было**

[POST /v1/batch](/docs/batch) со списочным подзапросом `currencies` публиковал `data.meta.<id>.total: 0` и `hasMore: false`, хотя в `data.results.<id>` лежали записи. Метод Битрикс24 `crm.currency.list` отдаёт конвертный `total: 0` рядом с непустым результатом, и на батч-двери этот литеральный ноль принимался за размер коллекции. Клиент, который листает по `hasMore`, при `limit` меньше справочника читал первую порцию и считал набор исчерпанным — хвост терялся.

**Стало**

На считанном подзапросе ноль из конверта больше не побеждает посчитанный размер набора: `data.meta.<id>.total` и `data.totals.<id>` показывают размер до клиентского среза, а `hasMore` считается как `offset + returned < total` и остаётся `true`, пока хвост есть. Правило совпало с одиночными эндпоинтами, где эта особенность метода нормализовалась и раньше. Непосчитанный подзапрос (`params.withTotal: false`, отрицательный `params.start`) по-прежнему не получает `total`, а честный пустой справочник по-прежнему отдаёт `total: 0`. Ответ остаётся HTTP 200.

### NEW-0904-9: партнёрское приложение отзывает свой ключ само

Добавлена ручка [POST /v1/connect/revoke](/docs/partner-connect) по RFC 7009: приложение передаёт `client_id`, `client_secret` (публичные клиенты — без него) и `token` и гасит ровно тот ключ, который предъявило. Место в лимите ключей пользователя на портале освобождается сразу, запросы с ключом начинают отвечать `401 KEY_INACTIVE`.

Ответ `200` приходит и когда гасить было нечего — на неизвестный токен, на чужой ключ и на уже отозванный, поэтому вызов идемпотентен и по нему нельзя выяснять перебором, живы ли чужие ключи. Отсутствие `client_id` или `token` даёт `400 invalid_request`, неизвестный клиент или неверный секрет — `401 invalid_client`. Ключ, выданный до деактивации клиента, отозвать тоже можно.

Ручка объявлена в документе обнаружения `/.well-known/oauth-authorization-server` полями `revocation_endpoint` и `revocation_endpoint_auth_methods_supported`. До неё отозвать выданный приложению ключ могли только пользователь в разделе «Подключённые приложения», владелец приложения полным удалением клиента и администратор платформы; все три способа работают как раньше.

### BC-0904-10: смещение в справочниках статусов и воронок работает на любой глубине

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

**Было**

[GET /v1/statuses](/docs/entities/statuses/list) возвращал одни и те же записи при `offset=0`,
`50`, `100` и `300`. Метод Битрикс24, на котором работает справочник, отдаёт весь набор одним
ответом и навигацию не применяет, а обёртка резала этот ответ с начала — клиент получал первую
страницу под видом пятидесятой. При смещении, не кратном 50, окно повторялось с периодом 50:
`offset=130` отдавал те же записи, что `offset=30`.

Обход по смещению завершался, но собирал дубли и не доходил до конца справочника: из 267 записей
через список было достижимо около 50, а `meta.total` при этом называл честные 267. Ошибки не
было ни на одном шаге — все ответы приходили с кодом 200. То же поведение было у
[GET /v1/deal-categories](/docs/entities/deal-categories/list) и у списочных подзапросов в
[POST /v1/batch](/docs/batch).

При этом списочный подзапрос батча БЕЗ явного `limit` вёл себя иначе, чем тот же список за
одиночным запросом: одиночный [GET /v1/statuses](/docs/entities/statuses/list) отдавал 50 записей
по умолчанию, а подзапрос батча — весь справочник целиком, все 267 записей одним ответом.

**Стало**

Окно `[offset, offset + limit)` вычисляется на стороне платформы Вайбкод по полному набору, в
том порядке, который вернуло ядро. `offset=50&limit=5` отдаёт 51-ю…55-ю записи, `limit` больше
50 не обрезает хвост, `meta.total` равен размеру набора с учётом фильтра, а `meta.hasMore`
становится `false` на последней странице. Обход по смещению завершается и покрывает каждую
запись ровно один раз. Ответ по-прежнему приходит с кодом `200`.

Списочный подзапрос батча теперь подчиняется тому же правилу по умолчанию, что и одиночный
запрос: без явного `limit` он отдаёт первые 50 записей и `hasMore: true`, а не весь справочник.

Сортировка и фильтрация по-прежнему выполняются на стороне Битрикс24, поэтому параметр `sort`
работает как раньше. То же поведение применяется на
[POST /v1/statuses/search](/docs/entities/statuses/search) и в списочных подзапросах
[POST /v1/batch](/docs/batch).

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

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

Менять код нужно в одном случае: подзапрос [POST /v1/batch](/docs/batch) со списком статусов или
воронок, у которого `limit` не задан явно. Раньше он отдавал весь справочник, теперь — первые 50
записей. Ошибки при этом не будет, ответ придёт с кодом `200` и с `hasMore: true`, поэтому
недостающие записи потеряются молча, если их не запросить.

Что делать: либо задать `limit` явно, либо читать справочник постранично, увеличивая `offset` на
размер страницы, пока `meta.hasMore` не станет `false`. Второй вариант предпочтителен — он не
зависит от размера справочника и работает на любом портале.

### BC-0904-11: История рабочего дня возвращает смещение часового пояса

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

**Было**

[GET /v1/workday/records](/docs/workday/records) требовал только `timeman`. В записи не было обязательного `tzOffset`, поэтому клиент не мог надёжно получить местное время сотрудника.

**Стало**

Ручка требует `timeman` и один из скоупов `user_brief`, `user_basic` или `user`. Каждая запись содержит обязательный `tzOffset` — смещение в секундах восточнее UTC, вычисленное для момента `startTime` по историческим правилам текущей IANA-зоны `TIME_ZONE` из профиля сотрудника. Значение не доказывает, что эта зона была назначена сотруднику при создании записи. Строки `startTime` и `endTime` не изменяются. Если текущую зону профиля или смещение по ней нельзя достоверно определить, непустая страница возвращает `502 BITRIX_UNAVAILABLE`; смену зоны после создания записи API обнаружить не может и 502 в этом случае не обещает.

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

Перевыпустите существующие ключи с `timeman` и одним user-family скоупом, затем обрабатывайте обязательный `tzOffset` в ответе [GET /v1/workday/records](/docs/workday/records).

### NEW-0904-12: асинхронные вызовы учётной системы под связанным пользователем

`POST /v1/onec/tools/{method}/call` ставит операцию в очередь под активной связью текущего пользователя и требует scope `vibe:onec`. Тело задаёт только метод, колонки, фильтры и пагинацию: идентификатор и имя пользователя сервер берёт из настроек портала, без клиентского override и без fallback-учётной записи. Ответ `202` содержит `operationId`, а состояние и результат доступны через `GET /v1/onec/operations/{operationId}` тому же порталу, пользователю и ключу.

### BC-0904-13: Чтение данных по сущностям получило лимит запросов на портал

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

**Было**

Чтение данных по сущностям — список (`GET /v1/deals` и аналогичные для всех сущностей), поиск (`POST /v1/deals/search`), агрегаты (`POST /v1/deals/aggregate`, включая устаревший `GET …/aggregate`), описание полей (`GET /v1/deals/fields`), связанные записи (`GET /v1/deals/{id}/contacts`, `…/activities`), товарные позиции (`GET /v1/deals/{id}/products`) — и батч по сущности (`POST /v1/deals/batch` и аналогичные) принимали запросы без ограничения частоты — при том, что общий `POST /v1/batch` лимит уже нёс. Один клиент, читающий список чаще примерно десяти раз в секунду, замедлял списки и поиск для всех порталов той же площадки вплоть до обрыва по времени. Запрос `HEAD` к списку обслуживался как полноценный `GET`: данные читались целиком, а отдавались только заголовки.

**Стало**

На каждое такое чтение действует лимит **300 запросов в минуту на портал**; все API-ключи одного портала делят один лимит, у каждой сущности и у каждой операции он считается отдельно. При превышении API Вайбкод отвечает `429 RATE_LIMITED` с заголовком `Retry-After`; срока в теле ответа нет — берите его из заголовка. Текущее значение лимита приходит в заголовке `x-ratelimit-limit`. Батч по сущности ограничен строже — **30 запросов в минуту на портал**, как и общий `POST /v1/batch`: один такой запрос разворачивается в сотни обращений к Битрикс24. Метод `HEAD` на этих адресах чтением больше не обслуживается — вместо него используйте `GET` с `limit=1`. Успешные ответы, коды ошибок и формат данных не изменились.

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

Обрабатывать `429` на всех чтениях по сущностям и на батче так же, как на `/v1/search` и `/v1/batch`: дождаться срока из `Retry-After` и повторить. Если лимит срабатывает регулярно — читать реже и крупнее (`limit` до 5000 за один вызов), кэшировать результаты у себя и не запускать одинаковые чтения параллельно. Если вы проверяли доступность списка методом `HEAD` — используйте `GET` с `limit=1`. Батч разумнее укрупнять, а не учащать: в один запрос помещается до 500 элементов.

### NEW-0904-14: счета поддерживают include=deal

[GET /v1/invoices/:id](/docs/entities/invoices/get), [GET /v1/invoices](/docs/entities/invoices/list) и [POST /v1/invoices/search](/docs/entities/invoices/search) теперь принимают `include=deal`. Связанная сделка из `parentId2` возвращается в `_included.deal`. Если связи нет, значение равно `null`.
