For AI agents: markdown of this page — /docs-content-en/changelog/2026-07-13.md documentation index — /llms.txt
API changes: July 13, 2026
FIX-0713-1: OAuth application key platform scopes now sync on create and edit
Before
A key issued together with an OAuth application via POST /v1/apps did not receive the platform scopes (vibe:infra, vibe:ai, vibe:search, vibe:storage) that a key created in the dashboard gets. As a result POST /v1/infra/servers under such a key returned 403 INFRA_SCOPE_REQUIRED. Adding vibe:infra to the app's scopes via PATCH /v1/apps/:id changed only the app, not the paired key — so it had no effect on access.
After
The paired key created via POST /v1/apps now receives the same default platform scopes as a key created in the dashboard. A vibe:* scope change via PATCH /v1/apps/:id (both add AND remove) now propagates to the app's active keys. A read-only (READONLY) key is rejected with 403 WRITE_BLOCKED_READONLY_KEY on three write operations: server creation (POST /v1/infra/servers), app scope change (PATCH /v1/apps/:id), and READWRITE key issuance (POST /v1/apps with mode: "READWRITE").
Impact on integrators
Apps created via the API can now manage infrastructure without re-creation. A key whose app already declares vibe:infra while the key itself lacks it (the old divergence) is fixed with one edit: remove vibe:infra from the app's scopes and add it back via PATCH /v1/apps/:id — the second edit syncs the key; or re-create the app. A READONLY key can still create a READONLY app (mode: "READONLY").
FIX-0713-2: product-sections: unsupported filters return 400 instead of the whole table
Before
Operators (>, <, !, %, $ne, $contains, $nin) and non-exact-match fields (sort, unknown) in the filter of GET /v1/product-sections and POST /v1/product-sections/search were silently ignored — the code 200 and the whole list were returned unfiltered.
After
Such filters are rejected with 400 UNSUPPORTED_FILTER. Filter by exact match or $in on id, name, xmlId, code, catalogId, sectionId. Sorting (order/sort) is unchanged.
Impact on integrators
Calls with operators or filter[sort] that previously returned 200 with unfiltered data now return 400 — switch to exact match or $in.
FIX-0713-3: the reason for a failed first server provisioning is now visible
Before
If a server failed to come up on its first creation (a preemptible plan evicted, no free capacity), it silently ended up in sleeping status with no explanation. A client polling GET /v1/infra/servers/:id saw sleeping and could not tell why the deploy was blocked.
After
Such a server now moves to status: "error" with a populated provisionError (a human-readable reason) and a new provisionErrorCode field — a machine-readable failure category (PREEMPTIBLE_EVICTION / PROVISION_TIMEOUT / NO_CAPACITY / GENERIC). The provisionErrorCode field is added to GET /v1/infra/servers/:id and GET /v1/infra/servers next to provisionError (additive, null when there were no errors).
Integrator impact
No action needed: error is an already-existing status. Recover such a server via POST /v1/infra/servers/:id/start or /repair (not /wake: on error status it returns 422; the availableActions field in the response points to the available action).
NEW-0713-4: POST and PATCH /v1/tasks/:taskId/time accept createdDate
An optional createdDate field is now forwarded on POST /v1/tasks/:taskId/time and PATCH /v1/tasks/:taskId/time/:itemId — the time entry lands on the given date instead of the current moment (backfilling last week's tracks). ISO 8601 with offset, bare ISO, and YYYY-MM-DD are all accepted and passed to CREATED_DATE verbatim. When the field is omitted the behaviour is unchanged — the date equals the creation moment.
FIX-0713-5: meta.hasMore no longer stays stuck at true with filter + offset
Before
When paginating a filtered list (for example GET /v1/deals with filter and offset), meta.hasMore stayed true at every offset — even well past meta.total. A while (meta.hasMore) { offset += limit } loop ran forever.
After
When Bitrix24 ignores an offset beyond the filtered set and returns the whole set, meta.hasMore is derived from the request window (offset + limit < meta.total) instead of being forced to true. At offset=0 the response is unchanged; once the window passes total, hasMore becomes false. Applies to list and POST /search across all entities.
FIX-0713-6: GET /v1/lists and /v1/lists/:iblockId/elements honour offset
Before
GET /v1/lists/:iblockId/elements and GET /v1/lists silently ignored offset — ?limit=50&offset=50 returned the same first page, and a client paginating by offset never reached rows 51 and beyond.
After
offset is mapped to start, the native pagination param for these methods, so offset-based paging works. An explicit start keeps priority when both are supplied.
NEW-0713-7: New preserveEnv flag keeps .env across cleanDeploy
The POST /v1/infra/servers/:id/deploy body gained an optional boolean preserveEnv (default false). When cleanDeploy: true (which wipes the app directory including the .env file) and preserveEnv: true, the existing .env is read before the wipe and restored afterwards unless this request also passes env (a supplied env wins). Without the flag a re-deploy with cleanDeploy could boot the app with no environment variables — on its default port.
NEW-0713-8: failed galaxy app builds now carry a `buildHint`
Before
A galaxy app build failure returned only GALAXY_APP_BUILD_FAILED
(and GALAXY_APP_START_FAILED) with a buildLog tail — you had to read the log
by hand to find the cause. GET /v1/infra/servers/:id for an ERROR app returned a
short provisionError but no ready recommendation.
After
The response now carries the parsed cause. The error body of
POST /v1/infra/servers/:id/deploy (502) additionally includes error.category
(a machine category such as MODULE_NOT_FOUND, INSTALL_AUTH, RESOURCE) and
error.buildHint — a localized recommendation line naming the concrete next step,
whenever the failure is classifiable. GET /v1/infra/servers/:id for an ERROR app
adds the same data.buildHint field. The fields are additive: when the cause is
unrecognized they are absent (buildHint is null), and provisionError/buildLog
keep arriving as before — existing requests are unaffected.
FIX-0713-9: concurrent identical source saves no longer mint a duplicate version
Before
Two simultaneous saves of identical bytes to the same server (POST /v1/infra/servers/:id/sources, and the auto-save on deploy) could, under rare timing, create two byte-identical versions instead of one — content deduplication was best-effort.
After
Deduplication is deterministic: identical bytes submitted concurrently always converge on a single version. On POST /v1/infra/servers/:id/sources both responses return the same versionId and the losing request gets deduplicated: true; the deploy auto-save converges on that same single version (the deploy response shape is unchanged).