[{"data":1,"prerenderedAt":7},["ShallowReactive",2],{"docs-changelog\u002F2026-08-31":3,"docs-tabs-changelog\u002F2026-08-31":6},{"content":4,"lastmod":5},"# API changes: August 31, 2026\n\n[← Changelog](\u002Fdocs\u002Fchangelog) · [August 2026](\u002Fdocs\u002Fchangelog\u002F2026-08)\n\n### FIX-0831-1: a server whose agent never came up is no longer reported as running\n\n**Before**\n\nWhen the on-boot agent install aborted, the VM still reached `running` and the server stayed\nthere. The server card and the server list returned `status: \"running\"` with `provisionError`\nand `provisionErrorCode` both empty — nothing in those responses told a working server from a\nbroken one, and billing kept accruing.\n\n```json\n{ \"status\": \"running\", \"blackholeStatus\": \"NONE\", \"provisionError\": null, \"provisionErrorCode\": null }\n```\n\n**After**\n\nSuch a server moves to `error` with an explanation and a new\n`provisionErrorCode: \"AGENT_NEVER_CONNECTED\"`, and its billing is closed out.\n\n```json\n{ \"status\": \"error\", \"blackholeStatus\": \"NONE\", \"provisionError\": \"The server booted, but its agent never connected — …\", \"provisionErrorCode\": \"AGENT_NEVER_CONNECTED\" }\n```\n\n**Impact on integrators**\n\nNothing to change: `error` is an existing status and no field was added. Worth knowing:\n\n- A readiness wait now terminates — `running` with `blackholeStatus: \"NONE\"` no longer lasts\n  forever. If you poll for `running` + `CONNECTED`, add an exit on `error`.\n- Recovery is [`POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Frepair`](\u002Fdocs\u002Finfra\u002Flifecycle\u002Frepair), which\n  reinstalls the agent over SSH. Recreate the server only if repair does not help.\n- `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fstart` on such a server answers `422` with the code\n  `AGENT_NEVER_CONNECTED`. The status did not change: this machine already got a `422` from `\u002Fstart`\n  (`SERVER_WRONG_STATE`, since it counted as `running`) — the code changes, not the status. Starting it fixes nothing and erases the explanation, which is why it\n  is refused. A client that restarts failed servers on a schedule must read the code and call\n  repair instead.\n- Three lifecycle operations on such a server turn from a success into a refusal, because they\n  require `running`: `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fstop` and `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Freboot`\n  answer `422` with the code `SERVER_WRONG_STATE`, and `POST \u002Fv1\u002Finfra\u002Fservers\u002F:id\u002Fsleep-now`\n  answers `400` with `NOT_RUNNING`. Stopping such a machine is not needed either: billing is\n  closed out with the verdict, so a scheduled stop saves nothing on it. The working actions are\n  [`repair`](\u002Fdocs\u002Finfra\u002Flifecycle\u002Frepair) and `DELETE \u002Fv1\u002Finfra\u002Fservers\u002F:id` — the same pair the\n  response lists in `availableActions`.\n- The verdict applies to newly created servers and never touches ones already running. The\n  platform checks with the gateway first, so a live tunnel whose notification was lost is\n  healed rather than failed. If the agent connects later, the server returns to `running` on\n  its own and both fields are cleared.\n\n### FIX-0831-2: key issuance on a free plan now names the cause instead of \"retry in a minute\"\n\n**Before**\n\nWhen Bitrix24 refused REST because the account's Bitrix24 plan does not permit it, key issuance and app installation answered `502 CONNECTOR_REST_UNAVAILABLE` with the text \"Bitrix24 did not issue the key. Retry in a minute\". Retrying never helped: the plan gate does not clear on its own, and the response never said what did block the call.\n\n**After**\n\nThe same situation answers `402` with a dedicated paywall code. The `userMessage` field states that a paid Bitrix24 plan is what unlocks the action. Successful responses are unchanged and still return HTTP 200, and every other refusal reason still answers `502 CONNECTOR_REST_UNAVAILABLE`.\n\n### FIX-0831-3: search and research through the Linkup provider\n\n**Before**\n\nEvery `POST \u002Fv1\u002Fsearch` or `POST \u002Fv1\u002Fresearch` call with `provider: \"linkup\"` was rejected by the provider: the platform did not send the required `outputType` field. For the same reason a Linkup key could not be connected — adding a BYOK key returned `INVALID_CREDENTIAL` with the text `HTTP 400` even for a working key.\n\n**After**\n\nLinkup calls go through, and connecting a BYOK key reflects the real state of that key: a working key is stored, a non-working one is rejected.\n\nIn `\u002Fv1\u002Fsearch` the `answer` field is filled when `include_answer: true` and is `null` when `include_answer: false`; in that case the page text arrives in `results[].content`. The `results[].published_date` field is always `null` for Linkup — the provider returns no publication date, and the capability matrix in `GET \u002Fv1\u002Fsearch\u002Fproviders` now reports that honestly.\n\n### FIX-0831-6: Batch create of telephony lines returns the addressable number in results[].id\n\n**Before**\n\n`POST \u002Fv1\u002Ftelephony-lines\u002Fbatch` with `action: \"create\"` answered `200`, but `results[].id` carried Bitrix24's internal numeric row id. It could not be used in `PATCH` or `DELETE \u002Fv1\u002Ftelephony-lines\u002F:number` — the line is looked up by number, so the request answered `422`. The single `POST \u002Fv1\u002Ftelephony-lines` already returned the correct number, so the two doors into the same create disagreed.\n\n**After**\n\n`results[].id` is the same number passed in that item's `number` field, and the same value the single [POST \u002Fv1\u002Ftelephony-lines](\u002Fdocs\u002Ftelephony\u002Flines\u002Fcreate) returns. It comes back verbatim, including numbers with `+` and other characters. The response is still `200` and no other field changed.\n\n### FIX-0831-7: signing back into Cowork on a fee-free seat no longer fails\n\n**Before**\n\nCancelling a fee-free Cowork subscription made every later desktop sign-in fail with\n`403 COWORK_SUB_CANCELLED`: the cancelled seat was never revived, and a key is only issued\nfor an active one. There was no way out from inside the app — this path has no browser\nroute back to a fee-free seat — so the person stayed locked out for good.\n\n**After**\n\nA zero-price seat is revived at sign-in and the key is issued. A paid seat still answers\n`403 COWORK_SUB_CANCELLED` \u002F `COWORK_SUB_PAUSED`: resuming it is a payment, and that stays\na deliberate action in the dashboard.\n\n### FIX-0831-8: `TOKEN_MISSING` for a personal key now names the webhook mint failure\n\n**Before**\n\nWhen a personal key (`vibe_api_*`) had no Bitrix24 webhook because Bitrix24 had refused\nthe key owner the right to create incoming webhooks, or because the last mint attempt had\nfailed, the `401 TOKEN_MISSING` response still reported a generic reason (for example\n`WEBHOOK_NOT_CONFIGURED`) and pointed at `GET \u002Fv1\u002Fme`, without explaining that no webhook\nwas coming or who needed to act.\n\n**After**\n\nIn these two scenarios `error.details.reason` now returns `WEBHOOK_MINT_REFUSED_BY_PORTAL`\n(a Bitrix24 account administrator must act) or `WEBHOOK_MINT_FAILED` (the platform retries on its\nown), and `error.message` names the cause and the addressee explicitly. For\n`WEBHOOK_MINT_REFUSED_BY_PORTAL` the reconnect advice is no\nlonger included — the platform mints the webhook automatically once a Bitrix24 account administrator\nopens the right to create incoming webhooks, and retrying reconnect will not help. The\nresponse code, HTTP status and `error` shape are unchanged.\n\n**Impact on integrators**\n\nHandle `WEBHOOK_MINT_REFUSED_BY_PORTAL` and `WEBHOOK_MINT_FAILED` as distinct\n`details.reason` values alongside the already-documented ones — do not recreate the key or\nloop on `reconnect` for these reasons; wait for the Bitrix24 account administrator or the platform's\nautomatic retry.\n\nA separate note on the message text. `error.message` now branches on the reason and on\nwhether reconnect is available for the key — and this affects more than the two new\nreasons. A key with no Bitrix24 scopes (`VIBE_SCOPES_ONLY`) gets its own wording, and keys\nthe platform would refuse reconnect for (cowork keys, app keys, keys bound to a server or\nto a live agent) get advice to create a new key instead of advice to reconnect. The\n`details.reason` values in those scenarios are unchanged. If your code matches on\n`error.message` as a string, switch to `details.reason`: the message text is not a\ncontract and does change.\n\n### FIX-0831-9: vibe top-up is open to self-hosted accounts on the international installation\n\n**Before**\n\nA self-hosted account on the international installation always got the\n`BOX_TOPUP_NOT_AVAILABLE` refusal. The subscription preview\n`GET \u002Fv1\u002Fcowork\u002Fsubscription\u002Fpreview` returned `topUpAvailable: false` for such\nan account, and the package catalogue came back empty.\n\n**After**\n\nA self-hosted account on the international installation tops up just like a\ncloud one — it gets the package catalogue, a payment link and\n`topUpAvailable: true` in the subscription preview. The\n`BOX_TOPUP_NOT_AVAILABLE` refusal remains only where top-up is closed to\nself-hosted accounts in the account's region. The response format is unchanged\nand the successful response remains HTTP 200.\n",null,{},1794739477254]