# API changes: September 29, 2026

[← Changelog](/docs/changelog) · [September 2026](/docs/changelog/2026-09)

### NEW-0929-1: Catalog measure and VAT rate reference data

The Vibecode API now provides `GET`, `POST`, `PATCH`, and `DELETE` for `/v1/catalog-measures` and `/v1/catalog-vat-rates`. Clients can read valid `measure` and `vatId` values before creating a product. Search, fields, and batch are also available for both entities.

### BC-0929-2: employee and requisite sorting now orders by identifier

> Old format supported until: not provided

**Before**

`sort=-id` and `order[id]=desc` did not change the order of employees, requisites, and requisite presets. Sorting employees by another ordinary field could be silently ignored while the request returned HTTP 200 with rows.

**After**

Both forms sort these lists by `id` in descending order on single endpoints, search, and `POST /v1/batch`. For employees, `id` is the only supported ordinary sort field. Other ordinary fields are rejected with `UNKNOWN_SORT_FIELD`. `UF_*` keeps its previous passthrough on one page and is rejected with `INVALID_SORT_FIELD` for multi-page retrieval. Responses to supported requests remain HTTP 200.

**What integrators need to do**

ID sort requests need no changes. Do not use other ordinary employee fields. Keep `UF_*` to single-page requests and remember that its order still depends on Bitrix24.

**Affected endpoints:** [GET /v1/users](/docs/entities/users/list), [POST /v1/users/search](/docs/entities/users/search), [GET /v1/requisites](/docs/entities/requisites/list), [POST /v1/requisites/search](/docs/entities/requisites/search), [GET /v1/requisite-presets](/docs/entities/requisite-presets/list), [POST /v1/requisite-presets/search](/docs/entities/requisite-presets/search), [POST /v1/batch](/docs/batch).

### BC-0929-3: Cowork ERP management status lists the EMAIL channel only when the account has an email address

> Old format supported until: not provided

**Before**

With `admin.stepUp.required: true`, `GET /v1/cowork/onec/status` always included `EMAIL` in `admin.stepUp.channels`.

**After**

For an account without an email address, `EMAIL` is not included in `admin.stepUp.channels`. The list may contain only `PORTAL` or be empty with `required: true`. The response for an account with an email address is unchanged.

**What integrators should do**

Build the channel choice from `admin.stepUp.channels` instead of assuming `EMAIL`. An empty list with `required: true` means the action cannot be confirmed right now.

### NEW-0929-5: catalog services are available through V1

The Vibecode API now provides `/v1/catalog-services` for listing, searching, reading, creating, updating, and deleting services. List and search require `filter.iblockId`. Service prices use the existing `/v1/catalog-prices` endpoint.

### FIX-0929-6: heavy revenue export pages no longer fail with 503 after 5 seconds

**Before**

An export page whose database query ran longer than 5 seconds answered `503` with code `DB_TRANSIENT` and the text "Service temporarily overloaded. Retry after a few seconds.", even though the export's own query budget is 25 seconds and nothing was overloaded. This showed most often on the first page of `GET /v1/platform/revenue/charges` over a long window; `GET /v1/platform/revenue/topups`, `GET /v1/platform/revenue/expirations`, `GET /v1/platform/revenue/refunds`, `GET /v1/platform/revenue/consumption/by-service`, `GET /v1/platform/revenue/money-in` and `GET /v1/platform/revenue/money-in/payments` could answer the same way. A retry a few seconds later sometimes went through and sometimes failed again.

**After**

An export query gets the full declared 25-second budget, and a page that fits in it answers HTTP 200. The response format, the traversal order and the cursors are unchanged.

**Impact on integrators**

None. Keep retrying on `503` after `Retry-After` — it is still needed for genuine short-lived failures. If a reconciliation over a window was interrupted by such a response, simply restart it: all of these endpoints only read data.

### FIX-0929-7: /v1/me lists only scopes obtainable on the Bitrix24 account

**Before**

`GET /v1/me` suggested reissuing a key for `performan` on a Bitrix24 account without the required flag. Public `GET /v1/openapi.json?scope=performan` differed from a request with an unknown name.

**After**

`scopeRequirements.missing` lists a flag-gated scope only when the Bitrix24 account can obtain it; an already granted scope remains in `granted`. Public `?scope=performan` returns the same full specification variant as an unknown name.

### NEW-0929-8: connector gateway for Cowork

The Vibecode API answers [POST /v1/connectors/mcp](/docs/connectors-mcp), an MCP gateway through which the Cowork desktop calls tools of connected services. The gateway is behind a feature flag and accepts only the Cowork desktop key, any other key gets `403 CONNECTOR_KEY_NOT_ALLOWED`. While the feature is not enabled, the path answers `404 ROUTE_NOT_FOUND`.

### FIX-0929-9: the Cowork/Code tier change preview quotes the discounted price

**Before**

`GET /v1/cowork/subscription/preview` quoted the plan price for the term in `chargeVibes` and `netVibes` even when a platform discount applied to the purchase: the purchase then charged less than the preview showed.

**After**

`chargeVibes` and `netVibes` include the discount this purchase will receive — exactly the amount that will be charged. Renewing a plan that is already paid and repeating the current plan get no discount, the same as the purchase itself. The response shape is unchanged and the response remains HTTP 200.

### NEW-0929-10: cause and action in Bitrix24 permission and scope refusals

`403 BITRIX_ACCESS_DENIED` responses and `422 BITRIX_ERROR` responses whose `b24Code` is `ACCESS_DENIED_EXTEND` or `NO_AUTH_FOUND` carry new optional fields. `error.cause` distinguishes a refusal by the rights of the Bitrix24 user (`b24_permission`), a scope missing on the key's credential (`b24_scope`) and a cause that cannot be determined (`unknown`). `error.fix` names the action (`action`) and where it is performed (`via`); `error.method` is the Bitrix24 method, at most 100 characters; `error.requiredScope` is the missing scope when it is known; `error.hint` is always present on these refusals. The values of `cause`, `fix.action` and `fix.via` are open sets: read an unknown value as `unknown` or `none`. Response codes and statuses are unchanged. Values explained — [Authorization, keys and permissions](/docs/errors/auth#bitrix_access_denied-403).

### FIX-0929-11: a post permission refusal returns an English message

**Before**

[PATCH /v1/posts/{id}](/docs/feed/posts/update), [DELETE /v1/posts/{id}](/docs/feed/posts/delete) and [POST /v1/posts/{id}/share](/docs/feed/posts/share) returned the Bitrix24 account's text as is in `error.message` when Bitrix24 refused access to the post — on a Russian-language account that text was in Russian.

**After**

`error.message` of such a refusal is the fixed English text `Bitrix24 denied access to this post.`, and the response also carries `error.cause`, `error.method`, `error.fix` and `error.hint`. The code and status are unchanged — `403 BITRIX_ACCESS_DENIED`.

**Impact on integrators**

Client code that branches on `error.code` needs no change. Parsing the `error.message` text of this refusal is no longer needed.

### BC-0929-12: File and folder search validates both supplied parent folder IDs

> Old format supported until: not provided

**Before**

In [POST /v1/files/search](/docs/entities/files/search) and [POST /v1/folders/search](/docs/entities/folders/search), a parent folder ID could be supplied both at the body top level and in `filter`. If one value was valid, a malformed value in the other location could reach the Disk call or go unnoticed.

**After**

Both supplied values must be non-empty scalars. A request with an object, array, `null`, or an empty string in either location is rejected before the Disk call. Two valid values still use the top-level value.

**What integrators should do**

If an ID is present in both locations, remove the malformed value and keep the valid `folderId` or `parentId`. Such a request could previously succeed when the valid value was at the top level.

### NEW-0929-13: balances export: user counters per Bitrix24 account

The `GET /v1/platform/revenue/balances` row gains three fields. `usersInVibecode` is the number of the Bitrix24 account's users registered on the Vibecode platform, the same value as `portal.usersInVibecode` in `GET /v1/platform/cowork/members`. `usersLoggedIn` is how many of them have signed in to Vibecode at least once. `usersInvited` is how many are registered but have never signed in. The numbers add up: `usersLoggedIn + usersInvited = usersInVibecode`.

`0` and `null` are different answers. A Bitrix24 account with no users returns `0` in all three fields. `null` in `usersLoggedIn` and `usersInvited` means the sign-in status of some of its users cannot be established; `usersInVibecode` is still a number in that case.

Deactivated users are not counted. A change in the counters does not move the account's `updatedAt` and does not show up in a `changedSince` query: fresh values come with a full pass without `changedSince`. The existing row fields, query parameters and pass order are unchanged.

### BC-0929-14: chat read boundaries, file metadata and publication recovery

> Old format supported until: not provided

**Before** A personal `vibe_api_*` key in `READONLY` mode received `403 WRITE_BLOCKED_READONLY_KEY` for [GET /v1/chats/{dialogId}/load](/docs/chats/messages/load), [GET /v1/chats/{dialogId}/messages?format=v2](/docs/chats/messages/list), and [GET /v1/chats/messages/{messageId}/context](/docs/chats/messages/context).

**After** These employee reads are allowed when the key has the `im` scope and the user has Bitrix24 access, the successful read response remains HTTP 200. If the chat allows auto-join, the call may make the employee a member. Bitrix24 updates presence on these reads. Chat loading may also trigger lazy project conversion. REST parameters cannot disable these effects. The method bodies do not mark messages read. Explicit state-changing commands remain blocked for a read-only key.

**What integrators should do** A personal employee read-only key can perform these named reads without enabling write commands. Guest session authentication is outside this contract. Successful response shapes are unchanged.

**Before** [GET /v1/chats/files/{fileId}](/docs/chats/files/file-get) accepted an `im`-only key and looked up an arbitrary Disk file ID. Message [PATCH /v1/chats/{dialogId}/messages/{messageId}](/docs/chats/messages/update) and [DELETE /v1/chats/{dialogId}/messages/{messageId}](/docs/chats/messages/delete) did not verify that `messageId` belonged to `dialogId`.

**After** READONLY requires an existing chat: `chatN`, or a numeric peer (including a resolved `me`) proved by the same employee’s recent list. The check scans at most 4000 raw rows; an unproved binding receives `403 WRITE_BLOCKED_READONLY_KEY` before a method that could create a chat. Metadata requires both `im` and `disk`, plus the user’s Bitrix24 access to the file. A missing scope returns `403 SCOPE_DENIED` before contacting Bitrix24. A message mutation is permitted only after finding the exact ID in the named dialog’s visible history. A mismatch returns `404 MESSAGE_NOT_FOUND_IN_DIALOG`, a received lookup response that cannot confirm membership returns `503 MESSAGE_MEMBERSHIP_UNAVAILABLE`; other preflight errors retain their ordinary API status and code. Neither refusal sends a mutation. In the [GET /v1/chats/recent](/docs/chats/discovery/recent), offset counts visible unique rows. Window validation is bounded to 20 pages or 4,000 rows, returning `503 RECENT_WINDOW_UNAVAILABLE` instead of partial success when the budget is exceeded. Metadata contains eight fields: `id`, `name`, `size`, `type`, `detailUrl`, `createdBy`, `createdAt`, `updatedAt`. The former optional `downloadUrl` is removed from metadata and successful file uploads to avoid returning a URL containing Bitrix24 credentials. Successful HTTP 200 message mutation responses are preserved. Chat file upload still requires `im`. In [POST /v1/chats/messages/bulk](/docs/chats/messages/bulk), a duplicate computed key (`id`, otherwise `dialogId`) now returns `400 INVALID_PARAMS` before any call to Bitrix24 instead of dropping the first item. Unique string keys, including Object property names, are preserved. Batch cursors accept non-negative safe integers and decimal-digit strings within the same range; null continues to omit a cursor. Validation and normalization run before sending the request to the Bitrix24 account. Incomplete or contradictory batch outcomes and unusable event polling responses return `502 BITRIX_ERROR` instead of a false HTTP 200. An empty recent page claiming continuation, or a row without a confirmed ID, returns `503 RECENT_WINDOW_UNAVAILABLE`; healthy response shapes are preserved.

**What integrators should do** For a read-only key, use an existing `chatN` or a private binding from recent dialogs; handle an unproved-context refusal. Add `disk` to metadata-reading keys. For bytes, replace `downloadUrl` with authenticated [GET /v1/files/{fileId}/download](/docs/entities/files/download), using `disk` or `crm`. Pass the dialog that contains the message to be changed. Handle membership refusals and do not try to mutate a message through a different dialog. Use the v2 cursor for deep recent-list navigation and handle temporary window-check refusal. The former `im`-only access closes immediately to correct the scope boundary.

**Before** A publication failure after uploading a file to Drive did not explain whether the file remained. Automatic replay or deletion after an ambiguous refusal could create a duplicate or delete an attached file.

**After** [POST /v1/chats/{chatId}/files](/docs/chats/files/upload) does not automatically replay upload or publication. A failure after upload preserves its original status and code and adds `meta.uploadRecovery` with the file and chat IDs and the publication and cleanup outcomes. Deletion is permitted only after a confirmed pre-attachment refusal and affects only this request’s file. An unknown outcome preserves the file. The successful HTTP 201 response contains `fileId`, `name`, `size`, without the former optional `downloadUrl`.

**What integrators should do** Inspect chat history and the named file’s metadata before recovery. Do not automatically replay an upload whose publication outcome is unknown.

**Before** [GET /v1/chats/{chatId}/folder](/docs/chats/files/folder) could initialize a missing Drive folder with a read-only key.

**After** Initialization requires `READWRITE`; closing modes receive `403 WRITE_BLOCKED_READONLY_KEY` before this method is called. File listing, metadata and byte reads retain their read rules.

**What integrators should do** Use a key with write access to retrieve the folder. After upload, verified local refusals before publication dispatch permit deletion of only this request's file; unknown outcomes preserve it. Upload, publication and compensation do not automatically replay after 429 or scope refusals.

**Before** [POST /v1/chats](/docs/chats/management/create) forwarded `users` without local validation; malformed entries could produce a Bitrix24 error or be dropped when creating the chat.

**After** Before `im.chat.add`, a provided list is checked as an array of positive safe integer IDs. Numbers and canonical decimal strings without leading zeros or spaces are normalized to numbers; malformed input receives `400 INVALID_PARAMS` before the method call. An omitted list or an empty array remains valid. The READONLY write refusal still precedes body validation. Entity-binding fields, including opaque `entityId` values such as `DEAL|1663`, are preserved.

**What integrators should do** Send valid participant IDs instead of relying on malformed values being silently dropped. Correct the list shape before retrying after `400 INVALID_PARAMS`.

### NEW-0929-16: catalog SKUs and offers are available through V1

The API now provides `/v1/catalog-skus` and `/v1/catalog-offers` for listing, searching, reading, creating, updating, and deleting records. List and search require the relevant catalog's `filter.iblockId`. An offer can be free or linked to a parent SKU through `parentId` on creation.

### NEW-0929-17: Chats: dialog list sections, shared chats, changes since a moment, chat pinning and reading

The chats section gained ten endpoints on the Bitrix24 messenger v2 methods. Dialog list sections are read in pages: [GET /v1/chats/recent/channels](/docs/chats/discovery/recent-channels) returns public channels by the `lastMessageId` cursor, [GET /v1/chats/recent/collabs](/docs/chats/discovery/recent-collabs) returns collab chats, and [GET /v1/chats/recent/external](/docs/chats/discovery/recent-external) returns the chats of one section by its `type` code, such as task chats or calendar event chats, both by the `lastMessageDate` cursor and the `hasNextPage` flag. [GET /v1/chats/shared](/docs/chats/discovery/shared) returns the chats shared with the given employee, and [GET /v1/chats/sync](/docs/chats/discovery/sync) returns changes to chats, messages and pins since the given moment. A chat is pinned in the dialog list with [POST /v1/chats/:dialogId/pin](/docs/chats/management/pin), its position among the pinned chats is set with [PUT /v1/chats/:dialogId/pin](/docs/chats/management/pin-sort), and the pin is removed with [DELETE /v1/chats/:dialogId/pin](/docs/chats/management/unpin). [POST /v1/chats/read-all](/docs/chats/management/read-all) marks all of the user's chats as read, and [POST /v1/chats/recent/read](/docs/chats/management/read-section) marks the chats of one list section as read. Limits outside the range are clamped with an echo in `meta`, and an unknown or repeated parameter or an extra body field is refused with `400 INVALID_PARAMS`. Pinning, changing the pinned order and marking as read are writes: a read-only key gets `403 WRITE_BLOCKED_READONLY_KEY` for them, as described on the [access rights](/docs/access-rights) page.

### FIX-0929-18: The legacy chat list supports deep offsets again

[GET /v1/chats/recent](/docs/chats/discovery/recent) without `format=v2` again forwards a deep `OFFSET` to Bitrix24 and reads one page with a possible refill for a hollow boundary row, as before Stage 2. Prefix replay, the 4,000-row window and the new `503 RECENT_WINDOW_UNAVAILABLE` refusals were removed. Ordinary keys also retain the original query parameters for legacy message reads; the READONLY protected-selector filter remains. This restores compatibility instead of the changes in the !4345 BC fragment.

### NEW-0929-19: write catalog list-property values through V1

The Vibecode API now supports creating, partially updating, and deleting list-property options: `POST /v1/catalog-product-property-enums`, `PATCH /v1/catalog-product-property-enums/:id`, and `DELETE /v1/catalog-product-property-enums/:id`. A partial update fills omitted Bitrix24-required fields from the existing record.

### NEW-0929-20: cause and a ready transfer step in the BOT_ACCESS_DENIED refusal

The `403 BOT_ACCESS_DENIED` response (the bot is bound to another API key) carries new optional fields: `error.cause` with the value `bot_other_key`, `error.fix` and `error.hint`. When the calling key can run the transfer to itself, `error.fix` is `{ "action": "transfer_bot", "via": "same_key", "path", "body" }`: `path` is the ready route `POST /v1/bots/{botId}/transfer` with the bot identifier from the request, and `body` holds the identifier of the calling key itself. The response never names the key the bot is bound to. Otherwise `error.fix.action` is `none`, and `error.hint` names the reason. The code, status and `error.message` are unchanged. Details — [Authorization, keys and permissions](/docs/errors/auth#bot_access_denied-403).
