# API changes: October 20, 2026

[← Changelog](/docs/changelog) · [October 2026](/docs/changelog/2026-10)

### FIX-1020-1: the reference and OpenAPI show the actual response of five operations

**Before**

The OpenAPI response schema of `GET /v1/users/me` listed five fields (`id`, `name`, `lastName`, `email`, `isAdmin`), although the call returns the whole user record. Its reference card printed a `userType` field the response does not carry. The cards of `POST /v1/chats/{chatId}/mute`, `GET /v1/activities/{activityId}/transcript` and `POST /v1/leads/{id}/convert` showed a chat, activity or lead record in the response example and the field list instead of what the operation returns. The `POST /v1/crm-documents/{id}/public-url` example carried a long link, while Bitrix24 returns a short one.

**After**

The `GET /v1/users/me` schema describes the user record fields under the same names as `GET /v1/users/{id}`, without `userType`, and allows keys beyond them: `WORK_*`, some `PERSONAL_*` keys and the account's `UF_*` fields arrive in UPPER_SNAKE_CASE. The card prints exactly those fields. The mute, transcript and convert cards show the operation's response: `{ chatId, muted }`, `{ transcription }` and `{ lead, deal, contact, company }`. The public-url example is a short link such as `https://<account address>/~a1B2c`. The documentation caught up with the actual response: the HTTP 200 response of these operations and its content are unchanged.

**Impact on integrators**

No client change is needed. A client built from the former card could expect the fields of a chat, activity or lead record, and `userType` from `GET /v1/users/me`. They were never in the response and still are not: read the fields the reference now lists.

### FIX-1020-2: Neutral server repair error messages

**Before**

The `error` field in `GET /v1/infra/servers/{id}/repair-status` could contain an internal server management error when a repair failed.

**After**

Server management errors now return a neutral English hint with an incident code. Include this code when contacting support. The `DISK_FULL:` machine prefix for insufficient disk space is preserved. The response schema and HTTP status codes are unchanged.

### FIX-1020-3: Public refusal reasons for bot updates and event polling

This change applies only to PATCH `/v1/bots/{botId}` and GET `/v1/bots/{botId}/events`. Bot registration, registration recovery, and resubscription retain their existing contracts.

**Before**

[PATCH /v1/bots/{botId}](/docs/bots/management/update) could return HTTP 409 with an internal refusal reason and `Retry-After: 5`, even when retrying could not help. [GET /v1/bots/{botId}/events](/docs/bots/events) built its recovery refusal separately from the shared handler.

**After**

On PATCH, bot lifecycle refusals use three public classes: `BOT_RECOVERY_IN_PROGRESS` with `Retry-After: 5`, `BOT_EFFECT_IN_PROGRESS` with `Retry-After: 30`, and `BOT_UNAVAILABLE` without `Retry-After`. The last class means that the bot state needs repair through support. Event polling uses the same handler after releasing its poll slot. Its current path only originates the recovery refusal `BOT_RECOVERY_IN_PROGRESS` with the same five-second wait. An unfinished bot mutation alone does not refuse a poll.

**Impact on integrators**

For PATCH, use the public class and its retry delay. Shared normalization also protects the poll error boundary, without introducing new refusals for polling. The behavior of `BOT_EVENTS_BUSY` and `BOT_ID_REPLACED` responses is unchanged.

### FIX-1020-4: marking notifications read accepts an empty body with a JSON header

**Before**

[POST /v1/notifications/read](/docs/notifications/read) with the `Content-Type: application/json` header and an empty body was refused with `400 FST_ERR_CTP_EMPTY_JSON_BODY` before the request was processed. The same request without the header went through.

**After**

An empty body and a whitespace-only body sent with the `Content-Type: application/json` header are handled as `{}`. The response is the same as for the body `{}`. A request with no body and no header is still handled as `{}`, as before. In the `format=v2` mode an empty body is checked as a body without the `ids` field and is refused with `400 INVALID_PARAMS`. A body that does not parse as JSON is still refused with `400 FST_ERR_CTP_INVALID_JSON_BODY`.

**Impact on integrators**

No action required. A client that sends the `Content-Type: application/json` header on every request no longer has to add the body `{}`.

### FIX-1020-5: a Compose deploy names the container that failed behind HTTP 200

**Before**

`POST /v1/infra/servers/{id}/deploy` for a Docker Compose rollout could finish as a success when the published port answered HTTP 200, even though a container of the same project was restarting and the API was not staying up. The `healthcheck` step did not name that container or attach its startup log. The HTTP status of the deploy response itself stayed 200.

**After**

When a container of the Compose project in the `extractTo` directory is restarting — even one that has been restarting since before the deploy — or a container started during this deploy has restarted since it started, has exited with a non-zero code, is in the dead state, or is marked unhealthy by Docker, the `healthcheck` step fails and `error.message` includes the service name, its state and the container's startup log. A successful deploy whose project containers stay up still returns `success: true`. For `POST /v1/infra/servers/{id}/deploy` the HTTP 200 response is unchanged: the failure still arrives in the body as `success: false`.

### FIX-1020-6: key deletion no longer gets stuck after a bot change

**Before**

If the key's bot had been changed through `PATCH /v1/bots/{botId}` shortly before deletion, for example to rename it, `DELETE /v1/keys/{id}` kept answering `409 KEY_BOT_CLEANUP_PENDING`. Retrying did not help, and both the key and the bot stayed in place.

**After**

A bot change made through `PATCH /v1/bots/{botId}` and already accepted by Bitrix24 no longer blocks deletion: the platform unregisters the bot in Bitrix24 and deletes the key, and the response is `204`. A change the platform has not finished yet — its Bitrix24 response has not arrived, or work on the change is still going on — keeps answering `409 KEY_BOT_CLEANUP_PENDING` until it completes.

The exception is a change that gives the bot a new token: a request carrying the `fields.botToken` field, or a switch to `webhook` mode in which the platform issues the new bot token itself. Until such a change is finished, the response stays `409 KEY_BOT_CLEANUP_PENDING`, and repeating the request does not change that.

**Impact on integrators**

No action required. Keys whose deletion got stuck after an ordinary bot change are deleted by repeating the request. If unregistering the bot in Bitrix24 failed, or the last bot change replaced the bot token, the response stays `409 KEY_BOT_CLEANUP_PENDING`.

### NEW-1020-7: Company connections: readiness checks at every phase

At `/v1/connect/authorize` and `/v1/connect/token`, `CREATE` and `RECONNECT` require enabled access and verified readiness. `CONNECT_COMPANY_DISABLED` and `CONNECT_COMPANY_NOT_READY` return no secret. `CONNECT_COMPANY_ATTEMPT_LIMITED` includes `Retry-After`.

`CREATE` returns the secret once. `RECONNECT` preserves it and returns `credential_unchanged: true` without `api_key`. `ROTATE_SECRET` works for an existing connection while new issuance is disabled, checks `credential_version` and returns the new secret once. Replaying a code returns `invalid_grant`. `bitrix_ready` reflects actual request availability, including pending deletion of old webhooks. AI and other `vibe:*` scopes are not supported for Company connections yet.

### NEW-1020-8: AI for company connections with separate administrator consent

COMPANY connections support `vibe:ai` when AI access is enabled for the Bitrix24 account and administrator and the app allows the scope. On CREATE and when RECONNECT first adds AI, the administrator explicitly selects additional consent. Without it, connection setup does not begin: `CONNECTION_SCOPE_CONSENT_REQUIRED`.

After each CREATE or RECONNECT with AI consent, the service attempts to create a separate AI permission if none exists. If saving it fails, the successful `/v1/connect/token` response and key delivery are preserved; an administrator can retry by reconnecting the company with AI consent. Check availability through `capabilities.ai` in connection status. An administrator can restore revoked permission in the Bitrix24 account AI settings. RECONNECT does not restore it; revocation does not disable Bitrix24 access. `vibe:storage` remains unavailable for COMPANY.

### FIX-1020-9: account cleanup fixed for deletion of apps without placement permission

**Before**

After [DELETE /v1/apps/:id](/docs/apps/delete), a cloud application without the `placement` permission could remain in Bitrix24, and cleanup retries stopped after several failed attempts.

**After**

Cleanup of such an application can use its verified creator's developer key. The application is unregistered only after a complete check and confirmed placement removal. If verification cannot be completed, retries continue at intervals of up to one day. The response remains HTTP `204 No Content`: it confirms deletion in Vibecode and revocation of the paired API key, while Bitrix24 cleanup may continue in the background.

**Impact on integrators**

No changes to requests or HTTP status handling are required.

### FIX-1020-10: updating a bot after an acknowledged write

**Before**

If Bitrix24 acknowledged a bot update but the new name did not appear on read, later `PATCH /v1/bots/{botId}` requests could keep returning `409 BOT_EFFECT_IN_PROGRESS`.

**After**

The platform reapplies the acknowledged update and verifies the result. Once the name matches, the next `PATCH /v1/bots/{botId}` succeeds again; the successful response shape is unchanged.

### FIX-1020-11: a storage key with an empty or "." segment is rejected at the entry

**Before**

`POST /v1/storage/objects/upload` and `POST /v1/storage/objects/multipart/create` accepted a key such as `docs//a.txt`, `docs/./a.txt` or `docs/a/.`: the key check caught only `..`, so an extra separator and a `.` segment went into the object path.

**After**

Such a key is rejected the same way as a key with `..`: response `400` with code `STORAGE_INVALID_KEY`, no object is created. Keys without empty segments and without `.` and `..` segments work as before.

**Impact on integrators**

If a key is built by joining parts, drop the extra separator and `.` segments before sending it.

### FIX-1020-12: Batch product creation returns product identifiers

**Before**

Successful product creation through `POST /v1/catalog-products/batch` could omit `id` from `data.results`. Accessing the created product required a separate search.

**After**

With `action: "create"`, results return the numeric `id` received when the corresponding product was created. `index` links each result to its input array item. The `data.summary` format and failure handling are preserved.

### FIX-1020-13: reading and copying a sleeping application's database

**Before**

A closed WAL database without `-wal` and `-shm` files returned `APP_DB_WAL_CLOSED` even for a sleeping application. This blocked database browsing, backups, and restoration, which requires a protective copy of the current data.

**After**

When the application is confirmed stopped, its closed database can be read and copied without waking the application. The fix affects `GET /v1/infra/servers/{id}/db`, `GET /v1/infra/servers/{id}/db/schema`, `GET /v1/infra/servers/{id}/db/tables/{table}/rows`, `POST /v1/infra/servers/{id}/db/query`, `POST /v1/infra/servers/{id}/db/backups` and `POST /v1/infra/servers/{id}/db/restore`, including the protective copy before restoration.

A running application with a closed WAL database still receives `APP_DB_WAL_CLOSED`: its database connection must remain open. If the application wakes during a read or copy, the result is discarded with `APP_DB_BUSY`; the operation can be retried.

### BC-1020-14: A new version of an existing app requires the same access as a new app

> Old format supported until: not provided

**Before**

[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) and [POST /v1/infra/servers/:id/upload](/docs/infra/deploy/upload) checked only the key and the rights to the server. A Bitrix24 account whose commercial plan had ended was refused when creating a new app but kept delivering new versions of an app it already had.

**After**

Both calls answer with the same refusal as creating a new app: `402 INT_TARIFF_REQUIRED`, `402 INT_VIBE_PLUS_REQUIRED` where access is narrowed to the Vibe+ plan line, or `403 PORTAL_TARIFF_UNREADABLE` when the plan could not be read. The body is the same as for creating an app: `userMessage`, `alternatives` and `hint`. When a purchase clears the refusal, `error.details.upgradeUrl` carries the upgrade link. When the platform could not read the plan, there is no purchase link: `error.details.remedy` is `refresh_tariff`, and `alternatives` holds the recheck via `GET /v1/me?refresh=tariff`. The check comes first, before the server is woken and before the archive is accepted, so the refusal leaves nothing behind and carries no operation id. The app that is already running keeps responding; commands on the server, logs and source downloads stay available.

**What integrators should do**

Handle these codes on delivery the same way as on app creation and pick the action by `error.details.remedy`. When it is `refresh_tariff`, call `GET /v1/me?refresh=tariff` and repeat the delivery: once the platform reads the plan, the retry can pass. Otherwise show the person `userMessage` and the path from `alternatives`; a retry without changing the plan returns the same answer. The state is visible in advance in `capabilities.servers.deploy` in `GET /v1/me`. The slot is built from the stored plan, so right after a purchase it can answer `false` a little longer than the delivery itself.

### FIX-1020-15: Explicit bitrix-search selection in the research schema

**Before**

The OpenAPI schema for [POST /v1/research](/docs/search/research) omitted `bitrix-search` from the allowed `provider` values, although this choice could support research.

**After**

`bitrix-search` is included. Its research availability depends on the provider's current capabilities: check `capabilities.modes.research` in [GET /v1/search/providers](/docs/search/providers). Access conditions and credential requirements still apply.

**Impact on integrators**

Clients validating request bodies against OpenAPI can explicitly select `bitrix-search`. Previous values and omission of `provider` remain supported.

### BC-1020-16: Quick replies accept only sections of their own channel

> Old format supported until: not provided

**Before**

[POST /v1/openline-configs/:lineId/quick-replies](/docs/openlines/quick-replies/create) and [PATCH /v1/openline-configs/:lineId/quick-replies/:id](/docs/openlines/quick-replies/update) accepted a `sectionId` of another channel's section or of a non-existent section and returned a successful response. Such a quick reply did not appear in any channel's list, and it could not be updated or deleted through the API.

**After**

A `sectionId` other than `0` is checked against `data.sections` of this channel's quick reply list. A section outside the list is rejected with `400 INVALID_PARAMS`, and nothing is created or changed. `PATCH` still accepts the reply's current section. If the channel's quick replies are unavailable to the key user, `POST` with `sectionId` returns `403 BITRIX_ACCESS_DENIED`. Requests without `sectionId` or with `0` work as before.

**What integrators should do**

Take `sectionId` from `data.sections` in the [GET /v1/openline-configs/:lineId/quick-replies](/docs/openlines/quick-replies/list) response of the same channel, or pass `0` to create a reply without a section.

### NEW-1020-17: Connector list pages, search and filters

[Connector list](/docs/connectors-host) `GET /v1/connectors` accepts `cursor`, `limit` from 1 to 100, `q`, `category`, `scope`, `type`, `view=mine`, `mode`, and `sort`. A request with list parameters returns `nextCursor`, `total`, group `counts`, and `truncated`: another page is available while it is `true`. `mode` is accepted without filtering until mode data is available; `type=own` returns an empty list. The `popular` sort currently uses title order. Without parameters, item fields and slug order are preserved; only `truncated` is added.

### BC-1020-18: activity update refuses the deadline instead of answering without a change

> Old format supported until: not provided

**Before**

[PATCH /v1/activities/:id](/docs/entities/activities/update) with a `deadline` field in the body returned `200` with `success: true`, but the activity deadline did not change: the response and a repeated read kept the previous `deadline`. A batch update `POST /v1/activities/batch` with `action: "update"` behaved the same way.

**After**

An update request with `deadline` returns `400 READONLY_FIELD` and applies none of the body fields. The `error.hint` in the response points to [POST /v1/activities/:id/deadline](/docs/entities/activities/deadline). A batch update refuses such an item with `400 BATCH_ITEM_VALIDATION`. In the `GET /v1/activities/fields` response the `deadline` field is marked `readonlyOnUpdate: true`. Creating an activity with `deadline` is unchanged.

**What integrators should do**

Remove `deadline` from the update body and change the deadline with [POST /v1/activities/:id/deadline](/docs/entities/activities/deadline), or shift it by a given amount of time with [POST /v1/activities/:id/postpone](/docs/entities/activities/postpone). Send the other fields in `PATCH` as before.

### NEW-1020-19: Connectors report their type and session modes

`GET /v1/connectors` returns `type: "connector"` and `modes` in every item: the supplier-supported `cowork` and `code` session modes. Both modes are available by default, including for previously published connectors. Existing fields and list order are preserved; `mode` still describes read or write access.

### NEW-1020-20: node24 runtime on a supported Node.js release

The [`GET /v1/infra/runtimes`](/docs/infra/deploy/runtimes) catalog adds the `node24`, `node24-pg`, `node24-mysql`, `node24-redis`, `node24-mysql-redis`, `node24-pg-redis` and `node24-rag` runtimes. They come first in the list, and `node24` is the runtime offered to new Node.js apps: Node.js 20 reached end of life on 2026-04-30. In Galaxy the runtime is built from the official `node:24-slim` image. On a dedicated virtual machine every deploy installs the latest 24.x release from the official Node.js archive and verifies the Node.js release team's signature. The `node20*` runtimes stay in the catalog and work as before. Every catalog entry now carries `deprecated` and `replacement`: for `node20*` they are `true` and the ID of the successor with the same package set, for example `node24-pg` for `node20-pg`, and `false` and `null` for every other runtime.

### NEW-1020-21: replace an application's server through the API

Added `GET /v1/applications/{id}/available-servers` and `POST /v1/applications/{id}/replace-server`. The first returns the card owner's servers the application can move to, and a `canCreateNew` flag that says whether a new server can be created. When it cannot, `createNewBlocked` gives the reason. The client can use the response to decide up front whether to show a replace button.

The second moves the application to an existing server (`{ "serverId": "…" }`) or creates a new one (`{ "provider": "…", "plan": "…", "region": "…" }`, the same values as `POST /v1/infra/servers`). The old server is not deleted and stays with its owner. The key of the call is not reassigned: `callerKeyManagesServer` says whether that key manages the server. If a failure happens after the application is moved, the response stays `200` and the problems are listed in `warnings`: `KEY_ASSIGN_FAILED`, `APP_URL_MOVE_FAILED`, `APP_URL_MANUAL`, `CATALOG_STALE`, `SERVER_KEY_STALE`.

Only the card owner can replace the server.

The server sleep mode is switched with the existing `PATCH /v1/infra/servers/{id}/run-mode`.

### NEW-1020-22: Connector selection for Cowork

Optional ASCII headers `X-Cowork-Connectors-Enabled` and `X-Cowork-Mode` on every request to [POST /v1/connectors/mcp](/docs/connectors-host) narrow the connector set and select `cowork` or `code`. Filtering applies before the direct-tool threshold, during discovery and direct/meta calls. Invalid headers return `400 INVALID_BODY`; omitting both headers preserves the response. Connection setup and settings remain in the web cabinet.

The card [GET /v1/connectors/{slug}](/docs/connectors-host) shows published tools with readOnly, separate service company and publisher, modes and safe state. Account-blocked connectors are hidden even from administrators.

### BC-1020-23: PHP 8.3 on a dedicated server is installed from the Ubuntu repository

> Old format supported until: not provided

**Before**

[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) with `runtime` `php83` or `php83-mysql` added the third-party `ppa:ondrej/php` repository on a dedicated server and installed PHP 8.3 from it. If that repository was unreachable, the runtime install could fail.

**After**

On a new server PHP 8.3 is installed from the standard Ubuntu 24.04 repository: version 8.3.6 with Canonical security fixes. The `php8.3` command, the `php8.3-fpm` service and Composer stay the same. Servers that already have the PPA are not affected.

**What integrators should do**

If the app's `composer.json` requires `"php": ">=8.3.7"` or higher, relax the constraint to `^8.3`: otherwise `composer install` fails on a new server. API requests need no changes. Servers that already have the PPA are not affected.

### NEW-1020-29: Official connector marker in catalog pages

When requesting the connector list with list parameters, each item includes verified, the official catalog connector marker. The card returns the same marker.

### NEW-1020-30: Service company and connector modes in the workshop

When creating or editing a connector, authors can set its service company separately from the publisher and select Cowork and Code modes. Service-company fields can be cleared; saving requires at least one mode.

### NEW-1020-31: Service companies in the connector catalog

Service companies are stored separately from publishers and configured through the workshop API. Cards, cabinet lists and host lists return the company, and server search includes its name. Existing connectors without configured company metadata return null.

### FIX-1020-32: Connector group counts in Cowork

The available count matches the server-selected group. Informational rows for previously connected services disabled by an administrator stay in the Cowork tab and are excluded from that group and its count.

### FIX-1020-33: Retry-After of a bot reconcile refusal is the time until the next scheduled check

**Before**

While a bot change was waiting to be reconciled with Bitrix24, a repeated `POST /v1/bots` with the same `code` got 409 with a `Retry-After: 5` header, and other bot changes got 409 `BOT_EFFECT_IN_PROGRESS` with `Retry-After: 30`. Every repeat contacted Bitrix24 again, even when the next scheduled check was minutes away. A repeated [DELETE /v1/bots/:botId](/docs/bots/management/delete) while an earlier deletion of the same bot was still being reconciled answered as a Bitrix24 refusal: `502 BOT_DELETE_PARTIAL` without `Retry-After` (with `?force=true`, `409 BOT_DELETE_PENDING` with `Retry-After: 5`), and made an extra check call to Bitrix24.

**After**

The `Retry-After` header of such a refusal carries the time until the next scheduled check of the record, at most 300 seconds. A repeat before that time gets the same refusal without contacting Bitrix24. The error codes and the 409 status are unchanged. In this case `DELETE /v1/bots/:botId`, with or without `?force=true`, returns `409 BOT_EFFECT_IN_PROGRESS` with `Retry-After`, does not contact Bitrix24 and keeps the bot record. A refusal from Bitrix24 itself still returns `502 BOT_DELETE_PARTIAL` or `409 BOT_DELETE_PENDING`.
