For AI agents: markdown of this page — /docs-content-en/changelog/2026-09-20.md documentation index — /llms.txt

API changes: September 20, 2026

← Changelog · September 2026

FIX-0920-1: the OpenAPI specification and the API reference name the required filter keys and count over `"*"`

Before

Nine entities do not run a read without a required filter key: calendar events (type, ownerId), calendar sections, Drive files and folders, timeline comments (entityType, entityId), catalog products and sections (iblockId), product list-property values (propertyId) and org-structure nodes (type). Without the key the operation answers 400 MISSING_REQUIRED_PARAMS or 400 MISSING_REQUIRED_FILTER. The machine specification GET /v1/openapi.json did not say so: on the GET list of all nine entities, on the POST /search of six of them and on POST /v1/catalog-products/aggregate the filter was described as optional. The reference examples led into the same refusal: search printed an empty filter, the list a call without parameters. The aggregation example of over twenty entities counted count over a field, although the operation accepts count over "*" only and answers 400 INVALID_PARAMS, and the list of aggregation fields in the specification did not contain "*". The per-entity batch example POST /v1/{entity}/batch passed limit next to params, where the sub-call does not read it.

After

The specification declares the required keys where the operation requires them. On search and aggregation they are part of the filter description, and search of files and folders also takes the key at the body top level. The folderId / parentId value is described as a non-empty scalar. On the list each key is described as its own query parameter and can be sent as ?type=… or as filter[type]=…, as before. The machine-readable list of keys is added as the x-required-filter-keys extension, and whether a batch call lifts the required parameters of a sub-call as the x-batch-list-lifts-params extension. Each key is named together with its refusal code. The list of aggregation fields contains "*". A batch sub-call is described by its params field. The reference examples pass the required keys, aggregation counts over "*", the batch example puts the parameters into params. Where a batch list cannot receive the required parameters, the example shows get, and create for calendar sections. The responses of the operations have not changed.

Impact on integrators

Working requests are not affected: the operations refused without these keys before. A client generated from the specification gets a required filter on search and aggregation of these entities once regenerated. The exception is search of files and folders: there the key is required, in filter or at the body top level.

BC-0920-2: updating or deleting a missing employee field answers 404

Old format supported until: not provided

Before

PATCH /v1/userfields/users/:id and DELETE /v1/userfields/users/:id answered 422 BITRIX_ERROR with the message Access denied. for an id the Bitrix24 account does not have — the same answer a genuine permission refusal produces. Deleting an already deleted field answered the same way, while GET /v1/userfields/users/:id answered 404 for that id. An id written with leading zeros was not resolved by GET either: 007 answered 404, although updating and deleting the same field by 007 worked.

After

The platform checks whether the field exists before updating or deleting it. No field — the answer is 404 ENTITY_NOT_FOUND, and no write request reaches Bitrix24. The same code comes back for a repeated delete and for the id of a field that is not an employee field. The permission refusal is unchanged: a key whose owner is not a Bitrix24 account administrator still gets 422 BITRIX_ERROR with the message Access denied.. In addition, GET /v1/userfields/users/:id now resolves an id written with leading zeros: 007 reads as 7, the way update and delete have always treated it.

What integrators should do

Move the "field is missing" branch from 422 BITRIX_ERROR to 404 ENTITY_NOT_FOUND, exactly as it is already written for CRM fields. A repeated DELETE answering 404 means the field is already gone, not an error. Keep the 422 BITRIX_ERROR branch with the message Access denied. — it now means either insufficient rights or a race where the field was removed between the check and the write. Update and delete each take one extra request to Bitrix24.

FIX-0920-3: two simultaneous server creations for one application now yield one machine

Before

Two POST /v1/infra/servers calls arriving at nearly the same moment with the key of one application that had no server yet both went through: each saw an application without a server, and each created a billable machine. One of them was bound to the application card; the other kept running and kept being charged while showing up neither on the card nor in reuse — it could only be found in GET /v1/infra/servers and had to be deleted by hand.

After

This is about an ordinary create — a call WITHOUT placement: "dedicated". The application's seat for its server is taken indivisibly on the Vibecode platform, at the same moment the server row is written to the database and before the cloud is called at all. This covers applications calling the API with an authorization key too: their card used to receive its server only at deploy time, and until then every further create raised one more machine — now the server lands on the card immediately and a repeat call returns that same server. A second machine is therefore no longer born: the call that arrives late for the free seat stops before anything is paid for, and answers 201 with the server the first call created plus reused: true, so there is nothing to retry. If that late call carried source, the response itself says what became of it, and that depends on whether there is anything to damage. When the server handed back is being deployed onto by the first call right now — and always for an ordinary server, onto which a create never deploys source at all — a second deploy on top of somebody else's is not started: the response carries sourceIgnored: true, so watch the server's state and deploy your own source in a separate call if it differed. When there is nothing to damage (the application's server has never been deployed onto), the late call's source is deployed as usual and the response carries deploying: true. Read those fields instead of assuming the outcome. When converging on that server is not possible, the answer is 409 with the new code APPLICATION_SERVER_SLOT_TAKEN and no machine is created for it either. That answer means the application has no server to hand back right now: its card was deleted meanwhile, or the machine sitting on it cannot be handed back — it is dead, or it is a shared host. Repeating the call in either case creates a NEW server rather than returning the old one, so read GET /v1/applications before repeating.

The protection also works before the application has a card: the first call raises the server, the second gets 409 with the code APPLICATION_FIRST_SERVER_IN_PROGRESS, and the retry returns the existing server as soon as the card appears. The two refusal codes are deliberately different, because they call for different actions: after APPLICATION_FIRST_SERVER_IN_PROGRESS a retry returns the server, after APPLICATION_SERVER_SLOT_TAKEN it creates a new one. Branch on the code — the message text is not meant for that. Two boundaries remain, both deliberate. The first is a call with placement: "dedicated": there an additional machine is exactly what you are asking for, and refusing it would be wrong. The second is an account with the Applications section switched off: no cards are created there at all, both machines stay visible in the server list, and neither is lost. Keep your own protection against repeated calls on those two paths. Successful responses of single creations are unchanged.

BC-0920-4: the clientId field is removed from the Cowork employee list response

Old format supported until: not provided

Before

The portal block of the GET /v1/platform/cowork/members response carried a clientId field. For cloud accounts it was always empty: the column it was read from is not filled for any cloud account.

After

The portal block has no clientId field. The account is still identified by portalNetworkId and portalDomain; the other response fields are unchanged.

What integrators should do

Nothing, if the field was never read. If your client expects a clientId key in the portal block, drop that check: its value was empty anyway. Address the account through portalNetworkId.

FIX-0920-5: server status stops reporting "connected" while the tunnel is dead

Before

When a server's connection to the platform dropped silently, the server status could stay CONNECTED forever: the server card showed the server as running while calls to the application external API no longer arrived. The caller got 503 APP_API_UNAVAILABLE, but the state never corrected itself — the server stayed that way until the connection happened to come back, and the status could not tell "the application is quiet right now" apart from "there is no connection at all".

After

On a refusal caused by a dropped connection, the platform checks the actual list of live connections and, when the connection is genuinely gone, clears the incorrect CONNECTED — the server status becomes DISCONNECTED and the server enters the regular recovery path. The check runs only on that refusal branch and only on a confirmed absence: while the list of live connections is unavailable, or the connection is present in it, the status is left alone. The answer to the caller is unchanged — 503 APP_API_UNAVAILABLE, with no new error codes.

FIX-0920-6: the OpenAPI schema declares the scope refusal on entity read operations

Before

Entity read operations — list, read by id, fields, search, aggregate, related-record and product-row reads — declared no 403 response in the OpenAPI schema, although the Vibecode API answers 403 with code SCOPE_DENIED when the key lacks the scope the operation requires. The requirement itself was published all along: the x-required-scope extension and the "Requires scope" sentence in the operation description. A client generated from the schema had no error model for the most ordinary refusal and met it as an unexpected server answer.

After

Every entity read operation declares 403 with code SCOPE_DENIED and names the codes that reach the same status from the shared key gate and from Bitrix24 itself. The fields operation deliberately names no Bitrix24 code there, for two reasons. Where the entity has a live field method, that fetch is best-effort and its failure arrives as a successful answer carrying the fields_partial warning. Where it has none, the field set is served from the declared contract and no Bitrix24 call happens at all — as the operation's own description states.

Impact on integrators

Nothing to do: endpoint behaviour is unchanged and the codes and statuses stay as they were. Regenerate your client from the schema to get a typed branch for the scope refusal.

BC-0920-7: batch writes and import no longer answer with success when Bitrix24 did not apply the stage or the manual amount

Old format supported until: not provided

Before

The single PATCH /v1/deals/{id}, POST /v1/deals/{id}/move (and the lead counterparts) already answered 422 STAGE_NOT_APPLIED, and POST / PATCH /v1/items/{entityTypeId} answered 422 AMOUNT_NOT_APPLIED, when Bitrix24 accepted the write but did not apply the stage, the pipeline, or an explicitly requested manual amount mode. The same writes sent through POST /v1/{entity}/batch, the global POST /v1/batch and POST /v1/{entity}/import answered success: true per item: the deal stayed on its previous stage (on import — landed on the default stage), the smart-process item amount became zero, and the caller saw success.

After

In POST /v1/{entity}/batch an item whose stage, pipeline or manual amount Bitrix24 did not apply comes back with success: false, the code STAGE_NOT_APPLIED or AMOUNT_NOT_APPLIED in error, an explanation in message and details.unappliedFields / details.currentValues; such an item keeps its id — the record was already created or updated, do not repeat it. In the global POST /v1/batch such a sub-call moves from data.results to data.errors under its id, with the same code / message / details, and the record Bitrix24 returned in the answer to the sub-call arrives in data.errors.<id>.data. In POST /v1/{entity}/import the result row gets the same fields and keeps its id as well. For both batch doors no additional Bitrix24 calls were added: the record compared is the one Bitrix24 already returns in the answer to each sub-call. After all chunks, import re-reads the created records once per page of fifty, and only those that carried a stage, a pipeline or an explicit manual amount mode — every other import costs exactly what it did before; import runs no automation rules, so the re-read record is the outcome of the import itself. Single create POST /v1/deals and POST /v1/leads does not verify the stage and answers as before: Bitrix24 automation does run there, and a robot «on creation — change stage» would produce a false refusal. A lead Bitrix24 itself converted in simple CRM mode on creation is not counted as an unapplied stage; on an update of an already closed lead an unapplied stage is refused, as in the single PATCH. Writes with valid values answer as before; an amount without an explicit isManualOpportunity: true is still not checked.

FIX-0920-8: the previous turn's reasoning reaches the model again

Before

In a tool dialogue the previous assistant turn's reasoning, returned in messages[].reasoning_content, did not reach the model: the platform passed it to the cluster under a name the model template does not read. The model lost the thread between tool calls, and the reasoning text did not count towards input tokens.

After

The platform passes the reasoning under the name the model template reads, so in a tool dialogue the model sees its previous reasoning again. The request field is unchanged: return the reasoning in messages[].reasoning_content, as described in function calling. The reasoning text now counts towards input tokens, so usage.prompt_tokens is higher for such requests.

Affected endpoints: POST /v1/chat/completions.