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

API changes: June 30, 2026

← Changelog · June 2026

NEW-0630-1: POST /v1/cowork/deploy-key — get a project deploy key from Cowork/Code

The Cowork/Code key (vibe:cowork) is data-plane only and is blocked from the infrastructure control-plane with 403 INFRA_FORBIDDEN_FOR_COWORK_KEY. The new POST /v1/cowork/deploy-key endpoint lets an agent self-serve a separate project deploy key: call it with the same Cowork key, take the top-level key field from the response (a bare object, not wrapped in data), and use it as the X-Api-Key header for deploy/provision/exec under /v1/infra/*.

The returned key carries the vibe:infra + vibe:storage scopes (no vibe:cowork), expires in 7 days, and is bound to the Cowork key's owner and account. Each call returns a fresh key and revokes the previous project key (exactly one is active). Requires the vibe:cowork scope and an active Cowork/Code subscription; rejection codes are 403 INSUFFICIENT_SCOPE / 403 COWORK_NOT_ACTIVATED / 503 DEPLOY_KEY_DISABLED / 503 INFRA_DISABLED.

NEW-0630-2: Self-hosted placement now receives a one-time authorization code on appUrl

For an app with its own appUrl (outside Black Hole) opened as a placement, the platform now appends a one-time authorization code (?code=...) to the appUrl redirect instead of an internal gateway token. The app exchanges this code for a vibe_session via the existing POST /v1/oauth/token — redirect_uri must exactly match the configured appUrl. Previously such apps received a non-redeemable token and could not authorize the user.

NEW-0630-3: New endpoint POST /v1/oauth/placement-session for self-hosted apps

A self-hosted app (on its own server, not on Black Hole) opened as a placement (iframe) in Bitrix24 can now exchange the Bitrix24 user token it received in the placement callback on its own handler for a vibe_session. The request POST /v1/oauth/placement-session with body { app_key, access_token, member_id, domain } (optionally refresh_token, expires_in) is server-to-server — the session token never reaches the browser. The authorization section of the docs covers both placement topologies.

FIX-0630-4: PATCH on an OAuth application key's scopes: honest rejection instead of false access

Before

PATCH /v1/keys/:id adding a Bitrix24 scope to an OAuth application key (vibe_app_*), and PATCH /v1/apps/:id widening an app's scopes, returned 200 and persisted the new scope set. But an OAuth application's scopes are fixed at issue time and such an edit never reaches the Bitrix24 side, so GET /v1/me then reported a scope Bitrix24 had not granted and the actual call was rejected.

After

Adding a Bitrix24 scope to an OAuth application key or to an app is now rejected with 403 OAUTH_SCOPE_CHANGE_REQUIRES_REISSUE. Removing scopes and changing vibe:* scopes still work. To gain a new scope, issue a new authorization key with the scopes you need.

FIX-0630-5: a key with the `tasks` scope now actually unlocks Tasks methods

Before

A key issued with the tasks scope (plural — the spelling the UI picker offers) minted, on a dev-key account, a webhook that Bitrix24 accepted but never bound to the Tasks REST methods. GET /v1/me reported tasks, yet Tasks method calls were rejected on the Bitrix24 side. The task scope (singular) worked.

After

On key issue and edit the scope set is canonicalised to the spelling Bitrix24 actually binds methods to (tasks → task), so the key unlocks Tasks methods regardless of the chosen spelling. Already-issued keys are not changed retroactively — re-issue the key.

FIX-0630-6: a malformed FILES field on a timeline comment is now rejected with 400

Before

POST /v1/timelines and PATCH /v1/timelines/:id accepted the FILES field in any shape and answered 200/201. When the shape was anything other than an array of [[fileName, base64Content]] pairs — a flat array of strings or a single pair without the outer array — the comment was created but the file was attached as garbage (random name, unreadable content) or silently dropped, with no error.

After

A FILES value that is not an array of [[fileName, base64Content]] pairs is rejected before the Bitrix24 call with 400 INVALID_FILES_SHAPE and a hint about the correct shape. An empty FILES ([]) and an omitted field are still accepted. The check applies to single POST/PATCH and to batch (POST /v1/batch, POST /v1/timelines/batch).

Impact on integrators

Callers passing FILES in the documented [[fileName, base64Content]] shape are unaffected. Callers relying on other shapes now get an explicit 400 instead of a silently broken attachment, and can fix the request.

FIX-0630-7: empty bot and user fields now return null/[] instead of false/{}

Before

In bot-card responses (GET /v1/bots/:botId, POST /v1/bots, PATCH /v1/bots/:botId) the unset fields inside users[] came back as the wrong primitive: the datetimes lastActivityDate, mobileLastDate, desktopLastDate were returned as boolean false, and an empty phones list was also false. The same lastActivityDate field in GET /v1/users came back as an empty object {}. As a result new Date(lastActivityDate) silently produced the epoch and phones.map(...) threw a type error.

After

An unset datetime is now encoded uniformly as null on every path, and an empty phone list as []. A populated datetime is still an ISO string and a populated list is still an array.

Impact on integrators

No action required — the types are now correct. Code that relied on comparing empty values to false will stop matching: check the datetime against null and treat the phone list as an array.

Affected endpoints: GET /v1/bots/:botId, POST /v1/bots, PATCH /v1/bots/:botId, GET /v1/users

A new endpoint POST /v1/apps/:id/relink-oauth updates bitrixClientId and bitrixClientSecret on an existing application without deleting it. This is needed when the local OAuth application is recreated in the Bitrix24 account and its client_id changes: previously the only path was to delete the app (which broke the linked bot, Open Channels config and bindings) and create it anew.

Request body: { bitrixClientId, bitrixClientSecret } (both required). The paired key, bot and bindings are preserved. If that client_id is already linked to another application — 409 OAUTH_CLIENT_ID_IN_USE. It cannot be called with the OAuth application's own key — 403 OAUTH_APP_KEY_CANNOT_RELINK (use a personal key or the dashboard). After relinking, reinstall the app in the account — this restores the event subscription.

NEW-0630-9: Web search: full page text, images, news mode, and research domain filters

Before

POST /v1/search accepted include_raw_content as a boolean flag, but the full text of the found pages did not reach the response. There were no parameters for news mode or for requesting images. POST /v1/research accepted include_domains and exclude_domains but silently dropped them.

After

POST /v1/search gained two new optional parameters: topic (general or news, default general) and include_images (boolean, default false). The boolean include_raw_content now actually returns the full text: each result gained a rawContent field (the full page text, size-capped). The response added top-level images (an array of objects with a url field) and ignored_filters (a string array — the passed filters the provider could not apply). These fields arrive in both the synchronous response body and the done streaming frame. The X-Search-Filters-Ignored header is kept and may now list topic and include_images. POST /v1/research now applies include_domains and exclude_domains (up to 20 each) for capable providers and reports overflow via ignored_filters in the done frame. Which capabilities a selected engine offers is returned by GET /v1/search/providers. Clients with strict schema validation via additionalProperties should account for the new response fields.

NEW-0630-10: Read AI client-call transcripts via the API

The new GET /v1/activities/:activityId/transcript endpoint returns the ready-made AI transcript of a client call by the ID of its CRM Call activity. The method only reads an existing transcript — it does not trigger generation. It requires the crm scope. When there is no transcript for the call yet, the data.transcription field is null — a normal response, not an error.