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

API changes: July 3, 2026

← Changelog · July 2026

FIX-0703-1: binding a placement via a developer key no longer returns 500 after an unpublish/republish cycle

Before

POST /v1/placements/bind for a developer-key-managed app (type local.*) could consistently return 500 (BITRIX_UNAVAILABLE, INTERNAL_SERVER_ERROR) when binding a placement (e.g. CRM_DEAL_DETAIL_TAB or CRM_CONTACT_DETAIL_TAB) after the app was unpublished and published again. The previous placement registration remained on the Bitrix24 side, and registering a new one on top of it failed with an internal error. Retries returned the same error.

After

Before registering the placement, the request now clears its previous registration on the Bitrix24 side, so the bind succeeds even after an unpublish/republish cycle. No change to your call.

FIX-0703-2: /v1/sites — filtering by knowledge-base (KNOWLEDGE) and group (GROUP) type is no longer ignored

Before

POST /v1/sites/search (as well as GET /v1/sites and POST /v1/sites/aggregate) with filter[type]=KNOWLEDGE or filter[type]=GROUP silently returned ordinary landing sites (PAGE / STORE / VIBE) instead of knowledge bases or group pages. The cause is on the Bitrix24 side: the landing.site.getList method binds the TYPE filter to an internal area (scope), and without the scope parameter the KNOWLEDGE / GROUP types are not part of the default area — so the type filter was silently dropped. The only workaround was to add scope manually (see List sites).

After

When the filter names one such type and scope is not passed explicitly, Vibecode supplies the matching area itself (type=KNOWLEDGE → scope=KNOWLEDGE, type=GROUP → scope=GROUP) — and the request returns exactly the knowledge bases / group pages. An explicitly passed scope always wins and is never overridden. If the type is given as a list or operator (for example {"type":{"$in":["KNOWLEDGE","PAGE"]}}), where a single area cannot be chosen, meta.warnings carries a hint with code TYPE_REQUIRES_SCOPE.

Impact on integrators

No action required. Requests with filter[type]=PAGE / STORE / VIBE and requests without a type filter work as before. MAINPAGE is an area, not a site type (its sites have type VIBE), so MAINPAGE is not derived from the type filter. Behavior for /v1/pages is unchanged.

FIX-0703-3: page and site aggregation returns count again

Before

POST /v1/pages/aggregate and POST /v1/sites/aggregate returned count: 0 and meta.totalRecords: 0 even when pages and sites existed — in every form: without a filter, with a filter, with a count expression, and as the top-level count alongside groupBy. Per-group counts under groupBy were already correct.

After

count and meta.totalRecords reflect the actual number of records; the top-level count under groupBy equals the sum of the group counts.

Integrator impact

No action required — the response is now correct.

NEW-0703-4: Quality and timestamp parameters in audio transcription

Audio transcription POST /v1/audio/transcriptions accepts five new optional fields. Recognition quality: prompt — a context hint (conversation topic, style, correct spelling of terms, up to 2000 characters), hotwords — a comma-separated list of special words (rare terms, brands, names, up to 500 characters), vad_filter — a silence filter applied before recognition (fewer hallucinations on recordings with pauses). Output control: temperature — decoder temperature from 0 to 1, timestamp_granularities[] — timestamp granularity word/segment (only with response_format=verbose_json; with word, each segment gains a words array with per-word timing and probability). The fields are passed in multipart/form-data alongside file and are compatible with the OpenAI contract. Invalid values are rejected with the invalid_prompt, invalid_hotwords, invalid_temperature, invalid_vad_filter, and invalid_timestamp_granularities codes.

FIX-0703-5: Apps created via the API now open correctly as placements

Before

Some apps created via POST /v1/apps failed to open when their placement was invoked in Bitrix24 — instead of the app interface the user saw an app-resolution error.

After

Created apps now resolve correctly and open as placement widgets in Bitrix24. The create response is unchanged — the app is immediately ready for publishing and binding placements.

Integrator impact

No action required. Recreate a previously non-opening app (delete and create it again) — the new app opens correctly.

NEW-0703-6: key deletion is blocked while an agent or bot is linked

DELETE /v1/keys/:id now returns 409 with code KEY_HAS_LINKED_AGENT when the key is the control key of a live AI agent or managed bot.

Before

Deleting such a key orphaned the agent and cascade-deleted the bot together with its token — the bot's Bitrix24 identity was lost irrecoverably, with no warning.

After

Response body: { success: false, error: { code: "KEY_HAS_LINKED_AGENT", message, details: { linkedAgentCount, linkedBotCount, agents: [{ id, name, status }] } } }. Rebind the resources to another key or delete the agent/bot first; to restore access for an orphaned agent, use the "Restore access" action in the dashboard. The check runs before Bitrix24 synchronization — on a 409 the Bitrix24-side credentials are left untouched. Sibling of the existing KEY_HAS_ACTIVE_SERVERS.

NEW-0703-7: Task change history and kanban stages

Two read-only endpoints added (scope task). GET /v1/tasks/:taskId/history returns a task's full change history in a single call: kanban stage moves, sprint and backlog moves, statuses and other events. Filter by event type via ?field=STAGE (comma-separate several, e.g. ?field=STAGE,MOVE_TO_SPRINT); sort via ?order=asc or ?order=desc (created-date ascending by default). Each entry carries id, createdDate, field, a value object with the previous and new value, and a user with the author id. GET /v1/tasks/stages/:entityId returns the current kanban columns of a workgroup (N) or personal plan (0).

FIX-0703-8: bizproc-activities: clear error instead of "Wrong handler URL" when handler is missing

Before

POST /v1/bizproc-activities without a handler field (or with the handler URL mistakenly sent under handlerUrl) returned the opaque core error 422 BITRIX_ERROR: Wrong handler URL.

After

code, name, and handler are validated before the Bitrix24 call: a missing handler now returns 400 MISSING_REQUIRED_FIELDS with the message Body field "handler" is required to create bizprocActivity, pointing at the correct field name. Successful calls that include a valid handler are unaffected.

FIX-0703-9: POST /v1/batch — update and delete responses are now normalized like create and get

Before

In the global batch call POST /v1/batch an update sub-call returned its response in a raw wrapper (a nested object instead of the flat record), and a delete sub-call returned an empty array with no success signal. This diverged from create and get in the same endpoint and from single PATCH /v1/{entity}/:id, which return a flat normalized record.

After

An update sub-call returns the flat normalized record (camelCase fields) — like create, get and single PATCH. A delete sub-call returns a success signal of the form { id, deleted: true }.

FIX-0703-10: POST /v1/{entity}/batch — create, update and delete work again for CRM entities

Before

A per-entity batch call to POST /v1/{entity}/batch with a create, update or delete action for deals, contacts, companies, leads, quotes and invoices returned a per-item error "Could not find value for parameter {entityTypeId}", and the record was not created, updated or deleted. Single calls (POST /v1/{entity}) and the global POST /v1/batch worked on the same entities.

After

Per-entity batch create, update and delete for these entities now succeed — the same way single calls and the global batch endpoint do.

FIX-0703-11: Omitting the model field in chat again falls back to the default model

Before

POST /v1/chat/completions without a model field returned 400 no_default_model on accounts where no default model was explicitly set — even when a free model was available in the account. Meanwhile GET /v1/me could report a defaultModel that could not be called.

After

When the model field is omitted, the request automatically uses the account's first callable model — as the docs describe. GET /v1/me now always reports a callable defaultModel, the same one chat will use.

Before

GET /v1/deals/:id?include=contact,company returned _included.company = null and _included.contacts as relation metadata only (sort/isPrimary/roleId) without the entity's own fields, even though the deal referenced an existing company and contacts.

After

_included.company carries the full company object, and _included.contacts carries the full contact objects (id, name, …) alongside the relation metadata. The fix applies to include across CRM entities (deals, leads, quotes, and others).

FIX-0703-13: deal search rejects an unknown filter field instead of silently returning every row

Before

GET /v1/deals and POST /v1/deals/search with an unknown filter field (a misspelled name, a field not in the schema) silently forwarded it to Bitrix24, which ignores unknown filter keys and returns the whole deal set with a 200. A client that sent a filter with a typo in the field name got neither an empty result nor a 400, but the full table — as if the filter had applied.

After

An unknown filter field is now rejected before the Bitrix24 call with a 400 and code UNKNOWN_FILTER_FIELD, listing the available fields in the message — the same behavior contacts, companies, leads, quotes, invoices, and items already have. Declared fields (including aliases such as amount), custom fields (UF_CRM_* and ufCrm*), and id work as before.

FIX-0703-14: Catalog: listing and search return a clean 400 when iblockId is missing

Before

Listing and search GET /v1/catalog-products, POST /v1/catalog-products/search, GET /v1/catalog-sections and POST /v1/catalog-sections/search without iblockId in the filter reached Bitrix24 and returned a murky 422 BITRIX_ERROR ("Field iblockId is not specified in the filter").

After

Catalog listing and search require iblockId in the filter — when it is missing they return 400 MISSING_REQUIRED_FILTER with an example and never reach Bitrix24.

Integrator impact

No change needed — correct requests (with filter[iblockId]) work as before. Only the error code and its clarity changed for requests that already failed.

FIX-0703-15: Contacts — real date fields createdTime/updatedTime instead of phantom createdAt/updatedAt

Before

GET /v1/contacts/fields advertised createdAt and updatedAt, but they never appeared in contact responses — Bitrix24 returns the dates under createdTime/updatedTime, and those are what the contact body carried. Meanwhile filter and select by createdTime (the name a client actually sees in the response) were rejected as an unknown field, while the phantom createdAt "worked" even though the field itself was never readable.

After

The schema declares the real keys createdTime and updatedTime (datetime, read-only): they appear in /fields, filter and select on them work, and the value is normalized to ISO-8601 in UTC. The phantom createdAt/updatedAt are no longer declared — filter or select on them returns 400 UNKNOWN_FILTER_FIELD.

Integrator impact

Reads are unchanged — the createdTime/updatedTime keys were already in the response body, now also normalized. If you filtered or projected contacts by createdAt/updatedAt, rename them to createdTime/updatedTime.

FIX-0703-16: Open Channels config list now honors the limit parameter

Before

GET /v1/openline-configs and its search counterpart ignored limit: the underlying Bitrix24 method returns the whole set of configurations and the wrapper forwarded every row. The hasMore flag was wrong too — false even when records remained beyond the requested limit.

After

The response is clamped to limit on the wrapper side. hasMore: true when Bitrix24 returned more records than the requested limit (a next page exists), otherwise false. total is the record count in the current window.

Integrator impact

A request with limit now returns no more than limit records. Clients that relied on the whole set coming back regardless of limit will see a truncated list — use offset for the next page.