# API changes: July 2, 2026

[← Changelog](/docs/changelog) · [July 2026](/docs/changelog/2026-07)

### NEW-0702-1: filter and sort tasks by real status (realStatus)

`GET /v1/tasks`, `POST /v1/tasks/search` and `POST /v1/tasks/aggregate` now accept `realStatus` in `filter` (list and search also in `sort`) — filtering by the task's actual stored status: 1 — new, 2 — pending, 3 — in progress, 4 — awaiting control, 5 — completed, 6 — deferred, 7 — declined. Previously `filter[realStatus]` was silently ignored and the request returned the whole set.

Unlike `filter[status]`, which Bitrix24 treats as a virtual (meta) filter (values −1 overdue, −2 unviewed, −3 almost overdue) that does not match the `status` field value in the response, `realStatus` filters by the stored status. The field is read-only (change the status via `status`) and is used only in `filter`/`sort` — the response already exposes the task's real status in the `status` field.

### FIX-0702-2: creating an app reuses a failed slot with the same name

**Before**

Repeating [POST /v1/infra/servers](/docs/infra/servers/create) with the same `name` after a failed deploy created a new app slot. Failed slots piled up and were only removed by auto-cleanup after 7 days.

**After**

If the key owner already has a slot with the same `name` in the account in `error` status (or one that was created but never received a deploy), the repeated call returns that same slot: its `id` is preserved, the error and build log are reset, and the status goes back to `provisioning` — deploy into it. Slots that never received any code are now removed by auto-cleanup after 24 hours instead of 7 days (slots with a failed build are still kept for 7 days together with their build log).

**Impact on integrators**

No request changes are required. If your flow re-created a slot with the same name after a failure, you will start receiving the previous `id` instead of a new one — this is expected: deploying into the returned slot works as usual. Slots owned by other users of the account and running apps are never picked up for reuse.

### FIX-0702-3: read-only keys can no longer write through /v1/bots

**Before**

A read-only API key (`accessMode: READONLY`) could perform write operations through the bot endpoints ([POST /v1/bots](/docs/bots/management/create), sending and deleting messages, adding chat members, registering and deleting a bot, and others) — the call returned 200 instead of 403. Every other Bitrix24 proxy surface already blocked such writes.

**After**

A write through `/v1/bots/*` with a read-only key returns 403 with code `WRITE_BLOCKED_READONLY_KEY`. Read operations are unaffected, including fetching a message context ([GET /v1/bots/:botId/messages/:messageId/context](/docs/bots/messages/context)) and downloading a file ([GET /v1/bots/:botId/files/:fileId](/docs/bots/files/download)).

**Impact on integrators**

If your bot integration needs to write, switch the key to read+write mode in the /keys section.

### FIX-0702-4: folders include=storage now resolves

**Before**

`GET /v1/folders/:id?include=storage` (and the list form `GET /v1/folders?parentId=...&include=storage`) did not add `_included` to the response, even though `GET /v1/folders/fields` advertises `includable: true` for the `storage` relation.

**After**

The related storage now resolves: the response includes `_included.storage` with the storage record looked up by `storageId`. The relation is described in [GET /v1/folders/fields](/docs/entities/folders/fields).

### FIX-0702-5: PAGE_BACKGROUND_WORKER: bind no longer fails with 500

**Before**

`POST /v1/placements/bind` for the `PAGE_BACKGROUND_WORKER` placement filled in the `options.errorHandlerUrl` field Bitrix24 requires only when the call went through an OAuth session. When an app bound via a developer key or on a self-hosted portal, the field was not added and Bitrix24 answered 500 (`BITRIX_UNAVAILABLE`, "Field errorHandlerUrl is empty"), even though other placements bound fine.

**After**

For `PAGE_BACKGROUND_WORKER` the `options.errorHandlerUrl` value now defaults to `handler` regardless of the bind path. An explicit `options.errorHandlerUrl` still takes precedence. The response `options` field now reflects the effective value (with the defaulted `errorHandlerUrl`).

**Impact on integrators**

No action required — a call that previously returned 500 now succeeds.

### FIX-0702-6: POST /search reports missing required parameters with a clean error

**Before**

`POST /v1/{entity}/search` for entities whose Bitrix24 list method requires mandatory parameters did not check for them and forwarded the request to Bitrix24 as-is. A raw Bitrix24 error leaked out (`BITRIX_ERROR`, e.g. "Invalid value of parameter [ `$id` ]" or "required parameter `type` is not set"), whereas the equivalent `GET` list already returned a clear `400 MISSING_REQUIRED_PARAMS` in the same case. Affected [POST /v1/calendar-events/search](/docs/entities/calendar-events/search) (needs `type`), [POST /v1/files/search](/docs/entities/files) (needs `folderId`) and [POST /v1/folders/search](/docs/entities/folders) (needs `parentId`).

**After**

`POST /v1/{entity}/search` validates the required parameters before calling Bitrix24 — the same guard the `GET` list has had for a while. A missing parameter returns `400` with code `MISSING_REQUIRED_PARAMS` and the list of missing fields, with no call to Bitrix24. The required parameter can be passed inside `filter`, and the parent parameter (`folderId` for files, `parentId` for folders) may also be passed at the top level of the request body.

### NEW-0702-7: Research price in the key self-description and the required top-up in the 402 body

[GET /v1/me](/docs/keys-auth) now returns `cost` for every provider in the `webResearch.providers[]` block, mirroring the `webSearch` block. The field carries the research-mode price in Ꝟ (`cost.research`) and the currency (`cost.currency`), so an agent sees the deep-search price directly in the key self-description, without a separate call.

The `402` response on insufficient balance (`INSUFFICIENT_BALANCE`, as well as `BILLING_FROZEN`) on [POST /v1/search](/docs/search/run) and [POST /v1/research](/docs/search/research) now carries a `required` field — the amount in Ꝟ needed for the request. The existing `userMessage` and `hint` fields are unchanged.

Clients with strict `additionalProperties` schema validation need to account for the new response fields.

### NEW-0702-8: POST /v1/triggers/fire supports invoices (SmartInvoice)

The [POST /v1/triggers/fire](/docs/automation/triggers/fire) endpoint accepts a new `entityType` value — `invoice`. Pass `entityType: "invoice"` and the invoice `entityId` (returned by [GET /v1/invoices](/docs/entities/invoices)) to fire an automation trigger for a smart invoice. Existing values (`deal`, `lead`, `contact`, `company`, `quote`, `item`) keep working unchanged.

Previously firing a trigger for an invoice was impossible, and trying it through `entityType="item"` with `entityTypeId=31` was rejected with a message that led to a dead end. Now `item` with a reserved `entityTypeId` (including 31) points to the matching `entityType` — for invoices, that is `invoice`.

### NEW-0702-9: GET /v1/ai/usage returns transcribed audio duration per model

[GET /v1/ai/usage](/docs/ai/consumption/usage) now returns an `audioSeconds` field in the `byModel[]` block — the total number of audio seconds sent for transcription per model over the selected period. The field is populated for speech-to-text (Whisper) calls and is `0` for text models, where audio duration does not apply.

The field is additive — existing integrations keep working unchanged.

### BC-0702-10: categories: code and isDefault marked read-only (were phantom-writable)

> Old format supported until: 01.10.2026

**Before**

`GET /v1/categories/:entityTypeId/fields` advertised `code` and `isDefault` as writable (`readonly: false`), but writing them via `crm.category.add`/`update` was silently ignored (values not persisted, `200` returned).

**After**

Both fields are marked `readonly: true`. `/fields` now reports them as read-only, and an attempt to write `code` or `isDefault` returns `400 READONLY_FIELD` instead of silently dropping the data.

**What integrators must do**

Previously, sending `code`/`isDefault` in a `POST`/`PATCH` `/v1/categories/:entityTypeId` body was accepted (`200`, values silently ignored). Now such a request returns `400 READONLY_FIELD`. Remove `code` and `isDefault` from your category create/update request bodies — these fields are no longer accepted on write.

### BC-0702-11: telephony-lines: crmAutoCreate normalized to boolean and now listed in /fields

> Old format supported until: 01.10.2026

**Before**

`GET /v1/telephony-lines/fields` returned only `number`, `serverName`, `name`. The CRM auto-create flag leaked into list responses under the raw UPPER name `CRM_AUTO_CREATE` as a `"Y"`/`"N"` string — the only UPPER field among camelCase ones — and was absent from `/fields`. On write, camelCase `crmAutoCreate` was silently dropped.

**After**

The field is declared as `crmAutoCreate` (boolean). It now appears in `/fields`, comes back normalized (`true`/`false`) in `list` responses instead of raw `"Y"`/`"N"`, and is accepted as a camelCase boolean on `create`/`update` (the raw UPPER name is still accepted on write for compatibility). Clients reading `data[].CRM_AUTO_CREATE` should switch to `data[].crmAutoCreate` (boolean).

### NEW-0702-12: workgroups: aggregate operation and groupBy fields exposed

**Before**

`POST /v1/workgroups/aggregate` worked but was never advertised: the operation was missing from the machine index at `/v1/guide`, and `groupBy` returned `400` on any field (`Available: .`) because the aggregatable list was empty.

**After**

An aggregatable list is declared: `membersCount` (numeric sum/avg/min/max) plus categorical `active`, `isProject`, `ownerId` for grouping. The operation is now visible in `/v1/guide` and `/fields`, and `groupBy` over these fields works.

### FIX-0702-13: /fields: metadata completeness for doc-templates and bookings

**Before**

`GET /v1/doc-templates/fields` omitted `isDefault` and `productsTableVariant` even though they appear in list responses. On `GET /v1/bookings/fields` the mandatory `resourceIds` and `datePeriod` were not flagged `required`, so their obligatoriness was invisible in the schema.

**After**

`doc-templates`: `isDefault` and `productsTableVariant` are declared (read-only) — `/fields` now matches the responses. `bookings`: `resourceIds` and `datePeriod` are marked `required: true`, so the requirement is visible in `/fields`.

### FIX-0702-14: orders: /fields synced with responses, pseudo-key order removed, companyId filterable

**Before**

`GET /v1/orders/fields` carried a spurious pseudo-key `order` (an artifact of parsing `sale.order.getFields`) and omitted fields that actually appear in responses: `companyId`, `clients`, `dateMarked`, `personTypeXmlId`, `statusXmlId`, `version`. Because `companyId` was not in the schema, filtering by it failed with `UNKNOWN_FILTER_FIELD`.

**After**

`/fields` is now built from the schema: the `order` pseudo-key is gone and the six missing fields are declared (`companyId` — writable number; `clients` — read-only object returned by `get`; `dateMarked`/`personTypeXmlId`/`statusXmlId`/`version` — read-only). Filtering and sorting by `companyId` now work.

### FIX-0702-15: users: limit > 50 now honored, meta.hasMore is accurate

**Before**

`GET /v1/users?limit=500` returned only 50 records even though `meta.total` reported more. `meta.hasMore` was always `false`, so the documented `hasMore`-based pagination silently dropped everything past the first page.

**After**

The entity is backed by the legacy `user.get` method (no `.list` suffix), so the auto-paginator never engaged. A `paginateViaStart` flag was added (same as departments): for `limit > 50` it now walks pages via `start`, and `meta.hasMore` reflects whether more records actually exist.

### FIX-0702-16: POST /v1/batch rejects disabled write operations and forwards required list parameters

**Before**

A global [POST /v1/batch](/docs/batch) call with action create, update or delete for an entity whose operation is disabled (for example openline-configs — writes live behind dedicated routes) went straight to Bitrix24, bypassing normalization, and could silently create or modify a record. Separately: action list or search for an entity with required method parameters (for example calendar-events — type and ownerId) returned AUTO_PAGINATION_FAILED "missing required parameter", even though a direct list request with the same parameters worked. In addition, batch list for folders and files sent the parent folder under the name parentId or folderId, which the disk.folder.getchildren method ignores, so the list silently came back for the wrong folder; and batch list for calendar-events with a leftover filter key forwarded it to Bitrix24 with no error, so the method returned the whole calendar.

**After**

A disabled write operation in a sub-call is rejected with ACTION_NOT_SUPPORTED before any Bitrix24 call — the same as POST /v1/{entity}/batch. Required list parameters and the method's top-level parameters are forwarded to Bitrix24 under their original names, so batch list behaves like the direct list, and when they are missing a clear MISSING_REQUIRED_PARAMS is returned instead of a raw Bitrix24 error. For folders and files the parent folder is now renamed to the id key the method expects, so batch list comes back for the right folder. For entities whose method has no filter envelope (calendar-events), a leftover filter key is now rejected with UNSUPPORTED_FILTER before any Bitrix24 call — the same as the direct list.

**Integrator impact**

No action needed. If a batch sub-call previously relied on a disabled write operation running, switch it to the entity's dedicated route. For batch list on entities with required parameters (calendar-events), pass type and ownerId in the sub-call params. If a calendar-events batch list used filter, drop it or move it to the top-level parameters, otherwise the sub-call returns UNSUPPORTED_FILTER.

### NEW-0702-17: GET /:entity/fields now returns field label and description

The `GET /v1/{entity}/fields` response can now carry a human-readable short name `label` and an explanatory `description` per field — previously a field was described only by the `{type, readonly}` pair. This lets an AI agent or UI show a field's name and purpose without consulting the documentation. The text is returned in English. The keys were added for the following entities: Departments, Smart Processes, Storages, Folders, Files, Workgroups, Document Templates, Bookings, Calendar Events, Tasks, Requisites, Users. For Users the label resolution was additionally fixed: `GET /v1/users/fields` now returns the real Bitrix24 field names from `user.fields` instead of the technical codes. The change is additive: the new keys appear alongside the existing ones, and existing calls keep working unchanged.

### FIX-0702-18: a vibe:*-only key now issues instead of failing

**Before**

Issuing an API key via `POST /v1/keys` whose every requested scope is an internal Vibecode `vibe:*` scope (for example only `vibe:infra`), on a dev-key portal (self-hosted Bitrix24 or a connected cloud portal), was rejected with `502 DEVKEY_MINT_FAILED`. `vibe:*` scopes are never sent to Bitrix24, so the Bitrix24 webhook scope set came out empty and Bitrix24 rejected the mint, requiring at least one scope.

**After**

A `vibe:*`-only key now issues successfully. No Bitrix24 webhook is created for it — none is needed, such a key never calls the Bitrix24 REST — and the key works with Vibecode's internal features per its scopes.

**Impact on integrators**

No action required: the request that previously failed now returns the created key.

### FIX-0702-19: /v1/storages pagination — limit over 50 returns all records, meta.hasMore is correct

**Before**

`GET /v1/storages` with `limit` over 50 returned at most 50 records, and `meta.hasMore` was always `false` — even when the account held more. A client requesting `?limit=50` against 489 storages saw `hasMore: false` and could not tell it needed to fetch the next page. Same on `POST /v1/storages/search` and in `/v1/batch`.

**After**

`limit` over 50 goes through auto-pagination (like every other list) and returns the requested number of records, and `meta.hasMore` equals `(offset + returned count) < meta.total` even for `limit` of 50 or less. The change applies to `GET /v1/storages`, `POST /v1/storages/search` and the `storages` list in `/v1/batch`.

Note: the correct `meta.hasMore` calculation for list responses with `limit` of 50 or less now applies to all entities (`GET /v1/{entity}` and `POST /v1/{entity}/search`), not only `storages` — previously `meta.hasMore` was always `false` on this path.

### FIX-0702-20: infra: Cyrillic in displayName on application create

**Before**

On [POST /v1/infra/servers](/docs/infra) with a Cyrillic `displayName`, the name could be stored as a run of question marks (`??????`) — an encoding corruption while sending to Bitrix24.

**After**

The name is transmitted as UTF-8 and Cyrillic is preserved correctly.

**Impact on integrators**

No action required. Cyrillic names are no longer mangled.

### FIX-0702-21: items: filtering by parentId<N> relation fields

**Before**

Filtering by a dynamic relation field (for example `parentId2` — the linked deal) on [GET /v1/items/:entityTypeId](/docs/entities/items/list) and [POST /v1/items/:entityTypeId/search](/docs/entities/items/search) was rejected with `400 UNKNOWN_FILTER_FIELD`, even though the field is present in `GET /v1/items/:entityTypeId/fields` and returned in responses.

**After**

Fields shaped like `parentId<N>` are accepted in the filter and forwarded to the request as-is. Finding a smart-process item linked to a specific parent entity now works directly through the items wrapper.

**Impact on integrators**

No action required. Requests that previously returned `400` now succeed.

### FIX-0702-22: smart processes: enumeration values and the userfield display name now persist

**Before**

On [POST /v1/items/:entityTypeId/userfields](/docs/userfields/smart-processes) an enumeration field (`userTypeId: enumeration`) was created but its value variants were not saved (the list came back empty), and a display name passed as a plain string stayed blank in the interface.

**After**

Value variants are accepted both as `enum` and as `list` and are saved correctly. A name passed as a plain string is automatically wrapped into a language map and fills the edit-form, list-column and list-filter labels.

**Impact on integrators**

No action required. The enumeration values and the name that were previously dropped silently now persist.

### FIX-0702-23: req-family: address and preset-field /fields now return camelCase keys

**Before**

`GET /v1/addresses/fields` and `GET /v1/requisite-presets/:presetId/fields/schema` returned the field description with raw UPPER_SNAKE_CASE keys (`TYPE_ID`, `ADDRESS_1`, `FIELD_NAME`, `IN_SHORT_LIST`), even though the data of these entities (`GET /v1/addresses`, the preset field list) already came back in camelCase — the schema did not match the real field names in the data.

**After**

Both endpoints normalize the description keys to camelCase (`typeId`, `address1`, `fieldName`, `inShortList`), like the rest of V1. The inner field descriptors (`type`, `isRequired`, `isReadOnly`, `title`) are unchanged.

**Impact on integrators**

The `/fields` response keys now match the field names in the data. A client that read the camelCase names from the data gets a consistent schema; no action required.
