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

API changes: August 23, 2026

← Changelog · August 2026

BC-0823-1: OpenAPI no longer offers create-only fields in PATCH

Old format supported until: not provided

Before

Fields accepted by the API only when creating a record appeared in GET /v1/openapi.json as ordinary PATCH body properties. A client generated from that schema could send them on update and receive 400 READONLY_FIELD.

After

For entities with create-only fields, PATCH uses a separate input schema without those fields. Other entities keep using their existing PATCH input schema. In both cases, the POST input schema preserves the create contract.

What integrators should do

Regenerate the SDK from the new OpenAPI schema and use the type referenced by each PATCH requestBody. Affected entities use UpdateInput; other entities keep Input. Remove fields allowed only during creation from update payloads; POST continues to use Input.

NEW-0823-2: several employees can work on one application's code

A server owner can now assemble a development team: employees of the account work with the server using their own personal keys, with no key handover and no server rebinding. The Developer role gets deploy, exec, upload, logs and the source depot; the Admin role additionally manages the machine: lifecycle (stop, start, reboot, sleep schedule, repair), settings and security, plan and disk, backups, the custom domain, the catalog card, the application audience and the costs. Team membership, server deletion, access links and key rebinding stay with the owner. Team membership is edited by the owner or a Bitrix24 account administrator on the Collaboration tab.

Access comes from membership, not from the key, so removing somebody from the team closes their access immediately. The feature is gated by the server-collaboration flag.

A team member's deploy differs from the owner's in three ways. Environment variables are preserved: the env field of their request is not applied (the response carries a warning), and the variables already set on the application survive the deploy — including galaxy applications, where every deploy used to wipe them. The Bitrix24 catalog card and the release announcement stay with the owner: displayName, description and the changelog announcement sent by a Developer are ignored with a warning, while the version note itself is still stored in the source depot.

There is also an overwrite guard: the baseVersionId field in the body of POST /v1/infra/servers/:id/deploy ("this is the source version I based my work on", e.g. v12). If a newer version has appeared in the depot, the deploy is refused with SOURCE_VERSION_STALE, carrying the current version number and a download link — instead of silently overwriting.

The declared version is checked for existence: a number ahead of the depot is refused with BASE_VERSION_NOT_FOUND and the current version number — otherwise any non-existent number would switch the guard off.

On a server whose owner has assembled a development team the field is required as soon as the depot holds any version: a deploy without it answers BASE_VERSION_REQUIRED and names the current version. A blind deploy over a colleague's changes is therefore refused even when nobody knew about the guard. On a server without a team the field stays optional and a deploy without it behaves exactly as before. So that the version number has somewhere to come from, the version-download response now carries a versionId field next to the link — see Source code storage.

A 409 EXEC_BUSY refusal now names whoever is holding the server: error.hint.holder carries the employee name, the kind of operation and when it started, and error.hint.reason begins with that name. A background platform operation has no human behind it, so holder.name comes back empty there. The field is additive — the existing fields of the refusal are unchanged.

A team member now sees the server in the API instead of working with it blind. GET /v1/infra/servers also returns the servers whose development team the caller belongs to: those rows carry an access block with via: "collaborator", the role, the allowed actions and the endpoints open to them, while the key's own rows carry access.via: "owner". GET /v1/infra/servers/:id answers a member with 200 and a reduced card (no IP, no SSH access, no managing key; costs and the sleep threshold follow the role) instead of the former 404. GET /v1/me lists the memberships in infra.collaboratorServers. Waking the machine, POST /v1/infra/servers/:id/wake, is open to the Developer role as well — the matrix promised it before, but the call answered 404. Searching for an employee to configure the audience, GET /v1/infra/servers/:id/b24-users, is open to the Admin role — it used to answer a refusal even though that same role already configures the audience itself.

Additionally: a team admin can now perform, via their own personal API key, every server operation their role allows — lifecycle control (stop, start, reboot, sleep, manual repair, wake schedules, metrics), settings (SSH access, port, Bitrix24 event subscriptions, switching the BLACKHOLE/OPEN mode via PATCH /v1/infra/servers/:id/mode), the catalog card (PATCH /v1/infra/servers/:id — name and description), and access audience (access policy, user/department access list). Previously these operations returned 403/404 via a member's V1 key regardless of role — they only worked from the Vibecode dashboard. V1 membership lists can now return a page: GET /v1/infra/servers accepts optional page and limit and returns a true total alongside. Without the parameters the response is unchanged and complete — the contract stays as published. In /v1/me the infra.collaboratorServers block gained a total field.

Deleting source versions stays with the owner: DELETE /v1/infra/servers/:id/sources/:versionId and the bulk POST /v1/infra/servers/:id/sources/cleanup answer a team member of any role with 403 NOT_AUTHORIZED. Listing, downloading, depositing and tagging remain open to them.

A member's deploy that must preserve the environment refuses to run when the environment cannot be read: instead of silently deploying with an empty environment it answers 502 GALAXY_PRESERVED_ENV_UNREADABLE with a retryable marker. The application keeps running its previous version.

A role refusal is now distinct from "no such server". A management operation not covered by the member's role answers 403 SERVER_ROLE_FORBIDDEN; error.hint carries their role, the role required, the denied action and the endpoints that are open to them. For an unrelated key the existence of the server stays hidden — it still gets a 404.

An app whose owner has been deleted survives only while its team still has an admin — someone who can take it over. A team of developers alone does not hold the app: nobody can manage it, so it is cleaned up like any other ownerless app.

The appUrl field in GET /v1/infra/servers, GET /v1/infra/servers/:id and GET /v1/me (the infra.collaboratorServers block) no longer promises a team member a link they are not allowed to open. Previously the field came back non-empty as soon as the server had a subdomain, regardless of whether the application's audience actually let that particular person open it — following such a link answered with a refusal. Now appUrl is empty whenever the audience (accessPolicy) does not open the application to every account employee and the member has no personal access grant. There is one exception: a member whose access comes through a department grant does not see the link yet even though they could open the application — for now the server's owner or team admin has to hand it to them directly.

FIX-0823-3: platform public URLs no longer point away from the stand

Before

OAuth metadata (GET /.well-known/oauth-authorization-server) built issuer and the endpoint URLs from the APP_URL variable, which the deployment does not set for the backend, with a http://localhost:3000 fallback. With that variable unset the document advertised an address no client can reach.

The welcome page at GET /v1/me had a different cause with the same outcome: it built every URL from the instance domain at once — both the images and the "Documentation" / "Home" buttons. On a stand those buttons led to the production dashboard.

After

OAuth metadata resolves through a shared helper that refuses a loopback value in production and falls back to the instance public domain.

The welcome page now keeps two addresses apart: images still load from the instance domain (otherwise they would not open), while everything clickable leads to the dashboard of the stand the page was opened from.