Pour les agents IA : markdown de cette page — /docs-content-en/errors/auth.md index de la documentation — /llms.txt

Les articles de documentation sont actuellement disponibles en anglais.

Authorization, keys and permissions

A detailed breakdown of the codes the Vibecode API returns when a key is not recognized, lacks the required permissions, or runs in read-only mode.

The summary table of all Vibecode API codes — Error codes.

`MISSING_API_KEY` (401)

The request carries no X-Api-Key header.

JSON
{
  "success": false,
  "error": {
    "code": "MISSING_API_KEY",
    "message": "API key required. Pass via X-Api-Key header."
  }
}

Causes:

  • The X-Api-Key or Authorization header was not passed.
  • The header was passed with an empty value.

Fix:

  • Add the X-Api-Key: vibe_api_... or X-Api-Key: vibe_app_... header.
  • Verify that the environment variable holding the key is set correctly (for CLI tools and SDKs).

`INVALID_API_KEY` (401)

The platform found no such key string: the value passed matches none of the issued keys.

This code does not mean your key stopped working. A key that exists but is rejected returns a different code: revoked or blocked — KEY_INACTIVE, expired — KEY_EXPIRED, with credentials the Bitrix24 account rejects — PORTAL_CREDENTIALS_REJECTED. Those states call for different steps, so start from the code in the response. Code summary — Errors, key states and how to tell them apart — Keys and authorization.

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_API_KEY",
    "message": "Invalid API key"
  }
}

Causes:

  • A typo or extra whitespace in the key.
  • The value was truncated while copying it or moving it into an environment variable.
  • The key is from a different environment — staging instead of production or the other way around.
  • The key was deleted by its owner or an administrator.
  • The prefix is not among the supported ones: vibe_api_, vibe_app_, vibe_live_.

Fix — in this order:

  1. Check the string the client actually sends: extra whitespace and line breaks, a truncated value, a key from another environment. Reissuing does not fix a string mangled in transit.
  2. Find the key on the page for its type: a personal key (vibe_api_) on API Keys; an application auth key (vibe_app_) in the application card under Applications, or under Auth Keys when the application has no card in that section; a management key (vibe_live_) on Management Keys. The API Keys section lists personal keys only, so a missing application or management key there does not mean it was deleted.
  3. Create a new key — only if the key really was deleted. A key that is present on its own page and travels to the platform intact does not return this code, and a new key changes nothing.

`TOKEN_MISSING` (401)

The key carries no Bitrix24 credentials, so there is no way to call Bitrix24. The cause depends on the key type — these are two different scenarios.

A personal key (vibe_api_*) reaches Bitrix24 through a webhook. When the key has no webhook, the response on entity calls (/v1/{entity} and POST /v1/batch) carries a machine-readable reason in error.details. Other routes return the same code without details:

JSON
{
  "success": false,
  "error": {
    "code": "TOKEN_MISSING",
    "message": "This personal API key (vibe_api_*) has no Bitrix24 webhook credentials, ...",
    "details": {
      "reason": "INT_TARIFF_REQUIRED",
      "paywallCode": "INT_TARIFF_REQUIRED"
    }
  }
}

Values of details.reason:

Reason What it means What to do
INT_TARIFF_REQUIRED The Bitrix24 account is on a free plan Upgrade to a commercial plan, then reconnect the key
VIBE_SCOPES_ONLY The key requested no Bitrix24 scope at all — by design it gets no webhook Create a key with the Bitrix24 scopes you need
WEBHOOK_NOT_CONFIGURED Bitrix24 access is fine or undetermined, and the key carries no webhook Reconnect the key. When details.hint is present, re-check via GET /v1/me?refresh=tariff
WEBHOOK_MINT_REFUSED_BY_PORTAL Bitrix24 refused the key owner the right to create incoming webhooks — that right is denied by default and a regular employee cannot grant it to themselves A portal administrator must grant the right to create incoming webhooks; the platform then mints the webhook on its own within 15 minutes, no reconnect needed. More — Creation rights
WEBHOOK_MINT_FAILED The last webhook-mint attempt failed for an unrecognized reason No action needed — the platform retries automatically; check again via GET /v1/me?refresh=tariff

Reconnecting — POST /api/keys/:id/reconnect: issues a webhook for the key without changing the key string (no integration has to be reconfigured) and re-enables linked bots that were disabled automatically. Not applicable to app keys, system-managed keys, or keys with no Bitrix24 scopes — those still need a new key.

Important: not every key can be reconnected: the platform refuses the call with 400 RECONNECT_NOT_APPLICABLE for app keys, keys with a system-managed purpose (including the Cowork key), keys linked to a server, to a live agent or to a live managed bot, and keys with no Bitrix24 scopes. For these keys the error message does not offer reconnecting at all — the cause has to be resolved on the Bitrix24 account, and the platform then mints the webhook on its own.

paywallCode arrives only for the plan-related reason and repeats it. The upgradeUrl field — a link to the upgrade page in the Bitrix24 account — never comes with INT_TARIFF_REQUIRED.

The same condition also blocks app installation and placement binding — there it arrives as a standalone 403 code, covered in Billing and plans.

An app key (vibe_app_*) keeps the Bitrix24 tokens in a per-user session, not on the key. For a call with X-Api-Key alone and no Authorization: Bearer <session token>, TOKEN_MISSING is the correct answer — this branch carries no details, and message describes the missing OAuth step. Full flow — Keys and authorization.

How to check a key's state up front: GET /v1/me for a personal key returns a b24Credentials block (ready, and when ready: false the same reason plus actions), and GET /v1/keys returns a b24Ready flag on every key. The /v1/me response is cached for 30 seconds, so right after fixing the Bitrix24 side, request it as GET /v1/me?refresh=tariff — otherwise the previous state is returned for up to half a minute. GET /v1/keys is not cached.


`PORTAL_CREDENTIALS_REJECTED` (401)

Bitrix24 rejected the credentials the platform uses to call it on behalf of this key. The difference from TOKEN_MISSING: there the key has no credentials at all, here it has them but Bitrix24 no longer accepts them — the webhook was revoked, deleted on the Bitrix24 side, or became invalid along with the owner's rights.

JSON
{
  "success": false,
  "error": {
    "code": "PORTAL_CREDENTIALS_REJECTED",
    "message": "Bitrix24 rejected the credentials this key calls the portal with",
    "hint": "The portal no longer accepts the webhook or token behind this key. Reconnect the key to the portal (or re-issue it) — Retrying will not help until the credentials are restored."
  }
}

Retrying does not help: until the credentials are restored, every call this key makes is refused the same way. The code arrives on any route that reads account data, and in a POST /v1/batch sub-error.

What to do: reconnect the key — POST /api/keys/:id/reconnect — or, when reconnection does not apply to the key, create a new one. The restrictions on reconnecting are the same as for TOKEN_MISSING above.

How to tell it from a permissions refusal: insufficient permissions arrive as SCOPE_DENIED (403) and BITRIX_ACCESS_DENIED (403) — there the credentials were accepted but the operation is not permitted. PORTAL_CREDENTIALS_REJECTED means Bitrix24 did not recognize the credentials themselves, and no permission setting changes that.


`PORTAL_ADDRESS_CHANGED` (409)

The self-hosted portal moved to a new address, while the key's webhook is still issued for the previous one. The platform does not send the secret to an address where Bitrix24 no longer answers, so the call is refused before reaching Bitrix24. The difference from PORTAL_CREDENTIALS_REJECTED: there Bitrix24 itself rejected the credentials, here the request never reaches Bitrix24 — the address the webhook is issued for is no longer the current one.

JSON
{
  "success": false,
  "error": {
    "code": "PORTAL_ADDRESS_CHANGED",
    "message": "Portal address changed: this credential is issued for the portal's previous address. Re-issue the key webhook to continue"
  }
}

Retrying does not help: while the webhook is issued for the previous address, every call this key makes to Bitrix24 is refused the same way.

Changing the scopes of such a key — PATCH /v1/keys/:id with a new scopes list — returns the same code. No request is sent to Bitrix24, and the key's scopes change neither on the Vibecode platform nor in Bitrix24.

What to do: reconnect the key — POST /api/keys/:id/reconnect. The platform re-issues the webhook for the current address, the key string and its scopes stay the same, and integrations need no reconfiguration. Repeat the refused scope change after reconnecting. The restrictions on reconnecting are the same as for TOKEN_MISSING above.


`SCOPE_DENIED` (403)

The key lacks the required scope for the requested operation.

JSON
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'crm' scope",
    "hint": "This request needs the 'crm' scope, which the calling key does not carry. Add 'crm' to this key in the developer cabinet (or through the management API), then repeat the call.",
    "cause": "key_scope_missing",
    "requiredScope": "crm",
    "keyScopes": ["calendar", "vibe:ai", "vibe:search"],
    "fix": { "action": "edit_key_scopes", "via": "cabinet" },
    "userMessage": "The app's API key lacks the “CRM” permission. You can add it in the key settings in the developer cabinet."
  }
}

Causes:

  • CRM entities require the crm scope, tasks require task, the bot platform requires imbot, the AI Router requires vibe:ai, infrastructure requires vibe:infra.
  • Only the full user scope opens the employee directory GET /v1/users and the rest of that section. The reduced user_basic and user_brief scopes do not replace it — the list of scopes and their boundaries is on the Scopes page.
  • The key's scope was narrowed at creation time.

Refusal fields. A refusal for a scope missing on the key itself carries error.cause = key_scope_missing, the missing scope in error.requiredScope, the key's scopes on this request in error.keyScopes, the action in error.fix, an English explanation in error.hint and a text for a person in error.userMessage. Entity routes (including their batch and aggregate calls and include), timeline items and open channels answer this way, and INSUFFICIENT_SCOPE of the /v1/cowork/* routes, INFRA_SCOPE_REQUIRED and SCOPE_NOT_ALLOWED of a batch request arrive with the same fields. The code, status and error.message are unchanged. error.keyScopes includes the automatically granted vibe:ai and vibe:search, so it can be wider than data.scopes of GET /v1/me.

Key and scope fix.action fix.via
Personal key that reaches Bitrix24 through a webhook, Bitrix24 scope edit_key_scopes cabinet
Ordinary key, platform scope vibe:ai, vibe:search, vibe:storage, vibe:feedback, or vibe:infra when servers are turned on for the Bitrix24 account edit_key_scopes cabinet
Key of an OAuth application from the Applications section, Bitrix24 scope reissue_key cabinet
A scope not granted on this Bitrix24 account, vibe:infra while the platform has servers turned off, or the system scope vibe:cowork — only Cowork/Code keys carry it none platform
A key issued through Partner Connect, a Bitrix24 scope or vibe:ai: the supported path is re-consent. The scope set of such a key records the user's consent, so the application adds the scope to its scopes on the application card and walks the user through consent again none —
A key issued through Partner Connect, platform scope vibe:search, vibe:infra, vibe:storage or vibe:feedback: if a platform administrator has not yet granted it to the application, the administrator grants it first; then the application requests it and walks the user through consent again none —
A key the platform issued for a specific purpose (Cowork/Code, server maintenance, collaborator access), a management key, a Bitrix24 AI token, the placement, entity or userfieldtype scope on a key that is not an OAuth application key, a Bitrix24 scope on a key with a legacy OAuth authorization or on a key without a webhook, vibe:infra while the account admin has servers turned off, a key of an OAuth application outside Applications none —

For some keys created in the cabinet, the response may not know whether the key was issued through Partner Connect. Entity routes (including their batch and aggregate calls and include), the batch request and INFRA_SCOPE_REQUIRED determine it and answer by the rows of the table. Timeline items and open channels do not: there such a key gets fix.action = none, and error.hint and error.userMessage say that it could not be determined. For a key the platform issued for a specific purpose, the response also says "not determined": whether editing its scope set would take effect is not known. With fix.action = none, the text of error.userMessage tells three cases apart: the permission cannot be added to this key; that could not be determined; the key was issued through Partner Connect — then the app's developer adds the permission by asking the user for consent again.

error.userMessage can be shown to the person as is: it names the permission as the key settings show it and where to add it, with no links or markup. In a batch request the entries of data.errors with the code SCOPE_NOT_ALLOWED carry cause, requiredScope, fix and hint, while keyScopes and userMessage arrive once — in the 403 response itself, when every call was refused for a scope. When the calls need different scopes, the response has no requiredScope. A call refused with OAUTH_REQUIRED gets none of these fields, and neither does a response that contains one.

Fix:

  • Follow error.fix when the response carries it: see the table above.
  • The full list of scopes and their purpose is on the Keys and authorization page.

A key issued through Partner Connect is a separate case. Its scope set comes from the consent page rather than from the key form, so reissuing adds nothing: the scope has to be requested and confirmed by the user again. On the application side — tick the scope on the application card and walk the user through consent once more; the new key arrives carrying it. An application ticks vibe:ai itself, while the other platform scopes are granted by a platform administrator — the procedure is in Platform scopes. Such a key is recognizable by its name in the key list: Connect: <application name>.


`BITRIX_ACCESS_DENIED` (403)

Bitrix24 refused access to a method or an entity. The refusal comes in two kinds, and each is resolved differently: the Bitrix24 user the call runs as lacks rights — or the key's credential lacks a scope. The kind of refusal arrives in error.cause, the action in error.fix, and an English explanation in error.hint. The Bitrix24 method that refused arrives in error.method, and a name longer than 100 characters is truncated.

JSON
{
  "success": false,
  "error": {
    "code": "BITRIX_ACCESS_DENIED",
    "message": "Access denied",
    "hint": "Bitrix24 reports an access-rights refusal for crm.item.fields, not a scope error. The Bitrix24 user this call runs as lacks access; ask a portal admin to grant it, or call under a user who has it. For this method Bitrix24 requires read permission for items of this CRM entity type (entityTypeId).",
    "cause": "b24_permission",
    "method": "crm.item.fields",
    "fix": { "action": "grant_b24_rights", "via": "portal_admin" }
  }
}

Causes — the cause field. The set is open: read an unknown value as unknown.

cause Meaning What to do
b24_permission The Bitrix24 user the call runs as lacks rights for the method or entity. The key's scopes are not involved Ask an administrator of the Bitrix24 account to grant the rights, or call as a user who has them. Reissuing the key or editing its scopes will not help
b24_scope Bitrix24 rejected the call because the key's credential lacks a scope. The missing scope is in requiredScope when it is known The action from fix — see the table below
key_scope_missing The API key itself lacks the scope the route needs. Arrives in SCOPE_DENIED, INSUFFICIENT_SCOPE, INFRA_SCOPE_REQUIRED and SCOPE_NOT_ALLOWED See SCOPE_DENIED
bot_other_key The bot is bound to another API key. Arrives only in 403 BOT_ACCESS_DENIED See BOT_ACCESS_DENIED
unknown The cause cannot be determined. For example, on chat and bot methods the refusal means either the user's role in the Bitrix24 account or access to a particular chat, and on a call transcript either CRM entity rights or AI call processing being off Read hint: it names both versions. fix.action is none here

Action — the fix field. action says what to do, via says where. The action set is open: read an unknown value as none.

fix.action What to do fix.via
grant_b24_rights Grant rights to the Bitrix24 user portal_admin
edit_key_scopes Add the scope to the key in the API Keys section or through management keys cabinet
reissue_key A key of an application issued in the developer cabinet. Reissue the authorization key in the application card in the Applications section with the extended scope set. After the reissue the Bitrix24 account authorizes the application again. The reissue issues a new API key that replaces this one — switch the integration to it. The other way is to create the application with the required set from the start cabinet
transfer_bot Move the bot to the calling key: call fix.path with the same key and fix.body as the request body same_key
none There is no machine action — read hint —
fix.via Where the action is performed
portal_admin By an administrator of the Bitrix24 account
cabinet In the developer cabinet
management_api Through the /v1/keys routes under a management key
platform On the platform side only
same_key Through a V1 route callable with the same key

"cabinet, portal_admin and platform are a step for a person: pass it to the user and do not retry the call until it is done." same_key and management_api the agent performs itself if it holds the required key. The via set is open too: read an unknown value as a step for a person.

When fix.action is none with cause: b24_scope. There is no action when its advice would be false:

  • the key was issued by the platform for a specific purpose — Cowork/Code, server maintenance, collaborator access — or is bound to a server. It is unknown whether adding a scope to such a key takes effect, and hint says so;
  • the key has a fixed rights set. Such a key is created in the cabinet or issued through Partner Connect, and on this refusal the platform does not tell the two apart. So it is unknown which step adds the scope: editing the key, or the application asking the user for consent again — and hint says so;
  • Bitrix24 does not grant the placement, entity or userfieldtype scope to a personal webhook — such a method needs an application authorization key;
  • the key carries the scope, but the webhook in the Bitrix24 account lags behind. The platform may already have repaired the webhook on its own — retry the call once. If the refusal repeats, the user reconnects the key with the Reconnect command in the API Keys section; it is not available for keys bound to an agent or a managed bot;
  • the scope of the method is unknown — compare the method's scope in the Bitrix24 REST documentation with data.scopes from GET /v1/me;
  • the key belongs to an OAuth application that is listed only in the cabinet's Auth Keys section, not in Applications — for example, one created through the API or on the Auth Keys page. The machine action is not offered for such a key. A person issues a new authorization key from the Auth Keys section (Reissue key) with the required scopes, or creates a new application with the required scope set from the start;
  • the key reaches Bitrix24 through legacy OAuth tokens issued to the key itself. Reissuing an application's authorization key does not apply to it. It needs a new API key or an OAuth application with this scope — a step for a person.

The ACCESS_DENIED_EXTEND and NO_AUTH_FOUND codes arrive not as 403 but as 422 BITRIX_ERROR with b24Code, and stay that way. The response to them carries the same cause, method, fix and hint.

Bitrix24 returns the same refusal when the requested module is disabled in the Bitrix24 account (no CRM, no bot platform, and so on). If the user's rights and the key's scopes are in order, check this.

How scopes are fixed to a key, how to reissue the key, and what to do if the refusal repeats after a reissue — Keys and authorization.


`BOT_ACCESS_DENIED` (403)

The bot is bound to another API key. Bot operations run with the key the bot is bound to, and a call with any other key is refused. error.cause is bot_other_key, and an English explanation arrives in error.hint.

JSON
{
  "success": false,
  "error": {
    "code": "BOT_ACCESS_DENIED",
    "message": "This bot belongs to a different API key",
    "hint": "This bot is bound to another API key on this Bitrix24 account, and bot operations run only with the key the bot is bound to. To move the bot to this key, call POST /v1/bots/42/transfer with this key and error.fix.body as the request body. After the transfer, check the bot's access with POST /v1/bots/42/reauth.",
    "cause": "bot_other_key",
    "fix": {
      "action": "transfer_bot",
      "via": "same_key",
      "path": "POST /v1/bots/42/transfer",
      "body": { "targetApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" }
    }
  }
}

fix.action is transfer_bot when the calling key can run the transfer to itself. The key must be allowed platform writes and be able to own a bot. Its Vibecode user must own the bot's current key or be an administrator of the Bitrix24 account, and the bot must not be managed by an agent or a managed bot. Call fix.path with the same key and fix.body as the request body. fix.body.targetApiKeyId is the identifier of the calling key itself. The response never names the key the bot is bound to. After the transfer, check the binding — Bot access recovery.

fix.action is none — there is no machine action, use the key the bot is bound to — when:

  • the calling key cannot run the transfer itself: it is read-only, and the transfer is a platform write;
  • the calling key cannot own a bot: it is a platform service key, it lacks the imbot scope, it has expired or is not active;
  • only the Vibecode user who owns the bot's current key, or an administrator of the Bitrix24 account, can move the bot to this key, and the caller is neither;
  • the bot is managed by an agent or a managed bot — its key changes through that resource;
  • the check could not be completed for this request.

hint names the specific case.


`WRITE_BLOCKED_READONLY_KEY` (403)

The key is in read-only mode (accessMode: "READONLY"), but the request performs a write. The mode, how to switch it, and the Bitrix24 account policy are described in full in Access mode.

JSON
{
  "success": false,
  "error": {
    "code": "WRITE_BLOCKED_READONLY_KEY",
    "message": "Key is in read-only mode. Switch to read+write in /keys to enable writes.",
    "details": {
      "method": "crm.item.add",
      "keyName": "MCP key",
      "currentMode": "READONLY",
      "switchUrl": "/keys"
    }
  }
}

Important: switchUrl is not a constant. The example above shows a personal key, so the path points to the keys page. The API Keys section lists personal keys only, by design, so every other kind has a different path: for a management key (vibe_live_*) it is /management-keys; for an application auth key (vibe_app_*) it is one of TWO pages — the Applications page /applications when the application has a card there, otherwise the Auth Keys page /apps. Read the value from the response instead of hardcoding one.

details fields:

Field When returned Description
method Only when proxying to Bitrix24 The Bitrix24 method name that would have been called on a successful write (e.g. crm.item.add). Not returned for management keys — the block is based on the request's HTTP method
keyName Always The key name from your Vibecode account. If the key has no name, "unnamed" is returned
currentMode Always The key's effective mode — always "READONLY" for this error
switchUrl Always The path to the page that switches the mode FOR THIS key: "/keys" for a personal key, "/management-keys" for a management key, and either "/applications" or "/apps" for an application auth key, depending on where that application's card lives. Read it from the response instead of hardcoding one

Causes:

  • An API key or authorization key (vibe_api_, vibe_app_) in READONLY mode made a call that proxies to Bitrix24 as a write operation: create, update, delete, an action on an entity.
  • A management key (vibe_live_) in READONLY mode made a request with the POST, PATCH, PUT, or DELETE HTTP method — e.g. an attempt to create a key via POST /v1/keys or delete a feedback record.

Fix:

  • The owner of a personal key (vibe_api_) should open API Keys, select "Read and write" in the Access mode block of the relevant key's card, and save. The mode takes effect on the next request — no reissue needed.
  • The owner of a management key (vibe_live_) should open Management Keys and switch the mode in the key's card. The API Keys section never lists such a key, by design, so the step above does not apply to it.
  • The owner of an application auth key (vibe_app_) should switch the mode in the Access mode block of the application card. The API Keys section never lists such a key, by design, so the step above does not apply to it. The card lives on one of two pages: Applications when the application is registered in that section, otherwise Auth Keys, where the card opens from the "Info" item in the row menu. Do not guess: the address of the right page always arrives in details.switchUrl — follow it instead of a hardcoded path.
  • If the toggle in the card is unavailable, the Bitrix24 account administrator has restricted the mode. Ask the administrator to lift the restriction for this key.
  • When working through an AI agent, the effective mode is returned by GET /v1/me in the data.accessMode field. If writes are needed permanently, issue a separate key in "read and write" mode.

See also