For AI agents: markdown of this page — /docs-content-en/changelog/2026-08-25.md documentation index — /llms.txt
API changes: August 25, 2026
FIX-0825-1: an application card now gets its server on galaxy accounts too
Before
An application created without a server and then deployed on a galaxy account stayed in the Applications section with no server: GET /v1/applications/{id} returned server: null indefinitely. Linking the container to an already existing card depended on a setting that is off by default, so the card and the container lived apart.
After
The container is linked to the already existing card regardless of that setting, and GET /v1/applications/{id} returns the server right after the deploy. The setting still governs only the creation of a NEW card for an app created on a shared host — its behaviour is unchanged.
BC-0825-2: a read-only key no longer writes on platform endpoints
Old format supported until: not provided
Before
The read-only key mode filtered Bitrix24 calls but did not cover platform V1 endpoints.
A read-only key could still manage servers (DELETE /v1/infra/servers/{id},
POST /v1/infra/servers/{id}/stop|start|reboot|wake), deploy and run commands on a server,
write to storage (POST /v1/storage/objects), submit feedback (POST /v1/feedback), manage
search and AI credentials, and call endpoints that spend credits.
After
Any write on a platform V1 endpoint made with a read-only key returns
403 WRITE_BLOCKED_READONLY_KEY before the operation runs. Endpoints that proxy a call to
Bitrix24 are unchanged: there the decision comes from the per-method classifier, so reads
that carry a request body (POST /v1/deals/search, a read-only POST /v1/batch, and
similar) are not affected.
There are two exceptions. POST /v1/apps — a read-only key can still create an application
and its paired key IN read-only mode, but cannot issue a read-write key.
DELETE /v1/infra/servers/{id}/lock — releasing a stuck lock does not change server state
and stays available: the recoveryAction field of an EXEC_BUSY response points to it.
If your application needs these operations, switch the key to read-write mode on the
/keys page. You can check the current mode and whether server creation is available via
GET /v1/me: for a read-only key the response now carries a
writeRestriction field — the refusal code, the scope it applies to, and the address of the
access-mode page. It exists because the response names writing endpoints in some thirty
places (storage, feedback, source-storage and cowork hints); those are addresses, not
permissions, and the field says so outright. Per-operation availability stays in
capabilities.
FIX-0825-3: /v1/me no longer reports app creation as unavailable to a read-only key
In the GET /v1/me response the capabilities.apps.create slot came back with available: false and the reason WRITE_BLOCKED_READONLY_KEY under a read-only key. That was wrong: POST /v1/apps refuses such a key only when it asks for an app and paired key in read+write mode, while an app in READ-ONLY mode is created by the same key and answers 201.
The slot is now reported as available, with the restriction spelled out in its note field. A client that branches on capabilities — which is what /v1/me exists for — no longer skips an operation that works.
BC-0825-4: a Cowork desktop key can no longer change OAuth application registrations
Old format supported until: not provided
Before
A key carrying the system vibe:cowork grant could register an OAuth application on the Bitrix24 account (POST /v1/apps), edit it (PATCH /v1/apps/{id}), delete it (DELETE /v1/apps/{id}) and re-point it at other credentials (POST /v1/apps/{id}/relink-oauth). The same key was already barred from infrastructure, the source depot and catalog publishing, so the restriction was incomplete.
After
All four operations answer 403 INFRA_FORBIDDEN_FOR_COWORK_KEY, with details.deployableKeys listing the owner's usable keys. On POST /v1/apps the refusal comes before the body is checked, so an invalid body also gets this code rather than VALIDATION_ERROR. Reads of the family (GET /v1/apps, GET /v1/apps/{id}) are unchanged.
What to do
Run these operations under an ordinary application key: the vibe:cowork grant is platform-minted and meant for data only. Candidate keys arrive in details.deployableKeys of the same response — name, prefix and trailing characters, never the secret. There is no support window for the old behaviour: the vibe:cowork grant is not user-grantable, never appears in the key dialogs, and its only holder does not call these operations.
BC-0825-5: re-uploading a file now replaces its content instead of failing with 500
Old format supported until: not provided
Before
Uploading to a logical key that was already taken returned 500 with code P2002 from
POST /v1/storage/objects/upload. The bytes in storage had already been overwritten, while the
object sizeBytes and sha256 still described the previous version — so the size shown in listings
and billing did not match the actual file.
After
Re-uploading to the same key replaces the content: 200, the same object.id (previously issued
links keep working), and sizeBytes, sha256, contentType and the new contentUpdatedAt field
match the new bytes.
This applies to an app-bound key. With a personal developer key that has no app binding,
re-uploading still creates a new object with its own id — unchanged behaviour, fixed separately.
When the object cannot be replaced in place, a 409 with a meaningful code is returned instead of
500: STORAGE_KEY_DELETED (the object is deleted and holds the name until the purge),
STORAGE_MULTIPART_IN_PROGRESS (a multipart upload is in progress),
STORAGE_UPLOAD_PENDING (the key holds an unfinished presigned reservation),
STORAGE_KEY_OWNED_ELSEWHERE (the name belongs to another object of this app),
STORAGE_KEY_CONFLICT (the object changed while the upload was in flight — retry).
What you need to do
- The
visibilityfield cannot change visibility while replacing: omit it or pass the current value. Any other value returns400 STORAGE_VISIBILITY_MISMATCH, and the current value is named in the message. Such a request used to return500while still replacing the bytes — so a client that ignored the error was in fact publishing updates and will stop doing so after this change. - A presigned URL (
POST /v1/storage/objects) is no longer minted for an existing object:409 STORAGE_KEY_EXISTS. Its Content-Type is unsigned, so content can only be replaced by a direct upload. An unfinished reservation of your own is reused instead —200with the sameobject.idand a fresh URL; such a URL cannot change the reservation visibility, so a differing value returns400 STORAGE_VISIBILITY_MISMATCH. - A multipart upload (
POST /v1/storage/objects/multipart/create) on a taken key also answers409instead of500:STORAGE_KEY_EXISTS,STORAGE_KEY_DELETED,STORAGE_MULTIPART_IN_PROGRESS,STORAGE_UPLOAD_PENDINGorSTORAGE_KEY_CONFLICT(a concurrent request created the object). Replacing an object through a multipart upload is not supported — use another key. - Responses now carry
object.contentUpdatedAt— when the content last became current. It isnullfor objects written before this change.
BC-0825-6: the binding and author fields of a timeline comment no longer look editable
Old format supported until: not provided
Before
GET /v1/timelines/fields returned entityType, entityId and authorId as ordinary writable fields. PATCH /v1/timelines/{id} with any of them answered 200 and success: true, yet the value did not change — reading the record back showed the previous one. Meanwhile id and createdAt in the same output were honestly refused with 400 READONLY_FIELD, so the field reference told the truth only selectively. An integrator or an AI agent concluded it had changed the author or moved the comment to another record, while nothing had changed at all.
After
The three fields are marked immutable in the field reference, and an attempt to write them is refused with 400 READONLY_FIELD instead of a silent success. The reasons differ per field, and the reference now distinguishes them:
entityTypeandentityId— available on create only: a comment is bound to its record at the moment it is added, and it cannot be moved to another one;authorId— read-only: Bitrix24 derives the author from the credentials the call is made with, so the value cannot be set on update or on create.
comment stays writable — it is the only field the Bitrix24 update accepts.
What integrators should do
Drop entityType, entityId and authorId from the body of PATCH /v1/timelines/{id} — they were never applied, and now a request carrying them returns 400 READONLY_FIELD. Check creation separately: POST /v1/timelines carrying authorId also moves from "201, value ignored" to 400 READONLY_FIELD, because the author cannot be set on create either. entityType and entityId stay required and accepted on create. If your code treated the successful answer as proof that the author had changed or the comment had moved, that expectation was already unmet before this change: the value stayed as it was. The comment text still updates through a normal PATCH with the comment field. Set the binding at creation time through POST /v1/timelines; the author cannot be changed — make the call under the account you need.
No support window for the previous behaviour is provided, deliberately: the previous behaviour was the defect — it silently discarded the value that was sent, and keeping it for a period would mean prolonging a silent data loss.
BC-0825-7: deploy base version is required when the top saved source version belongs to somebody else too
Old format supported until: not provided
Before
POST /v1/infra/servers/{id}/deploy required baseVersionId only on a server that currently had a live development team. If the owner added a teammate, the teammate deployed their own version, and the owner later removed them from the team, the requirement disappeared along with the last team member — and the next deploy silently overwrote the saved work.
After
baseVersionId is also required when the top version saved in the server's source depot was saved by somebody other than the caller deploying now — regardless of whether the server currently has a team. The error is unchanged: 409 BASE_VERSION_REQUIRED naming the current version.
What integrations must do
Send baseVersionId on every deploy. A client that already does needs no changes. A client that relied on "no team means no label needed" will get 409 BASE_VERSION_REQUIRED on a server holding somebody else's saved version — including after an application ownership transfer, where the top version was saved by the previous owner. Handle it the way the team case is already handled: read the current version number from the error body and repeat the deploy declaring it as the base. The old behaviour is not kept for any period: it is exactly what caused other people's work to be lost.
NEW-0825-8: a server's development-team member now sees its application in the catalog
A member of a server's development team now sees the application bound to that server in GET /v1/applications (arriving with viewerState: "shared") and can read its card via GET /v1/applications/{id} — previously the card answered 403 FORBIDDEN, because access was checked only by ownership and by the server's access policy, without considering team membership.
FIX-0825-9: include is advertised only for entities with relations
Before
OpenAPI and the MCP reference advertised the include parameter for list, get, and search on every entity. For entities without available relations, a request with this parameter returned 400 INVALID_INCLUDE with an empty list of available relations.
After
OpenAPI advertises include only for entities with available relations, while the MCP reference directs clients to check the capability through discover or get_fields first. Runtime validation and the 400 INVALID_INCLUDE response for an unsupported include are unchanged.
Impact on integrations
Client generators no longer receive an unsupported include from OpenAPI, while MCP agents get explicit guidance to check the capability first. The common optional MCP key remains available. Existing valid requests continue to work unchanged, while previously unsupported requests receive the same 400 INVALID_INCLUDE response.
BC-0825-10: Inline archive cap on the deploy body narrowed to 96 MB
Old format supported until: not provided
Before
POST /v1/infra/servers/:id/deploy with code in inline source.content, POST /v1/infra/servers/:id/upload with inline content, and POST /v1/infra/servers with the source field at creation accepted a body up to 500 MB. A body over the cap was refused with PAYLOAD_TOO_LARGE.
After
The body of these three requests is capped at 96 MB. The unit is the HTTP body itself, not the archive: source.content / content is base64, which runs about a third larger than the raw bytes, so a 96 MB body corresponds to roughly a 72 MB archive. A body over the cap is refused with 413 INLINE_SOURCE_TOO_LARGE — a new code, replacing the former PAYLOAD_TOO_LARGE on these three endpoints. The refusal is decided from the Content-Length header before the body is read, so it is deterministic — re-sending the same body fails identically. It saves no traffic: the whole body is uploaded first, and the refusal arrives once the upload has finished. The error envelope carries error.hint with reason, recovery, recoveryAction and note fields — a ready recovery recipe.
The multipart (multipart/form-data) form of POST /v1/infra/servers/:id/deploy falls under the same cap conditionally. The file part streams into storage — and keeps its former 500 MB archive limit — only when three conditions hold at once: the caller reaches the server as its direct owner, not through another application's card or a management key; the server is either not a galaxy app, or both link-based-deploy settings for galaxy apps are turned on for the caller; and the source storage feature is enabled, both platform-wide and for that account. If even one condition fails, streaming does not kick in and the form accepts the archive the same buffered way as the base64 fields above — under the same 72 MB archive cap, with the same 413 INLINE_SOURCE_TOO_LARGE code and error.hint.
The former PAYLOAD_TOO_LARGE code has not gone away: it still applies at the edge nginx layer on /v1/ (500 MB cap) and on every other platform route with its own limit — nothing was renamed.
Unchanged:
source.url— still accepted up to 500 MB; the platform downloads the archive from the link itself;source.versionId— deploying an already-saved version, up to a 500 MB archive;- the source-version save cap on POST /v1/infra/servers/:id/sources and
POST /v1/apps/:id/sources— 500 MB, untouched.
What integrators should do
Send an archive larger than 72 MB through the versioned path in two calls — it works the same way for a personal key (vibe_api_*) and for an OAuth application key, and for the server's direct owner these two calls are all it takes:
POST /v1/infra/servers/:id/sources # raw archive bytes, Content-Type: application/gzip, --data-binary
POST /v1/infra/servers/:id/deploy # {"source":{"versionId":"vN"}}
If, on the other hand, the server is reached through an application card or a management key rather than by its direct owner, those two calls take a third one: {versionId} may answer SOURCE_VERSION_REQUIRES_APP or SOURCE_VERSION_NOT_FOUND — in that case fetch a signed link at GET /v1/infra/servers/:id/sources/vN/download and deploy from it instead: {"source":{"url":"<link>"}}. This same path is also the way around the multipart form's conditional cap — a versioned deploy never buffers the whole archive, so its 500 MB limit is unconditional.
The cap was narrowed at the observable-behavior level: a body of several hundred megabytes in base64 form (and a multipart archive for which at least one of the conditions above did not hold) had to be held in memory whole for the duration of the request, and such a request could abort without a response, taking concurrent requests on the same process down with it.
NEW-0825-11: `GET /v1/me` now names the archive equivalent of the inline cap as its own field
Before
The deployment.limits block carried the inline body cap in a single uploadInlineMax field. Its unit is the HTTP body, while source.content and content travel as base64, so the archive size that fits into that body was left for the client to work out.
After
A sibling field uploadInlineMaxArchive was added — the same cap expressed as an ARCHIVE size: three quarters of uploadInlineMax, because base64 runs about a third larger than the raw bytes. The field is added to the response and removes nothing from it: uploadInlineMax stays where it was and means what it meant, so a client that ignores the new field needs no changes. Both values arrive as strings with a unit — for example 96MB and 72MB.
What integrators should do
Nothing is required. If you were converting the body cap into an archive size yourself, read uploadInlineMaxArchive instead — it is rendered from the same constant as the 413 INLINE_SOURCE_TOO_LARGE refusal, so it cannot drift from the actual behaviour.
BC-0825-12: POST /v1/apps now honours the Bitrix24 account policy for who may create apps
Old format supported until: not provided
Before
The public route only checked the legacy list-based mode. An account whose Bitrix24 admin had
limited app creation to admins, or disabled it entirely, still let any personal API key create
an app — while the same action in the dashboard answered 403.
After
POST /v1/apps answers 403 with code APP_CREATION_RESTRICTED when the
account policy does not allow the caller to create apps. The list-based mode behaves as before:
a member on the list creates the app, everyone else gets 403. On accounts where creation is
open to all, nothing changes.
What integrators should do
A key issued on a restricted account will start receiving 403 APP_CREATION_RESTRICTED where
it previously got 201. Ask the Bitrix24 admin to grant the app-creation right, or create apps
with a key that already holds it.
FIX-0825-13: Node.js 20 runtime setup no longer repeats completed steps
Before
When redeploying a Node.js 20 runtime through POST /v1/infra/servers/:id/deploy, the platform reinstalled Node.js and pm2. An unavailable npm registry could consume the entire step budget and finish without a precise cause.
After
The platform skips installation when Node.js 20 and pm2 are already available. If pm2 is absent, its installation has time and retry limits, and an error or timeout stops deployment with an explicit diagnostic.
Impact on integrators
Repeat deployments finish faster and require no integrator changes. A pm2 installation error is now immediately visible as the cause of an unsuccessful deployment.
FIX-0825-14: placement bind answers 400 for an over-long iconName instead of a reasonless 502
Before
POST /v1/placements/bind accepted an options.iconName of up to 255 characters. Bitrix24 refuses anything longer than 50, so the request travelled to the account and came back as 502 BITRIX_UNAVAILABLE carrying "Failed to register placement on Bitrix24 via dev key". Which field was at fault could not be told from the answer.
After
The schema bound now matches the Bitrix24 bound: a value longer than 50 characters is refused up front, and the 400 names the options.iconName field. Values that bound before keep binding — anything longer than 50 was never accepted by the account, and the default fa-cube icon sits well inside the bound.