For AI agents: markdown of this page — /docs-content-en/changelog/2026-08-04.md documentation index — /llms.txt
API changes: August 4, 2026
BC-0804-1: V1 /wake and /start wake galaxy apps via the host
Old format supported until: 22.08.2026
Before
POST /v1/infra/servers/:id/wake and /start for kind=GALAXY_APP returned 422 VM_MISSING (no cloud VM) and suggested redeploy even when the container was only idle-sleeping. Scheduled jobs could not recover via API after the first sleep.
After
For a placed galaxy app both verbs use host-mediated wake (same as the dashboard): wake the shared host if needed, then start the container. Success is HTTP 200. Galaxy ?wait=true does not wait until RUNNING with WAKE_TIMEOUT — after a cold wake the app may still be SLEEPING; poll GET. Host preventWake blocks both /wake and /start (403 SERVER_WAKE_BLOCKED or the 402 paywall code INT_TARIFF_REQUIRED — not freeze markers like TRIAL_EXPIRED). A slot without host/galaxyId → 404 GALAXY_HOST_NOT_FOUND (not 422 VM_MISSING). STANDALONE VM_MISSING / /start override behaviour is unchanged.
BC-0804-2: the declared archive type is now checked against the first bytes
Old format supported until: 03.08.2026
Before
Saving a source version — POST /v1/infra/servers/:id/sources and POST /v1/apps/:id/sources — trusted the Content-Type header. A zip archive sent with Content-Type: application/gzip was accepted, stored as gzip and named with a .tar.gz extension; deploying that version to a server then failed during extraction with an opaque archive-read error. Auto-saving a version after a deploy always recorded the format as gzip, whatever the request body actually contained.
After
The first bytes of the archive are read on intake. A direct contradiction between the declared type and the content — application/gzip declared while the bytes are zip, or the other way round — is rejected with 415 UNSUPPORTED_ARCHIVE_FORMAT; the response body carries error.hint.declared and error.hint.detected. The types application/x-tar and application/octet-stream never trigger this refusal: their signature is not readable within the first eight bytes, so no contradiction can be established. Unrecognised content is accepted as before.
Auto-save after a deploy never refuses: the client declares no archive type there, so the recognised bytes are simply recorded honestly — a zip is stored as a zip and goes to the right extractor on the next deploy.
What integrators should do
Send the Content-Type that matches the archive (application/gzip for tar.gz, application/zip for zip), or application/octet-stream when the type is unknown. Clients already sending the correct header need no change.
NEW-0804-3: field names and descriptions for product sections, requisite presets and bank details
What is new
GET /v1/product-sections/fields, GET /v1/requisite-presets/fields and GET /v1/bank-details/fields used to return only type and readonly — not a single field had a human-readable name, so the reference could not tell you what, say, rqAccNum means. Names are now declared for every field: 7 for product sections, 11 for requisite presets, 34 for bank details. For requisite presets and bank details a description arrives alongside the name.
The response gains label and description keys next to the existing type and readonly — no previously returned field changed.
The dynamic Bitrix24 reference could not supply these names: it only fills in fields absent from the static schema, so for a declared field its own labels were discarded. The aggregate operation on bank details stays disabled.
NEW-0804-4: `limit=0` is no longer ignored silently
What is new
limit=0 is not a page size: the parameter is dropped and the default page size applies. That used to happen without any signal — the response came back 200 with a full page of records, as if the parameter had been honoured. Such a response now carries a warning in meta.warnings:
{
"meta": {
"warnings": [
{
"code": "LIMIT_ZERO_IGNORED",
"field": "limit",
"message": "limit=0 is not a page size and was ignored. Valid range: 1..5000; pass an explicit limit (e.g. 5000) to read the whole collection."
}
]
}
}
It applies to GET /v1/{entity} and POST /v1/{entity}/search for every entity. The applied value itself has not changed — existing calls keep returning the same number of records as before; to read a whole collection pass an explicit limit (5000 maximum).
FIX-0804-5: bank details: `entityTypeId` marked as a field that is never returned
Before
GET /v1/bank-details/fields described entityTypeId as an ordinary numeric field — readable and writable. The fact that Bitrix24 accepts the value on create but never returns it on read was stated only in the field description text. A client that generates its model from the machine-readable reference rather than from the prose put the field in its read type and found nothing where a number was expected.
After
The field now carries notReturned: true — in GET /v1/bank-details/fields, in GET /v1/guide and in the OpenAPI schema (there as an x-notReturned annotation plus a sentence in the description). This release introduced the same flag for serverName on telephony lines.
The field stays writable: POST /v1/bank-details still accepts entityTypeId (always 8 — the owner requisite). The flag speaks only about reading.
Impact on integrators
Nothing to change — the flag is additive. If you generate types from the reference, entityTypeId can be dropped from the read model and kept in the create model.
FIX-0804-6: discover names the real path identifier
Before
GET /v1/guide and the OpenAPI schema advertised the item path as /:id for every entity. For four that was untrue: smart-processes is addressed by the public entityTypeId (1030 and up), telephony-lines by the line number, and bizproc-robots / bizproc-activities by their code — those two have no id of their own at all. A client that read {id} sent the record's own id field and got 404 SMART_PROCESS_NOT_FOUND naming that same value as an entityTypeId — while the published documentation already said :entityTypeId and :code.
After
GET /v1/guide shows /v1/smart-processes/:entityTypeId, /v1/telephony-lines/:number, /v1/bizproc-robots/:code and /v1/bizproc-activities/:code; every other entity keeps /:id. In OpenAPI the parameter name stays id: a path parameter's name has to match the placeholder in the path template, and the address itself did not change — instead the parameter description now names the real identifier. Where an entity declares no id field of its own (the telephony lines and both bizproc registries) the description says exactly that, rather than sending the caller to compare against a field that does not exist. The description of the id field on smart-processes was sharpened too.
Impact on integrators
Nothing to change: routes and response codes are unchanged, only descriptions are. If you were putting the record's internal id into the smart-processes path, the 404 now has an explanation — use entityTypeId; for business-process robots and activities, use code.
FIX-0804-7: telephony lines: `name` declared nullable, `serverName` marked as never returned
Before
GET /v1/telephony-lines/fields declared name as a plain string, although a line created without a name comes back as null — a model generated from the reference broke on the first such value. The serverName field looked like an ordinary readable field even though Bitrix24 neither stores nor ever returns it.
After
name now carries nullable: true — in GET /v1/telephony-lines/fields, in GET /v1/guide and in the OpenAPI schema (there as the type: ["string","null"] form). serverName now carries notReturned: true in the same places, plus an x-notReturned annotation and a sentence in its OpenAPI description. The field deliberately stays in the reference: a write to it is still rejected with 400 READONLY_FIELD, and a client must be able to look the field up and read why.
Impact on integrators
Nothing to change — both flags are additive. If you generate types from the reference, name becomes string | null and serverName can be dropped from the read model.
FIX-0804-8: workgroups: `limit > 50` and row-exact offset now work
Before
GET /v1/workgroups?limit=500 returned the first 50 records no matter how many groups were available, and meta.hasMore did not help read the rest. The cause: this entity's list method is not a .list one but sonet_group.get, and the "this is a list" flag was not declared for it, so neither limit nor auto-pagination ever reached Bitrix24. The offset was floored to a page boundary at the same time: offset=30 returned records starting from the first one, not the thirty-first.
After
limit reaches Bitrix24, and for limit > 50 the platform reads as many pages as needed — the way it has long worked for users, departments and storages. The offset is row-exact: offset=30 starts the window at the 31st record. The same behaviour applies to POST /v1/workgroups/search and to a list sub-call of POST /v1/batch.
Impact on integrators
If you paged workgroups by hand and compensated for the floored offset on your side (for example by dropping the leading records of a page), remove that compensation — otherwise records will be skipped twice. For deep paging a cursor is more reliable: filter {">id": lastId} with sorting by id.
FIX-0804-9: deleting an application now completes its removal from the account
Before
DELETE /v1/apps/:id removed the application from the Bitrix24 account in a single attempt. If the account was unreachable, the rights had been revoked, or the application author had no developer key, the attempt was silently lost: the application was deleted on our side but stayed installed on the account, with its menu entry still in place. Widgets were unbound only for applications published in the catalog, and only on cloud accounts.
After
The outcome of the attempt is stored, and an unfinished removal is retried in the background with a growing delay until the account confirms it. Widgets are unbound for any application, whether or not it was published in the catalog.
Impact on integrators
The endpoint response is unchanged — still 204 right after the deletion on our side.
What changed is the result: the application entry on the account now disappears in the
cases where it used to stay forever.
NEW-0804-10: Gateway timeout on exec now carries a recovery hint
A GATEWAY_TIMEOUT failure of POST /v1/infra/servers/:id/exec now carries a hint object with reason, recovery and recoveryAction fields — the same way EXEC_TIMEOUT and an agent-side EXEC_BUSY already do. The hint states the essential part: no exit status came back, so the outcome of the command is unknown and it may still be running on the server. Re-running it blindly can start a second copy alongside the first, so establish the real state first — read the logs or issue a short read-only command. For work that legitimately outlives the time limit the hint points at a detached background job.
The code and message fields are unchanged — the hint is additive and existing calls keep working. It arrives in both response modes: in the JSON envelope and as an SSE error event.
FIX-0804-11: model-unavailable refusal is now 429 with a wait hint, not 502
Before
When access to the models was temporarily closed after a run of failing calls, POST /v1/chat/completions and POST /v1/embeddings answered 502 with code AI_PROVIDER_UNAVAILABLE, and error.message carried an internal service string instead of an explanation. There was no Retry-After header, so a client had nothing to wait on — the typical library reaction to a 5xx is an immediate retry, which prolonged the outage.
After
The same refusal arrives as 429, error.type: "rate_limit_exceeded", error.code: "ai_provider_cooldown" (the streaming frame uses the same name in upper case, as the rest of this code family does), with a Retry-After header in seconds; in a streaming response the same value arrives as a retryAfter field inside the terminal error frame. The value is the remainder of the wait window, never below one second. error.message no longer contains internal strings or addresses. The refusal is temporary: wait out Retry-After and repeat the same request.
FIX-0804-12: a multipart archive deploy now keeps the source version even when the deploy fails
Before
POST /v1/infra/servers/:id/deploy with a multipart/form-data body saved the archive to source storage only after a successful deploy. When the deploy failed, no version was created at all — nothing to inspect, and a retry meant sending the same bytes again.
After
The archive is placed into source storage before the deploy starts, and the deploy proceeds from a link to that version. The version stays in history either way: deployStatus: "success" on success, "failed" on failure. The data.source block is unchanged — autoSaved, savedVersionId, sha256 and newVersion are filled in as before, and re-sending identical bytes still deduplicates instead of minting a new version.
A new refusal code SOURCE_DEPOT_UNAVAILABLE (502) was added: source storage did not accept the archive, the deploy never started, and the same request can be retried as is. Previously such a failure surfaced as VALIDATION_ERROR (400), i.e. it looked like a bad request.
Impact on integrators
No action required. The version list (GET /v1/infra/servers/:id/sources) of clients that deploy via multipart may now contain versions from failed deploys — those carry deployStatus: "failed".
NEW-0804-13: address fields come with human-readable labels and descriptions
Previously GET /v1/addresses/fields returned the Bitrix24 field name in title for six of the fourteen fields — TYPE_ID, ENTITY_TYPE_ID, ENTITY_ID, COUNTRY_CODE, ANCHOR_TYPE_ID, ANCHOR_ID. Such a label cannot be shown to a user, and the meaning of the codes had to be looked up in the documentation.
Now those six fields carry a label in the account language under title, and the fields that have something to add to the label gained a description key with the purpose of the field and the meaning of its codes: address types (all twelve, 1 through 12 — which of them are available depends on the account country zone) and owner types (1 — lead, 3 — contact, 4 — company, 8 — requisite). The countryCode description no longer promises a format: Bitrix24's own REST documentation marks that field as unused and kept for backward compatibility. Code 1 additionally carries the label the English Bitrix24 interface uses for it — Street address: Bitrix24 itself names that type differently in its Russian and English versions, and without the note the dictionary would not match the label the user sees in the interface.
Labels that Bitrix24 supplies itself are unchanged. Alongside title, the same label now also arrives under label — the key every other entity uses — so labels can be read one way on any entity. The description and label keys are added to the field description and the previous keys stay in place, so no action is needed.
The address type codes were also corrected in the documentation for creating, reading, updating and deleting an address: the values listed there were wrong, and code 13 does not exist at all — the set of types ends at 12, and which of them are available depends on the account country zone.
NEW-0804-14: product fields come with labels, descriptions and a description-format dictionary
GET /v1/products/fields described all twenty-one product fields with nothing but a type and a read-only flag — no label, no description. Such a response gave no way to tell that measure is a measurement unit and vatId is a VAT rate.
Now every one of the twenty-one fields carries a label in the account language, and the fields that have something to add to the label also carry a description: where to get the list of allowed values (GET /v1/currencies, GET /v1/product-sections, GET /v1/catalogs, GET /v1/users), how sorting works and what sets the description format. The descriptionType field gained an enum dictionary with the values text and html.
The keys are added to the field description and the existing type and readonly are unchanged, so no action is needed. Catalog properties PROPERTY_<N> still arrive with the label from the account settings.
NEW-0804-15: all 45 quote fields come with a label and a description
GET /v1/quotes/fields returned a label for thirty of the forty-five fields. The remaining fifteen were exactly the base ones — id, title, dealId, contactId, companyId, amount, currency, assignedById, createdBy, comments, isManualOpportunity, beginDate, closeDate, createdTime, updatedTime — described by nothing but a type and a read-only flag. Not a single field carried a description.
Now every one of the forty-five fields has a label, and each gained a description: what the field is for, where to get the list of allowed values (GET /v1/currencies, GET /v1/users, GET /v1/deals and others), write-time behaviour. The naming mismatches that are easy to get wrong are stated explicitly: the amount is named opportunity in Bitrix24, the currency is currencyId, and the start and close dates are begindate and closedate, all lowercase.
The stageId field deliberately has no value dictionary: the set of stages is configured in the account, so its description points at the GET /v1/statuses?filter[entityId]=QUOTE_STATUS directory — a static dictionary would go stale.
The keys are added to the field description and the existing type and readonly are unchanged, so no action is needed.
NEW-0804-16: catalog product fields come with labels and descriptions
GET /v1/catalog-products/fields described all forty-two catalog product fields with nothing but a type and service flags — no label, no description. Such a response gave no way to tell how purchasingCurrency differs from the price currency, or quantityTrace from canBuyZero.
Now every one of the forty-two fields carries a label in the account language, and thirty-eight of them also carry a description. The descriptions state what previously had to be found out by trial: iblockId is set on create only and does not allow moving a product between catalogs; iblockSection is accepted on write only, while on read the primary section arrives as the scalar iblockSectionId; available and bundle are computed by Bitrix24; recurSchemeLength, recurSchemeType and trialPriceId work only in on-premise Bitrix24 for content sales. Where a value comes from a directory, the endpoint is named — GET /v1/catalogs, GET /v1/catalog-sections, GET /v1/currencies, GET /v1/users.
For previewTextType and detailTextType the value set arrives as a machine-readable enum dictionary (text and html) — the same shape the product description format uses, instead of prose inside the description.
The keys are added to the field description and the existing type, readonly, createOnly and nullable are unchanged, so no action is needed.
FIX-0804-17: requisite preset field schema declares inShortList as boolean
Before
GET /v1/requisite-presets/:presetId/fields/schema described the inShortList field with the char type, while reading rows of the same preset returns true/false and writing accepts true/false. The schema contradicted the data it describes, and a client relying on the declared type prepared to parse a single-character string.
After
In the same response inShortList.type arrives as boolean. The other keys of the field description (isRequired, isReadOnly, title and the rest) are unchanged, and so are the types of the other fields.
Impact on integrators
No action needed: the data was already boolean. A check comparing inShortList.type against the string char will stop matching — compare against boolean instead.
NEW-0804-18: downloading call recordings and timeline attachments
Two endpoints were added for CRM files that Disk file download could not reach.
GET /v1/activities/:activityId/files/:fileId/download returns an activity file, including a call recording. Doing this through the API was previously impossible: an activity file is not a Disk object, its identifier lives in a separate space that overlaps Disk identifiers, and the link in the activity response arrives with an empty authorization parameter — requesting it returns the sign-in page with code 200. The endpoint adds the authorization itself, verifies that the file really belongs to the named activity, and returns a byte stream.
GET /v1/timelines/:commentId/files/:fileRef/download returns a timeline comment attachment. fileRef accepts either identifier: the attachment ID the account interface shows, and the Disk object ID — the object key in the files field of the comment response. The first computes access through the comment itself, so it reaches attachments that Disk file download refuses to serve; the second goes through personal Disk permissions. The comment itself is read first, then the Disk object ID, and the attachment ID only when the comment does not list that reference; you do not have to state which one you pass.
Both endpoints require the crm scope and never return the download address: it contains an authorization code, so only the content leaves. A file whose membership in the named activity or comment is not confirmed gets 404 — including an attachment that hangs on a different kind of record, a task with the same number for instance — without that check the endpoint would allow enumerating the account's files, because Bitrix24 itself answers such a request with a page under code 200 rather than a refusal.
The address check extends to redirects: the endpoint walks them itself, checking every hop, bounds the chain in length and in time, and does not follow a redirect to an internal address — such an answer becomes 502. The same applies to Disk file download, which uses the same wrapper.
A 404 on the attachment download means the reference itself is wrong. A temporary cause — a Bitrix24 request limit, an unavailable account, the repeated-error guard tripping — comes back as itself: 429 or 502/503 with a Retry-After header. The practical difference: retrying a 404 is pointless, whereas a 429/5xx should be retried with a delay. The Retry-After value is computed for the Bitrix24 call that actually hit the limit.
The contract of Disk file download is unchanged: same parameters, same responses. Through the shared wrapper it inherited only the address and redirect check described above.
FIX-0804-19: a bot message without text is refused with a clear error instead of a false success
Before
POST /v1/bots/:botId/messages with the text under an unrecognized key — for example {"dialogId": "…", "text": "hi"} — reached Bitrix24 with no content, and Bitrix24 answered 422 with the code EMPTY_MESSAGE and the text "Message can't be empty". That response gave no way to tell the field name was the problem: the text had been passed.
Update behaved worse. PATCH /v1/bots/:botId/messages/:messageId answered 200 {"result": true} in the same situation while the message text stayed unchanged — a false success after which an integrator considered the edit applied.
After
Both requests check for content before calling Bitrix24 and answer 400 with the code MESSAGE_REQUIRED when there is none. The error text lists the unrecognized body keys and states that the message text belongs in the message field. Neither an empty attach array nor an empty message string counts as content; an attach block without text does, and so does a number (0 is the text "0").
The fields wrapper is how a body is passed through in Bitrix24's own shape, and "a wrapper was supplied" is now understood the same way at every processing step. A value that is not a wrapper (false, 0, an empty array) is not treated as one: {"dialogId": "…", "fields": false} gets the same 400 with the code MESSAGE_REQUIRED, and {"message": "hi", "fields": []} sends the text instead of losing it.
This is the same code and the same wording as the sibling POST /v1/chats/:dialogId/messages: one contract for the same mistake across two related endpoints.
Impact on integrators
A request with the text in the message field works as before. A request that used to get 422 EMPTY_MESSAGE now gets 400 MESSAGE_REQUIRED telling it what to fix. The text field does not become a synonym for message: on read the message content really is called text, but silently accepting both names would split the contract with the chats endpoint.