# API changes: October 14, 2026

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

### FIX-1014-1: Epic and sprint lists honour a limit of up to 50

**Before**

[GET /v1/scrum/epics](/docs/scrum/epics/list) and [GET /v1/scrum/sprints](/docs/scrum/sprints/list) with a `limit` from 1 to 50 returned the whole first Bitrix24 page, up to 50 records. For example, a request with `limit=2` could return 6 epics.

**After**

Both methods return at most `limit` records for any value from 1 to 1000, as the documentation promises. The order of records has not changed.

**Impact on integrators**

No action is needed. If your code relied on getting more records with a small `limit`, pass the `limit` you need explicitly — it defaults to 200.

### FIX-1014-2: repeated error protection holds the block until a successful call

**Before**

The `ERROR_LOOP_DETECTED` block expired after an hour even during active retries. The hint suggested continuing to retry, and the next-attempt delay arrived only in the `Retry-After` header.

**After**

Active retries keep the block until the first successful call. Recovery probes require both the configured request count and a pause: 1, 5, 15, then 60 minutes after failed probes. `Retry-After` and `error.retryAfter` carry the remaining pause, or 60 seconds before another check if time has elapsed but the call is still blocked. The hint asks callers to fix the request; the key owner receives a notification at most once per 24 hours for the same method. Local refusals without dispatch to Bitrix24 do not increase the probe pause. The scope matches in standalone and batch responses for queue, timeout, and key authorization refusals. Bitrix24 `RATE_LIMITED` refusals now include `scope: "portal"`, including legacy chat methods and notification reads without `format=v2`; this adds a field to the previous error contract. Extended inactivity also clears the block.

### FIX-1014-3: issuing a key into an empty slot waits for another operation on the application

**Before**

[POST /v1/cowork/applications/{id}/key](/docs/cowork/applications-key) on an application without a personal key issued a key even while another operation on the application's keys or owner was running, for example a transfer of the application to another person. The issued key could disagree with the outcome of that operation.

**After**

While another operation on the application's keys or owner is running, issuing into an empty slot answers `409 APPLICATION_KEY_REPLACE_IN_PROGRESS` and mints nothing — the refusal this method already documents. Replacing an already issued key under such an operation works as before, and outside such operations the successful `201` response is unchanged.

**Impact on integrators**

No change is required: the `APPLICATION_KEY_REPLACE_IN_PROGRESS` code and its guidance are the same, and no new codes were added. The refusal now also arrives when the parallel operation was started outside this method. Treat it as a normal outcome: wait, read the application card and check whether a key is still needed.

### FIX-1014-4: Group calendar event owner and organizer

**Before**

For a group calendar event, `include=owner` could return an unrelated employee's card because `ownerId` contains the workgroup ID. For an event without a meeting, the same error affected `include=host`: Bitrix24 supplies the workgroup ID in `meetingHost`.

**After**

For every event with `type=group`, `_included.owner` returns `null`, including for meetings. The `_included.host` relation returns `null` unless `isMeeting` confirms a meeting. The original `ownerId` and `meetingHost` values are preserved. The event creator is identified by `createdBy`.

**Impact on integrators**

Handle `owner: null` when reading a group event, and also `host: null` without a confirmed meeting. The `host` relation continues to work as before for group meetings. Personal and company events retain both relations, including with `select`.

**Affected endpoints:** [GET /v1/calendar-events/{id}](/docs/entities/calendar-events/get), [GET /v1/calendar-events](/docs/entities/calendar-events/list), [POST /v1/calendar-events/search](/docs/entities/calendar-events/search).

### FIX-1014-5: Catalog document and item lists honor withTotal=false

**Before**

Calling [GET /v1/catalog-documents](/docs/entities/catalog-documents/list) or [GET /v1/catalog-document-elements](/docs/entities/catalog-document-elements/list) with `withTotal=false` still returned `meta.total`.

**After**

With an explicit `withTotal=false`, the `meta.total` key is absent. Omitting the parameter or setting `withTotal=true` preserves the previous count behavior.

**Impact on integrators**

Integrations that request `withTotal=false` should no longer expect `meta.total` in the response.

### FIX-1014-6: Connect sign-in accepts a localhost redirect address for both client types

**Before**

[GET /v1/connect/authorize](/docs/partner-connect) rejected a localhost redirect address for a confidential client even though the dashboard saved it: `http://localhost:3030/callback` returned `400 invalid_request`. A public client was rejected the same way on an `https://localhost` address. Every redirect address refusal carried the same description, `Redirect URI not registered`, even when the address was malformed or the scheme did not fit.

**After**

An address on `127.0.0.1`, `localhost` or `[::1]` over `http` or `https` is accepted for both client types. For a public client the port of such an address is not matched, for a confidential client the whole address is matched, port included. A redirect address refusal still answers `400 invalid_request`, and `error_description` names the reason: `Redirect URI is malformed` for a malformed address, `Redirect URI scheme is not allowed for this host` for a scheme that does not fit, `Redirect URI not registered` for an address that is not registered. An address with a username or a password in the URL is now always treated as malformed. Such an address cannot be registered in the dashboard.

**Impact on integrators**

A confidential client with a saved localhost address starts passing sign-in without editing its registration. If your application parses `error_description` as a string, account for the two new texts. If your application sent a username or a password in `redirect_uri` that the registered address does not have, that sign-in is now rejected: send the address exactly as it is registered.

### FIX-1014-7: Reference pagination advice respects unsupported filtering

**Before**

The [calendar section](/docs/entities/calendar-sections/list) and [calendar event](/docs/entities/calendar-events/list) cards recommended continuing traversal with an id filter that these methods reject with `400 UNSUPPORTED_FILTER`.

**After**

Entities that do not support filtering no longer receive this advice. The cards explicitly state that keyset pagination is unavailable and stable traversal under concurrent writes is not guaranteed. The section offset limitation remains documented. Method behavior is unchanged.

### FIX-1014-9: A missing method no longer means a missing record

**Before**

When Bitrix24 rejected an operation with a missing-method code, the V1 response depended on the description language: Russian text could produce `404 ENTITY_NOT_FOUND`, while English text produced `422 BITRIX_ERROR`.

**After**

This refusal returns `422 BITRIX_ERROR` with the original code in `error.b24Code`. The specific `409` refusals for unavailable modules, `422 METHOD_NOT_YET_AVAILABLE`, temporary unavailability errors and retry deadlines are preserved.

**Impact on integrators**

Do not treat a missing-method refusal as proof that a record is absent. Responses for truly missing records and the error shapes of individual calls inside a batch are unchanged.

### FIX-1014-11: Repetition in truncated JSON no longer suggests a higher limit

**Before**

When calling [POST /v1/chat/completions](/docs/ai/chat/completions) with a [JSON response](/docs/ai/chat/json), the model could repeat incomplete JSON until the token limit. The `structured_output_truncated` error suggested increasing `max_tokens`, thereby prolonging the repetition.

**After**

If repetition is detected in non-empty incomplete JSON after `finish_reason: "length"`, the response carries `reasoning_repetition` with a JSON-specific message, without `param` or `suggestedMaxTokens`. In a [stream](/docs/ai/chat/streaming), this is an error event before `data: [DONE]`.

**Impact**

The heuristic can also trigger on an expected repetitive array that exceeded the budget; a larger limit may help in that case. Completed-request accounting is preserved for both sync and SSE. The check runs after generation: the wait until the limit is unchanged. Complete JSON and short truncation without detected repetition retain their previous behavior. Successful responses remain successful.

### FIX-1014-12: product-row field dictionary no longer marks productId as required

**Before**

The product-row field dictionary returned `productId` with `isRequired: true`. A write, however, accepted a row without `productId`: the row was created with `productId` set to `0` and the name from `productName`.

**After**

Every product-row field has `isRequired` set to `false`, matching the write: it accepts a row that carries at least one writable field. Writing product rows is unchanged.

**Affected endpoints:** [GET /v1/deals/:id/products/fields](/docs/entities/deals/products-fields), [GET /v1/leads/:id/products/fields](/docs/entities/leads/products-fields), [GET /v1/quotes/:id/products/fields](/docs/entities/quotes/products-fields), [GET /v1/invoices/:id/products/fields](/docs/entities/invoices/products-fields), [GET /v1/items/:entityTypeId/:id/products/fields](/docs/entities/items/products-fields).

**Impact on integrators**

No action is needed. A form that derives required fields from this dictionary stops requiring `productId`. If a row without a catalog product is not acceptable for your use case, validate `productId` on your side.

### BC-1014-13: CRM dictionary record description comes in the description field instead of DESCRIPTION

> Old format supported until: not provided

**Before**

CRM dictionary records in the responses of [GET /v1/statuses](/docs/entities/statuses/list), [GET /v1/statuses/:id](/docs/entities/statuses/get) and [POST /v1/statuses](/docs/entities/statuses/create) carried the record description under the `DESCRIPTION` key, and [GET /v1/statuses/fields](/docs/entities/statuses/fields) listed it as a separate `DESCRIPTION` field. A `description` value passed when creating or updating a record was not saved.

**After**

The record description comes under the `description` key in the same responses and is described in the field reference as `description`. The `DESCRIPTION` key is no longer present in the responses or in the field reference. The `description` field is accepted when a record is created or updated. The field is not available on every Bitrix24 account. Filtering by `description` is not supported and returns `400 UNSUPPORTED_FILTER`.

**What integrators should do**

Read the record description from `description` instead of `DESCRIPTION`. To write a description, pass `description` in the create or update request body.

### BC-1014-14: PKCE is also enforced for confidential clients

> Old format supported until: not provided

**Before**

[GET /v1/connect/authorize](/docs/partner-connect) ignored `code_challenge` for confidential clients unless PKCE was mandatory. The code could be exchanged without `code_verifier`.

**After**

Every supplied `code_challenge` must be valid and accompanied by `code_challenge_method=S256`. Errors redirect to the verified callback with `error=invalid_request`. Exchange through `POST /v1/connect/token` requires the matching `code_verifier` together with `client_secret`, otherwise the response is `400 invalid_grant`. Without a challenge, exchange with a secret works as before.

**What integrators should do**

If you send a challenge, retain the original verifier until code exchange and send it to `/v1/connect/token`. Use only `S256`.

### BC-1014-15: Catalog product, SKU, and service date filters are rejected

> Old format supported until: not provided

**Before**

Filters on `dateCreate`, `timestampX`, `dateActiveFrom`, and `dateActiveTo` returned `200` with the entire catalog instead of the requested range.

**After**

[GET /v1/catalog-products](/docs/entities/catalog-products/list), [POST /v1/catalog-products/search](/docs/entities/catalog-products/search), [GET /v1/catalog-skus](/docs/entities/catalog-skus/list), [POST /v1/catalog-skus/search](/docs/entities/catalog-skus/search), [GET /v1/catalog-services](/docs/entities/catalog-services/list), and [POST /v1/catalog-services/search](/docs/entities/catalog-services/search) return `400 UNKNOWN_FILTER_FIELD` for these date filters. The same restriction applies to [POST /v1/catalog-products/aggregate](/docs/entities/catalog-products/aggregate), [POST /v1/catalog-skus/aggregate](/docs/entities/catalog-skus/aggregate), [POST /v1/catalog-services/aggregate](/docs/entities/catalog-services/aggregate) and to the legacy `GET /v1/catalog-products/aggregate`, `GET /v1/catalog-skus/aggregate`, `GET /v1/catalog-services/aggregate`. In a list sub-call for these three entities in [POST /v1/{entity}/batch](/docs/batch) and [POST /v1/batch](/docs/batch) the same code arrives in that sub-call's own error field, and the remaining sub-calls still run. The dates remain available in responses and `select`.

**What integrators should do**

Remove these dates from `filter` on every endpoint listed above, including list sub-calls of a batch. Use supported fields such as `id`, or filter the retrieved records by date in your integration after fetching all pages.

### FIX-1014-16: an AI key shared by the Bitrix24 account administrator works for account users

**Before**

A Bitrix24 account administrator connected a provider key in the Vibecode cabinet with the "Available to all Bitrix24 account users" option. An account user saw the key in their list of keys, but the provider's models were missing from the model list, and a model request returned `402 ai_credentials_not_configured`.

**After**

The provider's models on the shared key are in the account user's model list, and requests to them go through that key. If the user has their own key for the same provider, their own key is still used. Shared keys connected earlier are switched on after the update, except keys whose last verification with the provider failed: the account administrator needs to connect such a key again.

**Affected endpoints:** [GET /v1/models](/docs/ai/models/list), [POST /v1/chat/completions](/docs/ai/chat/completions).

**Impact on integrators**

No action is needed. An app that received `402 ai_credentials_not_configured` on a Bitrix24 account with a shared key connected will receive the model's response.
