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

API changes: September 1, 2026

← Changelog · September 2026

FIX-0901-1: a permission refusal on the sprint board arrives as 403, not as a platform error

Before

A key whose user has no access to the scrum project got 422 BITRIX_ERROR for the sprint board columns — the same class the Vibecode platform uses to report a Bitrix24 business error. The code gave no way to tell "no rights" from "something is temporarily off on the account", so the request was retried even though the state is stable and a retry changes nothing.

HTTP 422
{ "success": false, "error": { "code": "BITRIX_ERROR", "message": "Access denied", "b24Code": "0" } }

After

GET /v1/scrum/sprints/{sprintId}/stages and POST /v1/scrum/sprints/{sprintId}/stages answer a permission refusal with 403 BITRIX_ACCESS_DENIED — the code the common error reference already describes. It reads as "do not retry, grant the user access to the scrum project instead".

HTTP 403
{ "success": false, "error": { "code": "BITRIX_ACCESS_DENIED", "message": "Access denied" } }

Successful responses are unchanged: the column list still arrives with HTTP 200 and a created column with HTTP 201. The answer for a missing sprint is unchanged too — it stays 404 ENTITY_NOT_FOUND.

BC-0901-2: an empty employee photo is refused on update

Old format supported until: not provided

Before

On employee UPDATE, an empty or whitespace-only string in personalPhoto reached Bitrix24 as a command to remove the current photo. The single PATCH /v1/users/:id returned 200 success:true even though the photo was removed.

After

Such values are refused with INVALID_PARAMS before the Bitrix24 call. The single PATCH /v1/users/:id returns 400 success:false; batch routes keep their existing error envelopes. The global POST /v1/batch also refuses personalPhoto: null: its sub-call encoder turns null into an empty query-string value, the same remove-the-photo command. On PATCH /v1/users/:id and in the per-entity batch, null gets no new refusal. To leave the photo unchanged, omit personalPhoto. On CREATE in POST /v1/users, an empty string does not get the new refusal; the working inline pair and separate employee-invite validation are unchanged.

FIX-0901-3: rate limit descriptions now name the replica share, not just the total cap

Before

The descriptions of POST /v1/feedback in the GET /v1/guide directory, in the feedback.limits block of the GET /v1/me response and in the GET /v1/openapi.json schema named the limit as a number — "5 requests per minute". Requests are served by several backend replicas and each one holds its own share of the limit, so the client received less than promised and the X-RateLimit-Limit header disagreed with the description. The same mismatch was present on the help pages for submitting a ticket and uploading an attachment, and in the schema for five operations of the Cowork section.

After

The descriptions name the number and explain next to it that the cap is divided across the replicas, while the value actually in force arrives in the X-RateLimit-Limit header. For the Cowork operations in the schema, the 429 refusal description is aligned with the form already used on the help pages. A single shared 429 row on the feedback page is split in two — creating a ticket and uploading an attachment carry different counters.

Impact on integrators

The limit values did not change and the behaviour is the same as before. A client that relied on the number from the description was refused earlier than expected — the source of the value in force is now named explicitly: read X-RateLimit-Limit from the response.

BC-0901-4: task comment updates reject read-only fields

Old format supported until: not provided

Before

On a legacy card, PATCH /v1/tasks/:taskId/comments/:id could return HTTP 200 when a client sent a comment object from GET with an updated message, forwarding read-only fields to Bitrix24. An item in POST /v1/tasks/:taskId/comments/batch could similarly finish with success:true.

After

A single PATCH containing a read-only field returns HTTP 400 READONLY_FIELD before Bitrix24 is called. For a successful legacy-card comment update containing only {message}, the response remains HTTP 200; the existing 410 GONE remains unchanged on the new card.

In the custom batch, the top-level response remains HTTP 200 with success:true; the rejected item gets success:false and error:READONLY_FIELD, is not sent to Bitrix24, and does not stop valid sibling items.

What integrators should do

For a single PATCH, build a new body containing only {message}; do not send response fields such as id, taskId, authorId, createdAt, or their aliases back to the endpoint. In a custom batch item, keep lowercase id as the comment selector and send only message beside it; remove an additional ID and all other read-only fields. Clients that already send only documented writable fields need no changes.

FIX-0901-5: the 401 TOKEN_MISSING error now names the reason on every V1 route

Before

The reason a personal key had no Bitrix24 webhook was named only on entity routes (/v1/deals, /v1/tasks and so on) and in POST /v1/batch. Every other family — chats, lists, mail, scrum, notes, Open Channels, bots, userfields and the rest — answered with the flat text "API key has no tokens configured." and no error.details field. The same broken key got an explanation on /v1/deals and a text that implied nothing on /v1/chats.

After

The 401 TOKEN_MISSING body is built the same way on every V1 route: a personal key gets the reason in error.details.reason plus the text naming the required action, an app key gets a pointer to the missing OAuth step. The response remains HTTP 401 and the set of codes is unchanged.

Impact on integrators

Read error.details.reason — that is the contract, not error.message. The message text on these routes has changed, so code comparing it with the literal "API key has no tokens configured." stops matching; that parsing was unreliable before as well. The reasons are listed in the GET /v1/me response under b24Credentials.

FIX-0901-6: direct upload can be repeated after object deletion

Before

After a successful DELETE /v1/storage/objects/{key}, a new direct POST /v1/storage/objects/upload with the same key returned 409 STORAGE_KEY_DELETED until the object was physically purged 30 days later.

After

For an app object in the COMPLETED state without a multipart session, direct upload returns HTTP 200, preserves the same id and visibility, and writes new content. A deleted public link with that id becomes available again with the new bytes. This does not restore the previous content.

Path B remains disabled and returns 503 STORAGE_PRESIGNED_UPLOAD_DISABLED without a URL. Path C, deleted PENDING objects, and objects with a multipart session continue to return 409 STORAGE_KEY_DELETED. DELETE itself and subsequent reads without a new eligible direct upload continue to return 410 STORAGE_OBJECT_DELETED during the retention period.

Impact on integrations

No request changes are required. After deleting an eligible object, send the new bytes with a regular direct upload using the same key.

FIX-0901-7: a transient image-registry outage no longer marks a galaxy app broken

Before

POST /v1/infra/servers with a source field that hit 502 GALAXY_BASE_IMAGE_UNAVAILABLE — or ran the host out of disk — flipped the slot to status=error, even though the same refusal on POST /v1/infra/servers/:id/deploy left the status untouched and the error text promised the slot, its container and its /data volume were intact. Re-sending the deploy never cleared that error: GET kept reporting a broken slot, and the app stopped holding its host awake.

After

Both transient refusals leave the slot at status=provisioning; the cause stays readable in provisionError of GET /v1/infra/servers/:id. Re-sending the same deploy to a slot broken by such a cause clears error at the start of the attempt. An abandoned slot is still failed by the platform after ~20 minutes, but it keeps its real cause instead of the generic DEPLOY_INCOMPLETE. The error.hint copy, the /v1/me checklist and the docs no longer promise a "2–3 minutes" window: the registry outage can last an hour.

BC-0901-8: Regular chat-bot blocks key deletion

Old format supported until: not provided

Before

Deleting an API key could delete its linked regular chat-bot together with the token required for normal unregistration on Bitrix24.

After

Deleting a key with a regular chat-bot, including a disabled Bot Platform row, returns 409 KEY_HAS_LINKED_AGENT. Take numeric bitrixBotId from details.bots in the 409 response, then unregister the bot through DELETE /v1/bots/:botId or transfer it to another key.

FIX-0901-9: file uploads and AI requests now answer 429 under memory pressure

Before

POST /v1/files/upload (up to 70 MB), POST /v1/note/documents/{id}/files (up to 40 MB), POST /v1/chat/completions (up to 30 MB) and POST /v1/audio/transcriptions (audio up to 25 MB) accepted any number of concurrent large bodies. Several parallel uploads at the ceiling could drop requests without a response — other requests in flight at that moment included.

One more observable difference: a request with a missing or invalid key on these routes could get 400 (unparsed JSON), 413 (size) or 415 (content type) — an answer about the body before the answer about the key.

After

Concurrent bodies over 1 MiB are bounded by their total size. A request over the bound gets 429 with code LARGE_BODY_BACKEND_BUSY and a Retry-After: 5 header, emitted before any Bitrix24 call, so it carries no side effects — and identically whether or not Content-Length is declared:

JSON
{
  "success": false,
  "error": {
    "code": "LARGE_BODY_BACKEND_BUSY",
    "message": "Too many large request bodies are being processed. Retry in a few seconds.",
    "retryAfter": 5
  }
}

On the OpenAI-compatible POST /v1/chat/completions, POST /v1/ai/chat/completions and POST /v1/audio/transcriptions (+ POST /v1/ai/audio/transcriptions) the envelope matches the rest of that surface — no success, lowercase code:

JSON
{
  "error": {
    "message": "Too many large request bodies are being processed. Retry in a few seconds.",
    "type": "rate_limit_exceeded",
    "code": "large_body_backend_busy",
    "retryAfter": 5
  }
}

A request with a missing or invalid key now gets 401 on all of these routes — the key is checked before the body is read. Successful requests and bodies under 1 MiB are unaffected; a retry after 5 seconds succeeds.

Important: on transcriptions the bound is counted from the declared Content-Length. An upload without one (Transfer-Encoding: chunked) is not counted against the shared total and is bounded only by its own 25 MB per-file ceiling.

FIX-0901-10: creating a Hermes agent no longer fails because of the startup payload size

Before

Creating a Hermes agent failed right after the server step. The virtual machine was never created, the agent stayed in the error state with an incident code, and the server field on the card stayed empty. Retrying produced the same result. The cause was the cloud startup payload growing past the size limit the cloud allows for such payloads.

After

Internal comments are no longer shipped to the cloud together with the install script, so the startup payload fits well within the limit again and the virtual machine is created. The install script itself and every other delivery path for it are unchanged. In addition, a size check now runs before the cloud is called: should the payload ever grow past the limit again, no cloud request is sent at all and Vibecode returns the usual provider error with an incident code.

NEW-0901-11: the business-process editor is available through the API

A new /v1/workflow-designer/* section works with templates of the new business-process editor in the editor's own language: blocks, connections, a catalog of block types, graph validation, drafts and publication. It is not the same as /v1/bizproc-templates, which reads and writes template rows with the graph as an opaque blob.

The bizprocdesigner scope is required — a separate one from bizproc. Add it to the key and re-issue the key.

Writing takes two steps. POST /v1/workflow-designer/templates/{id}/draft saves a draft: the running business process keeps executing its published version, so a draft can be shown to a person, rewritten or thrown away. POST /v1/workflow-designer/templates/{id}/publish makes the draft the working version — irreversibly, and it deletes every draft of the template, other people's included. Publication requires the draftFingerprint from GET /v1/workflow-designer/templates/{id}, so that exactly the graph you read and showed the person is the one published; a draft someone rewrote in the meantime is refused instead of quietly replacing it.

Start with GET /v1/workflow-designer/capabilities: it answers whether the editor is available to this Bitrix24 account and this key, and names the reason when it is not (DESIGNER_NOT_SUPPORTED — Bitrix24 is not updated to a version that serves the editor through the API, or the module is absent, DESIGNER_UNAVAILABLE — switched off or not in the plan, SCOPE_DENIED — the key lacks the scope, DESIGNER_REQUIRES_WRITE_KEY — the key is read-only and the operation writes, DESIGNER_PROBE_FAILED — the check did not complete and the editor state is unknown). These states cannot be told apart from a refusal of the methods themselves, which is why the check is a call of its own.

A read-only key is served by this section: the graph, the block catalog, the document fields, the instructions from Bitrix24 and validate all read. DESIGNER_REQUIRES_WRITE_KEY arrives only on the three writing operations — creating a template, saving a draft and publishing one.

Affected endpoints: GET /v1/workflow-designer/capabilities, POST /v1/workflow-designer/templates, GET /v1/workflow-designer/templates/{id}, GET /v1/workflow-designer/templates/{id}/brief, GET /v1/workflow-designer/templates/{id}/blocks, GET /v1/workflow-designer/templates/{id}/blocks/{blockId}, GET /v1/workflow-designer/templates/{id}/document-fields, POST /v1/workflow-designer/templates/{id}/validate, POST /v1/workflow-designer/templates/{id}/draft, POST /v1/workflow-designer/templates/{id}/publish

BC-0901-12: deleting a server now deletes the agent bound to it

Old format supported until: not provided

Before

DELETE /v1/infra/servers/:id deleted the server only. The agent that ran on it stayed alive on the Vibecode platform: its state still read as running, its bot stayed registered in the Bitrix24 account, its key stayed valid, and the agent pointed at a server that no longer existed.

After

The agent bound to the server is deleted together with it. The agent row is marked deleted, the bot is removed from the Bitrix24 account, the agent key is revoked, and the application card is removed from the Bitrix24 catalog. A successful delete still answers HTTP 200 with the body {"success": true}.

One new outcome appears. If another request was changing that same agent concurrently, the answer is 409 AGENT_DELETE_CONFLICT in the usual rejection shape {"success": false, "error": {"code": "...", "message": "..."}}. In that case the server is not deleted either: it keeps running and keeps being billed, and the request has to be repeated.

What integrators should do

An integration that expected the agent to survive a server delete and be reused has to be reworked: create the agent again after creating the new server. Treat AGENT_DELETE_CONFLICT as retryable — the server is intact, so repeat the same request. Deleting a server with no agent and deleting a server of kind GALAXY_APP behave as before.