[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"docs-changelog\u002F2026-07-08":3,"docs-tabs-changelog\u002F2026-07-08":6},{"content":4,"lastmod":5},"# API changes: July 8, 2026\n\n[← Changelog](\u002Fdocs\u002Fchangelog) · [July 2026](\u002Fdocs\u002Fchangelog\u002F2026-07)\n\n### FIX-0708-1: GET \u002Fv1\u002Fdoc-templates and POST \u002Fsearch now honour order and offset\n\n**Before**\n\nThe `order` and `offset` parameters on `GET \u002Fv1\u002Fdoc-templates` and `POST \u002Fv1\u002Fdoc-templates\u002Fsearch` were silently ignored: the list always came back sorted ascending by `id`, and `offset` did not move the window. The underlying Bitrix24 method returns templates as an id-keyed object, and the requested order was lost while unwrapping the response.\n\n**After**\n\nSorting (`order[field]=asc|desc`, including multi-field) and windowing (`offset`\u002F`limit`) are applied on the Vibecode side: the full template set is fetched, sorted, and sliced to the requested window. `total` and `hasMore` are computed from the actually collected set.\n\n**Impact on integrators**\n\nIf you relied on the implicit ascending-by-`id` order at `offset=0` with no sort, nothing changes — that stays the default. `POST \u002Fv1\u002Fdoc-templates\u002Fbatch` (batch list) is unaffected. String order (`name`, `region`) is byte-wise, not locale-aware.\n\n### NEW-0708-2: GET \u002Fv1\u002Fapps\u002F:id\u002Fsources — new linkedServerSources field\n\n[GET \u002Fv1\u002Fapps\u002F:id\u002Fsources](\u002Fdocs\u002Fsource-storage) now additionally returns a `linkedServerSources` field — source versions stored under a server (via `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fsources` or auto-save on deploy), grouped by server, each with its own `serverContext`. Such versions previously did not appear in this response when saved under a personal key — they are now visible.\n\nThe field is additive: `versions`, `totalVersions`, `currentVersionId` and `totalSizeBytes` are unchanged and still list only app-scoped versions. Alongside it come `linkedServerSourcesTruncated` (a truncation flag for very large histories) and `linkedServerHint`, which points to `GET \u002Fv1\u002Finfra\u002Fservers\u002F:serverId\u002Fsources` — the authoritative full list and download for those versions. The section is populated for the app author (personal key) and the Bitrix24 account administrator; it is empty when called with an OAuth application key, and is not computed on a `?sha256=` probe.\n\n### NEW-0708-3: preemptible field on the server plans list response\n\nThe [GET \u002Fv1\u002Finfra\u002Fproviders\u002F:id\u002Fplans](\u002Fdocs\u002Finfra\u002Fproviders\u002Fplans) response now formally documents the `preemptible` field on each plan. A preemptible plan is cheaper, but the cloud force-restarts such a machine roughly once a day — it is not suitable for continuous 24\u002F7 workloads. For a server, agent or bot that must run without interruption, pick a non-preemptible plan (`preemptible` is `false` or absent).\n\nThe field was already returned by the runtime — this entry formalizes it in OpenAPI and the docs; no change to existing integrations is required.\n\n### NEW-0708-4: GET \u002Fv1\u002Fmodels\u002F:id now reports a retired model's successor price and a replaced_by field\n\nFor a model that has been retired, the by-id detail request now returns a `replaced_by` field with the identifier of the successor model that actually serves the calls, and the `pricing` field shows that successor's price — the price the request is billed at. Previously `pricing` showed the retired row's own zero price, making the model look free while a paid successor served the calls. Ordinary models and existing calls are unchanged.\n\n### FIX-0708-5: list auto-pagination preserves row order for limits above 550\n\n**Before**\n\nAuto-paginated list reads — `GET \u002Fv1\u002F{entity}?limit=…` and `POST \u002Fv1\u002F{entity}\u002Fsearch` — returned rows out of order when `limit` exceeded ~550: internal result pages were merged in the wrong sequence relative to what Bitrix24 returned, so the `order` parameter was not honored across the final array. When the collection held more rows than `limit`, the window trim could drop rows from the middle of the sorted set while keeping later ones.\n\n**After**\n\nPages are merged strictly in Bitrix24 return order: rows arrive in the requested sort for any `limit`, and the `limit` trim no longer drops rows from the middle of the set because of wrong merge order.\n\n**Impact on integrators**\n\nNo changes required. If you re-sorted large result sets on your side as a workaround, that is no longer needed.\n\n### FIX-0708-6: auto-pagination no longer silently drops a page when a batch sub-request fails\n\n**Before**\n\nWith `limit > 50` the list is assembled from batch sub-requests of 50 records each. If Bitrix24 rejected one sub-request (most often on its request limit — `QUERY_LIMIT_EXCEEDED`), that page silently fell out of the middle of the set: the response stayed `200` with an undetectable 50-record hole in the data (e.g. records 1–200 and 251–600 without 201–250), while `meta.total` and `meta.hasMore` looked self-consistent.\n\n**After**\n\nFor lists, plain search, batch sub-calls and aggregations the result is always a contiguous prefix of the set: records past the failed page are dropped, `meta.hasMore` stays `true`, and the response carries `meta.pageErrorSample { code, message }` with the failure reason — mirroring windowed search's `meta.windowErrorSample`. The field is added to list responses (e.g. [GET \u002Fv1\u002Fdeals](\u002Fdocs\u002Fentities\u002Fdeals\u002Flist)), to `POST \u002Fv1\u002F{entity}\u002Fsearch` (e.g. [deals](\u002Fdocs\u002Fentities\u002Fdeals\u002Fsearch)), to per-sub-call `meta` of [POST \u002Fv1\u002Fbatch](\u002Fdocs\u002Fbatch) and to `data.meta` of `POST \u002Fv1\u002F{entity}\u002Faggregate` (where it explains why `recordsProcessed` is below `totalRecords`). In windowed search (a wide date range) the set is assembled from windows, so a page lost inside one window can leave that window's tail missing — there the incompleteness signal is `meta.pageErrorSample` itself, not `meta.hasMore`. In all cases the field appears only when the returned page is actually shorter than `limit`: a full page is never flagged with a false alarm. Incomplete responses are never cached: a retry goes straight to Bitrix24.\n\n**Impact on integrators**\n\nNo client changes required: result sets that could previously contain an invisible hole are now correct, and the shortfall reason is visible in `meta.pageErrorSample`. Fetch the remainder by retrying with `offset` equal to your original `offset` plus the number of records received — except for windowed searches over a wide date range (`offset` is not supported there: narrow the range or retry later).\n\n### BC-0708-7: structured output: a truncated or empty result now returns 422 instead of an empty 200\n\n> Old format supported until: 08.07.2026\n\n**Before**\n\n[POST \u002Fv1\u002Fchat\u002Fcompletions](\u002Fdocs\u002Fai\u002Fchat\u002Fcompletions) with `response_format` (`json_object` or `json_schema`) could return `200` with `content: null` (or a truncated, unparseable JSON string) plus a warning that clients ignored, when generation was cut off. This happened most often on reasoning models: the reasoning phase consumed the whole `max_tokens` budget before the model produced the JSON. The response looked successful but could not be parsed.\n\n**After**\n\nSuch a request now returns `422` with `code: \"structured_output_truncated\"`, plus `finishReason`, `suggestedMaxTokens` (a larger `max_tokens` to retry with), and `param: \"max_tokens\"`. In streaming mode a `{\"error\":{\"code\":\"structured_output_truncated\"}}` frame is emitted before `data: [DONE]` — read the stream through to `[DONE]`. Additionally, for free reasoning models given a too-small `max_tokens` the platform raises the budget to a safe minimum and tags the successful response with a `MAX_TOKENS_RAISED` warning. The truncated attempt still consumes and bills tokens.\n\n**What integrators should do**\n\nHandle `422 structured_output_truncated` in your error branch and retry with a larger `max_tokens` (you can use the `suggestedMaxTokens` value). For strictly deterministic JSON, set a generous `max_tokens` or use a non-reasoning model.\n",null,{},1794739469956]