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

API changes: August 22, 2026

← Changelog · August 2026

NEW-0822-1: promo code on an occupied seat: the preview returns branches and redemption executes them

Before

POST /v1/cowork/coupon/preview answered only what the code grants, and on an occupied seat redemption refused with "the seat is already paid" — with nothing the person could do about it.

After

The preview returns a decision field — what this code does to the seat and what may be offered: apply, extend (same tier, the paid window moves), choose (branches to pick from, where "apply now" carries losesDays — the whole days of paid term that burn) or refuse with a refusal code. The chosen branch goes to POST /v1/cowork/coupon/redeem in the new optional field action (apply | extend | force | resume-and-apply); omitting it keeps the previous behaviour.

The action is re-checked at redemption time: if the seat changed meanwhile, the answer is 409 COUPON_ACTION_NOT_AVAILABLE and the code is NOT spent. The correct reaction is to re-read the preview and offer the branches it returns now. An unknown action value answers 400 INVALID_ACTION — such a body previously answered 400 INVALID_CODE, pointing at the code field, which was not the problem.

BC-0822-2: the create and rotate responses now match the documented key shape

Old format supported until: not provided

Before

On some accounts POST /v1/keys and POST /v1/keys/:id/rotate returned the whole key row with only the secret fields removed. Alongside the documented shape, the response carried internal platform fields that appear neither in the key-shape reference nor in GET /v1/keys and GET /v1/keys/:id: preMigrationScopes, ownerActive, deletedAt, isOAuthApp, appId, purpose, scopesAuthoritative, linkedServerId, userAgentAutoModel, webhookScopesRepairedAt, tokenExpiresAt.

After

Both methods return exactly the documented key shape — the same field set as GET /v1/keys/:id, plus the one-time rawKey. The internal fields listed above are gone from the response; none of them was documented or part of the contract.

If your integration read any of them, switch the source: key state is status, access mode is accessMode, and the issuing channel is issuedVia. Documented fields, expiry and error codes are unchanged.

BC-0822-3: key rotation now requires the same Bitrix24 plan as creation

Old format supported until: not provided

Before

On an account whose Bitrix24 plan does not grant access to the platform, POST /v1/keys/:id/rotate issued a new key, while POST /v1/keys on the same account answered with a plan-required refusal. Rotation stayed a way around that requirement.

After

Both methods answer the same way. On an account whose plan does not grant access, rotation returns 403 with the same code as creation, INT_TARIFF_REQUIRED.

Only accounts without a qualifying plan are affected. Self-hosted accounts, accounts on a qualifying plan and already-issued keys are unchanged: nothing is revoked or stopped, and rotation resumes as soon as the account is on a qualifying plan.

NEW-0822-4: a key now reports the channel it was issued through, and a refusal reports its exact cause

Before

POST /v1/keys and POST /v1/keys/:id/rotate did not report which channel issued the key on the account. On accounts where only the platform module can create an inbound webhook, both methods answered with an issuance error even though issuance on the account itself worked.

After

The key shape carries an optional issuedVia field — the issuing channel; it arrives in the responses of POST /v1/keys, POST /v1/keys/:id/rotate, GET /v1/keys, GET /v1/keys/:id and PATCH /v1/keys/:id. A refusal body gained an optional error.reason field with the exact cause, while error.code on existing refusals is unchanged. Accounts where the platform module issues keys are now served by both methods.

The create and rotate responses are now identical regardless of the issuing channel — some channels used to return a narrower field set. The message field stays human-readable and may change: branch on error.code, not on its text.

FIX-0822-5: a rotation refused over scopes now reports the same code on every account

Before

POST /v1/keys/:id/rotate on a key left with only application-context scopes — placement, entity, userfieldtype — answered differently depending on the channel the account issues keys through. Where the platform module issues the key, 400 PERSONAL_KEY_WEBHOOK_SCOPES_INVALID arrived, while other accounts got a generic 502 BITRIX_UNAVAILABLE after a failed issuance attempt.

After

The scope set is checked before the account is contacted, so the refusal is the same everywhere — 400 PERSONAL_KEY_WEBHOOK_SCOPES_INVALID, the code creation and update already return. Nothing changes on the client side: the refusal is more precise and arrives earlier. To let rotation through, add a data scope to the previous key via PATCH /v1/keys/:id.

NEW-0822-6: platform requests to Bitrix24 now carry a signed origin proof

Before

Bitrix24 refused the call on plan grounds or for a missing Market subscription, and a platform request looked to it exactly like any other integration.

After

Every Bitrix24 request carries an X-Vibecode-Origin header — a short-lived signed token. The token names the origin: cowork for a paid Cowork/Code seat key, app for every other user key, vibecode for the platform's own service calls. An account with the Vibecode connector module installed admits Cowork/Code requests on that proof; other values grant nothing. Accounts without the module ignore the header; existing integrations are unaffected.

FIX-0822-7: Reliable source downloads for dedicated VM deploys

Before: a dedicated virtual machine fetched source.url through its own network path. One orchestrator retry did not tolerate intermittent egress or NAT failures, and callers received raw agent networking text.

After: for servers enrolled in the staged rollout, the platform downloads the archive and streams it to the VM through the tunnel, with up to four attempts and backoff inside a shared five-minute budget. The compatible VM-download fallback and public /upload receive bounded retries, a safe outbound policy, and stable messages under the same rollout; before enrollment, the existing contract is preserved. DEPLOY_FAILED is unchanged; in the new mode a failed download step adds causeCode, retryable, and attempts. See the deploy documentation.

Impact: request payloads do not change. Automation can branch on the new fields instead of parsing message text; archives up to 500 MB are streamed and do not consume an inline-memory slot. For public /upload, the long phase in the new URL mode completes under an HTTP 200 keepalive response, so determine success or failure from JSON success and error.code; pre-dispatch checks and pre-enrollment behavior retain their previous HTTP statuses.

BC-0822-8: rotating and bringing back platform-issued keys is closed

Old format supported until: not provided

Before

POST /v1/keys/:id/rotate rotated any key of its owner, and PATCH /v1/keys/:id moved any key back to ACTIVE and pushed its expiry back — including the keys the platform issues on its own separate endpoints: a Cowork/Code desktop key, an agent key and a project deploy key. In the GET /v1/keys listing such a key is barely distinguishable from a personal one, so a "rotate or switch back on all my keys" script walked over it along with the rest: rotation answered 201 with a fresh rawKey, switching back on answered 200 — and the key value never changed there, so the previous one started working again.

After

Both operations on such a key answer 403: rotation with the code SYSTEM_KEY_ROTATE_FORBIDDEN, moving back to ACTIVE and extending the expiry with the code SYSTEM_KEY_REACTIVATE_FORBIDDEN. The response text says where a key of that class is issued again. The key is left as it was in both cases. Both operations bypassed the checks that guard the issuance of each such key: for keys carrying vibe:cowork — Cowork/Code access, the account "third-party clients" policy and the subscription state; for a project deploy key — three platform switches, the Cowork/Code key requirement and an active subscription. Rotation also handed out a value with no expiry at all: on a project deploy key that removed the seven-day lifetime, the only thing that limits a leaked key. Revoking a key and shortening its expiry are still allowed: those stop a key rather than hand one out. The former behaviour is gone at once, with no transition period.

What integrators should do

Exclude the keys the platform issues from bulk rotation and bulk switch-on: a Cowork/Code desktop key, an agent key and a project deploy key. The first two are recognisable in the GET /v1/keys response by the vibe:cowork scope; a project deploy key has no separate marker in the listing, so treat a 403 with these codes as the final answer for that key and do not retry. A desktop key is issued again by connecting the Cowork/Code desktop app, an agent key — by re-issuing the agent key in the Vibecode dashboard, a project deploy key — by calling POST /v1/cowork/deploy-key again. Other keys rotate and switch back on as before.

NEW-0822-9: POST /v1/cowork/deploy-key is closed to external-agent keys

Before

The endpoint checked the vibe:cowork scope only.

After

On POST /v1/cowork/deploy-key a key issued for a third-party agent gets 403 COWORK_HARNESS_KEY_FORBIDDEN. Such a key lives inside someone else's application, while minting a project deploy key revokes the previous one and moves the owner's servers and applications onto the new key. Desktop and agent keys are unaffected.

NEW-0822-10: Reactivating a subscription key checks the issuance gates

Before

A subscription-billed key went back to active through an ordinary status field change, and its expiry was cleared with null. Only the permanent block was checked, so a revocation by the Bitrix24 account administrator was undone in a single request — and the secret itself never changed.

After

PATCH /v1/keys/:id answers 403 with the matching gate code when the request moves a subscription key to ACTIVE, or pushes back or clears expiresAt, while Cowork access, the Bitrix24 "third-party clients" policy or the subscription state is closed. Shortening the expiry, revoking and editing the other fields work as before. Ordinary keys are unaffected.

NEW-0822-11: Rotating a subscription key checks the issuance gates

Before

Rotation carried the key's scopes and purpose over verbatim, asking nothing.

After

POST /v1/keys/:id/rotate answers 403 with the matching gate code when rotating a subscription-billed key while Cowork access, the account's "third-party clients" policy or the subscription state is closed. Ordinary keys rotate as before.

NEW-0822-12: POST /v1/keys rejects subscription billing

Before

The billing field did not exist in the request body; the unknown key was silently dropped by the schema.

After

On POST /v1/keys the value billing: "subscription" is rejected with BILLING_MODE_NOT_SUPPORTED. Subscription-billed keys are issued from the Vibecode dashboard only — that is where the access, Bitrix24 account policy and subscription-state checks live, and the public route has none of them. billing: "wallet" and requests without the field behave exactly as before.

FIX-0822-13: The inactive-subscription refusal now points at the subscription page

Before

The 402 refusal carrying code cowork_subscription_inactive advised activating the subscription by calling POST /api/cowork/subscription. That route works only inside a signed-in web session and is unavailable to a client authenticating with an API key. A third-party agent client shows the message field verbatim, so the advice looked actionable while there was nothing to act on.

After

The same refusal on POST /v1/chat/completions names the state and the place where it changes: the subscription is resumed in the Cowork/Code section of your Vibecode account, and the key stays the same. The code, the status and the other body fields are unchanged.