# API changes: July 17, 2026

[← Changelog](/docs/changelog) · [July 2026](/docs/changelog/2026-07)

### FIX-0717-1: deploying to a sleeping galaxy host now answers before client timeouts

**Before**

[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) on a sleeping shared host held the connection open for up to ~6.5 minutes while the host woke. HTTP clients with a typical response-headers timeout (~300 seconds — the Node fetch default) dropped the connection before the platform answered: the deploy surfaced as an opaque `fetch failed` network error with no error code and no recovery steps. A failed wake also put the host back to sleep, so every retry restarted the host boot from zero.

**After**

The platform wakes the host in the background and waits for it to connect for at most ~4 minutes. If the host connects in time, the deploy completes in one call as before. If not, the platform immediately returns a retryable `502 GALAXY_HOST_UNREACHABLE` with a `hint` (re-send the same request in 1-2 minutes, do not delete the slot), and the host keeps booting in the background — a re-sent deploy joins the boot already in progress instead of restarting it. `deployment.galaxyApp._rules` and `deployment.standalone._rules` (GET /v1/me) now recommend an HTTP client timeout of at least 690 seconds — strictly above the platform's 660-second window.

**Impact on integrators**

No request changes are required. If a deploy to a sleeping galaxy host previously ended for you in a network error with no platform response, you will now get either a success or a 502 with retry instructions.

### NEW-0717-2: server user search explains an empty list

The [GET /v1/infra/servers/:id/b24-users](/docs/infra/access/b24-users) endpoint now returns an additional `hint` field when the list is empty because there is no Bitrix24 access — the app is not yet authorized on the account, or the key was revoked. Existing calls are unaffected: the field is additive and absent on a successful response.

### NEW-0717-3: the catalog field references now report nullable fields

The [GET /v1/catalog-prices/fields](/docs/entities/catalog-prices/fields), [GET /v1/catalog-sections/fields](/docs/entities/catalog-sections/fields) and [GET /v1/catalog-products/fields](/docs/entities/catalog-products/fields) references now add `"nullable": true` to fields that can return `null`: for prices these are `quantityFrom`, `quantityTo` and `extraId`, for sections — `iblockSectionId`, `xmlId`, `code` and `description`, for products — `iblockSectionId`, `code`, `weight`, `purchasingPrice`, `purchasingCurrency`, `quantity` and `quantityReserved`. The same flag arrives in `data.entities[].fieldsDetailed` of the [GET /v1/guide](/docs/keys-auth/guide) response, which an OAuth-application key reads without a session, and in the machine-readable [GET /v1/openapi.json](/docs/cli) spec such fields are described with a union type like `["number", "null"]`. A client building a typed model from the reference now gets the correct nullability and no longer breaks on the first `null`. The field set, the types and the response values are unchanged.

### NEW-0717-4: EXEC_BUSY tells you when to retry

The `409 EXEC_BUSY` response (another operation holds the server lock) on [POST /v1/infra/servers/:id/exec](/docs/infra/deploy/exec) and `POST /v1/infra/servers/:id/deploy` now carries a retry hint: the `Retry-After` response header (in seconds) plus two new error-body fields — `retryable: true` and `retryAfter` (in seconds). The `retryAfter` value is a short poll interval (keep retrying with it until the lock clears), not the full time until the lock auto-expires; the full upper bound stays in `error.hint.autoExpiresInSeconds`. The change is additive: the code, `message`, and `hint` are unchanged, so clients matching on `error.code` keep working without changes.

### FIX-0717-5: deploying a galaxy app with an oversized archive returns 413, not "host unreachable"

**Before**

[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) with a `source.content` larger than the upload limit returned `502 GALAXY_HOST_UNREACHABLE` — a message that blamed an unreachable host and advised retrying "once it reconnects". The host was fully reachable, and re-sending the same archive failed identically: the integrator was stuck in an endless loop of useless retries.

**After**

The same case now returns `413 GALAXY_UPLOAD_TOO_LARGE` with a structured `error.hint`. The cause is deterministic (the archive is too large), not transient, so re-sending it unchanged will not help. The `hint` advises shrinking the archive — exclude `node_modules`, `.git` and build artifacts (the platform installs dependencies on the host). A galaxy application accepts the inline `source.content` only (`source.url` is rejected with `400 GALAXY_DEPLOY_CONTENT_ONLY`), so shrinking the archive is the only recovery. A separate adjacent case: a request body exceeding the platform's hard outer limit (500 MB on the base64 body ≈ ~375 MB binary archive) is now rejected at the edge with a coded `413 PAYLOAD_TOO_LARGE` (on the Vibe-REST `/v1/` routes — deploy/upload/create; OpenAI-compatible AI routes return their error in their own envelope) instead of raw HTML — previously the client got an undecodable response.

**Impact on integrators**

No change is required: successful deploys are unaffected. Clients that branched on the error code for this failure now see an honest `413 GALAXY_UPLOAD_TOO_LARGE` instead of the misleading `502 GALAXY_HOST_UNREACHABLE` — the latter remains for a genuine tunnel drop during the build.

### NEW-0717-6: displayName and description on deploy set the Bitrix24 catalog card

[POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) accepted two new optional body fields — `displayName` and `description`. [POST /v1/infra/servers](/docs/infra/servers/create) (server creation) accepted an optional `description`. The values become the app's name and description on the Bitrix24 catalog card. If a deploy omits `displayName` and `description`, the response includes a `warnings: string[]` entry nudging the client to set them; the one-shot galaxy create-and-deploy (a `POST /v1/infra/servers` body carrying `source`) likewise returns `warnings` in its 201 response when the fields are absent. Backward-compatible — requests without the new fields keep working as before.

### FIX-0717-7: galaxy deploy returns 503 on transient database overload

**Before**

On a brief database connection-pool exhaustion during a galaxy app deploy, [POST /v1/infra/servers/:id/deploy](/docs/infra/deploy/deploy) returned a generic `502 GALAXY_APP_DEPLOY_FAILED` — the same code as a real build failure. A client could not tell a transient overload from a terminal error and often treated the response as final.

**After**

A transient database overload is now shed as `503 POOL_EXHAUSTED` with a `Retry-After` header (seconds to wait before retrying). A genuine build failure stays `502 GALAXY_APP_DEPLOY_FAILED`.

**Integrator impact**

No action required. If your client retries, a `503` now carries an explicit backoff signal via `Retry-After` instead of an opaque `502`.

### FIX-0717-8: filtering and sorting of the task comment list work on both cards

**Before**

A [GET /v1/tasks/:taskId/comments](/docs/entities/task-comments/list) request with a `filter` parameter or with a sort other than `ID` on a Bitrix24 account with the new task card returned `200` and an empty list, even when the task did have comments. No error arrived, so there was no way to tell "nothing matched the filter" from "the filter did not work".

**After**

Such a request returns the matching comments. Filtering and sorting work by the fields `ID`, `AUTHOR_ID` and `POST_DATE`, and in a filter the field name may carry a `!`, `>`, `>=`, `<` or `<=` prefix. Filtering by `AUTHOR_NAME` and sorting by `AUTHOR_NAME` or `AUTHOR_EMAIL` on the new card answer with `400` and the code `UNSUPPORTED_FILTER_FIELD` or `UNSUPPORTED_SORT_FIELD` and point at `AUTHOR_ID`, on the old card those fields are still accepted. An `offset` parameter is added — it is honoured on the new card for a request with `filter` or a sort other than `ID`, and ignored on the other read paths. The `INVALID_FILTER` code now also arrives when `filter` is a scalar or an empty array instead of an object (`0`, `false`, `""`, `[]`), the value of the field `ID` or `AUTHOR_ID` is not a number, the value of `POST_DATE` does not parse as a date, or a field value is an object or an array instead of a scalar. A `truncated` field with the value `true` is added to `meta` — the scan window of the history was exhausted, and some comments stayed beyond its edge.

**Impact on integrators**

Nothing to change: a request that used to hand back an empty list starts handing back data. Mind three edges. First — filtering by `AUTHOR_NAME` and sorting by `AUTHOR_NAME` or `AUTHOR_EMAIL` on a Bitrix24 account with the new card now answer with `400` instead of an empty `200`, move such a request to `AUTHOR_ID`, an employee identifier by name comes from `GET /v1/users`. Second — `meta.total` for a filtered request against the new card counts the matching comments within the scanned window rather than across the whole task history, and with `meta.truncated: true` it is an incomplete number. Third — the value of `POST_DATE` on the new card is compared against `createdAt` in UTC, so a result on a day boundary may differ from the selection on the old card. On Bitrix24 accounts with the old card the behaviour is unchanged.
