For AI agents: markdown of this page — /docs-content-en/changelog/2026-08-22.md documentation index — /llms.txt
API changes: August 22, 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.