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

Error codes

Reference of Vibe API error codes: the unified response format, the code list, common causes, and how to fix them. Applies to all /v1/... endpoints.

Error response format

Every error response is returned in a unified shape. error is an object.

JSON
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Item not found"
  }
}
Field Type Req. Description
success boolean yes Always false on error
error.code string yes Machine-readable error code. Use it to distinguish error types in client code
error.message string yes Error description for the developer. The language is not known in advance and depends on the source: the platform's technical messages arrive in English, messages from Bitrix24 arrive in the Bitrix24 account's language, and cloud provider failure messages are localized to the user's language. Do not parse the text or rely on its language — branch on error.code
error.hint string | object no Developer hint: what to try next, which limits to watch. A text string, or — on infrastructure creation endpoints POST /v1/infra/servers — an object with reason, recovery, and example fields, where example holds a ready-to-send request body to fix the call
error.userMessage string no Message for the end user in the user's interface language. Appears in billing, infrastructure, and plan errors
error.warning string no Appears on repeated identical errors on the same key — a likely sign of a bug in the client code. The counter is heuristic, so the warning does not guarantee a bug
error.retryAfter number no Seconds until the next attempt. Appears in 429 (rate-limit, and also the portal queue — QUEUE_OVERFLOW/QUEUE_TIMEOUT)

Example response with extra fields (429 RATE_LIMITED):

JSON
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "QUERY_LIMIT_EXCEEDED",
    "hint": "Wait 1-2 seconds and retry. Use POST /v1/batch to combine up to 50 calls in 1 request.",
    "retryAfter": 2
  }
}

The Retry-After HTTP header mirrors the error.retryAfter value for compatibility with the HTTP standard.

Code summary table

The table covers the core codes that appear on any Vibe API endpoint. Domain codes (BOT_NOT_FOUND, SERVER_NOT_RUNNING, AGENT_LIMIT_REACHED, and similar) are documented on the pages of their respective sections.

Authorization and keys

Code HTTP When it occurs
MISSING_API_KEY 401 Request without the X-Api-Key header
INVALID_API_KEY 401 Key not found in the system or its format is unrecognized
INVALID_APP_KEY 401 A vibe_app_* key was passed without an accompanying Authorization: Bearer ...
WRONG_AUTH_SCHEME 401 An API key was passed in the Authorization: Bearer header. An OAuth app key (vibe_app_*) goes in X-Api-Key, and Authorization: Bearer carries the session token (vibe_session_*). For a client that can only send Bearer, use a personal key (vibe_api_*) — it is accepted in Authorization: Bearer
TOKEN_EXPIRED 401 The OAuth token has expired
TOKEN_REFRESH_FAILED 401 Failed to refresh the OAuth token on the Bitrix24 side
WRONG_KEY_TYPE 401 The key type does not match the endpoint: e.g. a management key on an entity route
SESSION_REQUIRED 401 A placement operation was called without the Authorization: Bearer header carrying a session token, on an account that requires it

Application user authorization (OAuth)

Code HTTP When it occurs
INVALID_REDIRECT_URI 400 redirect_uri is not registered for the application, on entry to GET /v1/oauth/authorize
INVALID_STATE 400 state was not found or expired after 20 minutes when receiving the Bitrix24 response. error.details.reason carries NOT_FOUND or EXPIRED
INVALID_CODE 400 The authorization code was not found or belongs to another application
CODE_EXPIRED 400 The authorization code has expired — 5 minutes
CODE_ALREADY_USED 400 The authorization code has already been exchanged for a session token
REDIRECT_URI_MISMATCH 400 The redirect_uri at code exchange does not match the one passed on entry
DOMAIN_MISMATCH 400 domain in POST /v1/oauth/placement-session does not match the application's portal
USER_AUTH_REQUIRED 401 The Bitrix24 user token did not confirm authorization on the portal
MISSING_TOKEN 400 POST /v1/oauth/revoke without an Authorization: Bearer header carrying a session token

A rejection on the return may arrive not as a code but as an ?error= parameter appended to the redirect_uritoken_exchange_failed, invalid_domain or profile_fetch_failed.

Full description of the flow — Application user authorization.

Permissions and scopes

Code HTTP When it occurs
SCOPE_DENIED 403 The key lacks the required scope (e.g. crm for deals, imbot for bots)
WRITE_BLOCKED_READONLY_KEY 403 The key is in read-only mode, but the call performs a write
INFRA_FORBIDDEN_FOR_COWORK_KEY 403 A Co-work subscription key (vibe:cowork) — data-plane only: provision / deploy / exec / upload / server lifecycle and catalog publishing are forbidden. Use a project key with deploy permissions. The response lists your other active deploy-capable keys in error.details.deployableKeys (name / prefix / suffix, up to 5)
INFRA_SCOPE_REQUIRED 403 The key lacks the vibe:infra scope — infrastructure management is unavailable. Add the scope or use a key with infrastructure permissions
KEY_POLICY_READONLY_REQUIRED 403 The portal policy allows regular users to create read-only keys only — issuing a write-enabled key was rejected
MANAGEMENT_KEY_READ_ONLY 403 A management key without write permissions attempts a POST/PATCH/DELETE
MANAGEMENT_KEY_NO_ENTITY_ACCESS 403 A management key accesses an entity endpoint — an APP key with the required scope is needed
BITRIX_ACCESS_DENIED 403 Bitrix24 returned ACCESS_DENIED: the user lacks permission for the operation or entity
OAUTH_REQUIRED 403 The endpoint requires a user context — a vibe_app_* key + Bearer token is needed
WAITLIST_PENDING 403 The account is awaiting waitlist activation
OAUTH_SCOPE_CHANGE_REQUIRES_REISSUE 403 An attempt to add a Bitrix24 scope to an OAuth-app key (vibe_app_*) via PATCH /v1/keys/:id, or to an app via PATCH /v1/apps/:id. An OAuth app's scopes are fixed at issue time — removals work, but for a new scope create a new authorization key with the scopes you need
OAUTH_APP_REQUIRED 400 A placement operation was called with a personal vibe_api_* key. Binding, unbinding, and listing bound placements are available only to the application authorization key vibe_app_*
PLACEMENT_SCOPE_MISSING 403 The key lacks the placement scope — binding and unbinding placements are unavailable
SESSION_REQUIRES_ADMIN 403 Binding a placement on a self-hosted account is performed under an account without account-administrator rights
APP_NOT_REGISTERED 400 The application has no Bitrix24 application identifier — a placement cannot be bound or unbound
BOX_NO_DEVELOPER_KEY 400 The application author has no developer key configured — placement operations on a self-hosted account are unavailable
OAUTH_APP_KEY_CANNOT_RELINK 403 POST /v1/apps/:id/relink-oauth was called with the OAuth app's own key (vibe_app_*). Such a key cannot relink the app's credentials — use a personal key (vibe_api_*) or the Vibecode dashboard

Request validation

Code HTTP When it occurs
VALIDATION_ERROR 400 The body or query failed schema validation. message contains per-field details
INVALID_JSON_BODY 400 The request body cannot be parsed as JSON. It is returned before schema validation, so message carries no field details. This code comes from the entity routes /v1/<entity>, as well as /v1/apps, /v1/bots, /v1/keys, /v1/note, every /v1/infra/servers/:id server operation — deploy, exec, upload, icon, logs, lock, unstick — and /v1/infra/runtimes
FST_ERR_CTP_INVALID_JSON_BODY 400 The same case — the body cannot be parsed as JSON — on the other routes: POST /v1/search, POST /v1/research, POST /v1/batch and the rest
fst_err_ctp_invalid_json_body 400 The same case on the OpenAI-compatible AI Router routes — /v1/ai/, /v1/chat/, /v1/models, /v1/audio/. There the codes are lowercased and the response uses the OpenAI envelope: error.type, error.code, with no success field
INVALID_PARAMS 400 Bitrix24 returned INVALID_PARAMS or the route handler found an invalid parameter value
INVALID_REQUEST 400 The request structure does not match the required one (e.g. calls in /v1/batch is an empty array or contains more than 50 elements)
MISSING_PARAMS 400 A required parameter explicitly listed in the endpoint schema was not passed
MISSING_REQUIRED_FILTER 400 A required filter for list endpoints that need context (timelines, task-comments, and similar) was not passed
MISSING_REQUIRED_PARAMS 400 Required context parameters for a nested search or list were not passed: files requires folderId, folders requires parentId, calendar-events requires type and ownerId. message lists the missing fields
MISSING_REQUIRED_FIELDS 400 A body field declared required for creating the entity was not passed. message names the missing field
EMPTY_CREATE_BODY 400 The create request body is empty — no field was passed
EMPTY_UPDATE_BODY 400 The update request body is empty — no field was passed
INVALID_FILTER_FIELD 400 Field name starts with the Bitrix24-native prefix @ (IN) or !@ (NOT IN) — use the $in / $nin operators instead
UNKNOWN_SORT_FIELD 400 Sort on a non-existent field (for entities whose sort validator is active)
BATCH_LIMIT_EXCEEDED 400 The request contains more than 50 elements in a bulk operation (vipchats, task-comments, and similar)
MESSAGE_REQUIRED 400 POST /v1/chats/{dialogId}/messages with no text: the message field is empty and there is no attach block. Often the text was passed under an unknown field name, for example text. The response lists the unrecognized fields
INVALID_EVENT 400 The portal event subscription code does not match the ^[A-Z][A-Z0-9_]+$ format. See portal event subscriptions
INVALID_APP_PATH 400 The appPath delivery path does not start with / or contains control characters. See portal event subscriptions
PLATFORM_HANDLER_UNRESOLVABLE 400 The handler address points at the technical address of the app server, and the platform handler could not be resolved. The placement was not registered. See Bind a placement

File uploads

Code HTTP When it occurs
STORAGE_FORBIDDEN_CONTENT_TYPE 415 For PUBLIC objects the types text/html, application/javascript, application/x-javascript, image/svg+xml are forbidden — they are prone to cross-site scripting. Upload such a file as PRIVATE

Portal event subscription preconditions

Code HTTP When it occurs
NOT_OAUTH_APP 400 The server is not bound to an OAuth app with an application_token — an event subscription cannot be registered
NO_USER_TOKEN 400 The app has no OAuth token — authorize the app on the portal first

For the full operation reference, see portal event subscriptions.

Resource not found

Code HTTP When it occurs
ENTITY_NOT_FOUND 404 A CRM entity record with the given id does not exist. The canonical code for /v1/deals/:id, /v1/contacts/:id, and similar
NOT_FOUND 404 GET /:id only: Bitrix24 returned success, but result is empty (applies to several smart methods)

Domain *_NOT_FOUND codes (BOT_NOT_FOUND, SERVER_NOT_FOUND, AGENT_NOT_FOUND, APP_NOT_FOUND, PORTAL_NOT_FOUND, USER_NOT_FOUND, FILE_NOT_FOUND, SUBSCRIPTION_NOT_FOUND) are documented on the pages of their respective sections.

State conflicts

Code HTTP When it occurs
CONFLICT 409 The current resource state is incompatible with the request
ALREADY_EXISTS 409 A record with these key fields already exists
EVENT_BOUND_ELSEWHERE 409 A portal event is already bound to another server of the same OAuth app. See portal event subscriptions
OAUTH_CLIENT_ID_IN_USE 409 POST /v1/apps/:id/relink-oauth: the given bitrixClientId is already linked to another application. One client_id — one application

Billing and plans

Occur on endpoints that create and wake infrastructure (servers, agents, managed bots). The response includes a localized userMessage for display in the client interface.

Code HTTP When it occurs
BILLING_EXHAUSTED 402 The balance dropped into the red zone and the account is frozen. A top-up is required
ACCOUNT_FROZEN 402 The billing account is frozen for other reasons
COMMERCIAL_PLAN_REQUIRED 402 Free Bitrix24 plan, the trial period is unavailable or already used
INT_TARIFF_REQUIRED 402 The portal is on a free Bitrix24 plan — creating servers, deploying, and waking require a commercial plan (a demo plan grants a limited trial)
TRIAL_EXPIRED 402 The trial period has ended
TRIAL_PORTAL_LIMIT 402 The overall per-portal server limit was exceeded during the trial period
TRIAL_USER_LIMIT 402 The per-user server limit was exceeded during the trial period
PLAN_NOT_ALLOWED_ON_TRIAL 402 The requested server/agent plan is unavailable during the trial period
SERVER_WAKE_BLOCKED 403 Server wake-up is blocked for a non-billing reason
INT_TARIFF_REQUIRED 403 The account gets access through its Bitrix24 plan, and binding a placement requires a commercial plan

Rate limiting

Code HTTP When it occurs
RATE_LIMITED 429 Bitrix24 throttled the request rate or an internal limit was exceeded. The response includes retryAfter (seconds) and the Retry-After header
ERROR_LOOP_DETECTED 429 A Vibecode-side block: the same request repeats with the same error. A signal of a bug in the client code. Every Nth request is forwarded onward to check for recovery

Backend and third-party services

Code HTTP When it occurs
BITRIX_ERROR 422 Bitrix24 returned a business error that does not fall under narrower categories (ACCESS_DENIED, NOT_FOUND, INVALID_PARAMS)
BITRIX_UNAVAILABLE 502 Bitrix24 returned 5xx or did not respond in time
BIND_FAILED 502 Bitrix24 rejected the event registration (event.bind) — for example, the portal is not on a commercial plan. See portal event subscriptions
WINDOWED_SEARCH_FAILED Retired: when auto-windowing fails completely, /search returns the real Bitrix24 code — UNKNOWN_FILTER_FIELD / INVALID_PARAMS / BITRIX_ACCESS_DENIED / RATE_LIMITED / BITRIX_UNAVAILABLE / BITRIX_TIMEOUT (503), same as for a narrow range
QUEUE_OVERFLOW 429 The portal queue is overflowing: too many concurrent Bitrix24 calls. Rejected instantly, Retry-After in the header
QUEUE_TIMEOUT 429 The portal queue is saturated: more than 30 seconds of waiting on the Vibecode side. The request was NOT sent to Bitrix24 — safe to retry
BITRIX_TIMEOUT 503 Bitrix24 accepted the request but did not respond within 15 seconds — the outcome is unknown. For writes: re-read the entity first, the change may have applied
POOL_EXHAUSTED 503 The service is temporarily overloaded — the database connection pool is exhausted. The response carries retryAfter and a Retry-After header, retry after a few seconds
INTERNAL_ERROR 500 An unexpected Vibecode backend error
NETWORK_DEVKEY_REQUIRED 503 The developer key for the application author has not been issued yet — binding a placement is temporarily unavailable

Detailed reference

`MISSING_API_KEY` (401)

The request does not contain the 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 passed key does not exist or its format is unrecognized.

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

Causes:

  • A typo or extra whitespace in the key.
  • The key was deleted by its owner or an administrator.
  • The key is from a different environment (staging/production).
  • The prefix is not among the supported ones: vibe_api_, vibe_app_, vibe_live_, vibe_mgmt_.

Fix:

  • Check the key in your account on the /keys page.
  • Create a new key if the old one was deleted.

`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"
  }
}

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.
  • The key's scope was narrowed at creation time.

Fix:

  • Open the key page in your account and issue a new key with a broader scope set.
  • The full list of scopes and their purpose is on the Keys and authorization page.

`BITRIX_ACCESS_DENIED` (403)

Bitrix24 returned ACCESS_DENIED: the user or app lacks permission for the entity or operation.

JSON
{
  "success": false,
  "error": {
    "code": "BITRIX_ACCESS_DENIED",
    "message": "ACCESS_DENIED"
  }
}

Causes:

  • The user lacks permission for the entity in CRM (e.g. another user's deal with restricted visibility).
  • The Bitrix24 app does not have the required scope in its permissions on the Bitrix24 account.
  • The requested module is disabled in the Bitrix24 account (no CRM, no bot platform, and so on).

Fix:

  • Check the user's permissions in the Bitrix24 entity card.
  • Open the app settings in the Bitrix24 account and broaden the permission set.

`WRITE_BLOCKED_READONLY_KEY` (403)

The key is in read-only mode (accessMode: "READONLY"), but the request performs a write. The full description of the mode, switching, and portal policy is 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"
    }
  }
}

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 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 account page where the mode is switched — "/keys"

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 key owner should open API Keys, select "Read and write" under the Access mode block in the relevant key's card, and save. The mode applies to the next request, no reissue needed.
  • If the toggle in the card is unavailable — the Bitrix24 account administrator 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.

`VALIDATION_ERROR` (400)

The body or query parameters failed schema validation. Most V1 endpoints validate via Zod, so the message lists the specific problematic fields.

JSON
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "fields.title: Required; fields.stageId: Expected string, received number"
  }
}

Causes:

  • Required fields are missing.
  • A value's type does not match the schema (string instead of number, wrong date format).
  • The Content-Type: application/json header is missing. A body that cannot be parsed as JSON is rejected with separate codes — INVALID_JSON_BODY, FST_ERR_CTP_INVALID_JSON_BODY, or fst_err_ctp_invalid_json_body on the AI Router routes. Which one you get depends on the route — see the table above.

Fix:

  • Check the body against the endpoint schema in the entity reference or on the specific endpoint page.
  • Pass numbers without quotes, dates in ISO 8601 format (2026-04-29T10:00:00).
  • Add the Content-Type: application/json header.

`INVALID_PARAMS` (400)

Bitrix24 or the route handler found an invalid parameter value. Bitrix24 errors of the form INVALID_PARAMS: ... arrive under this same code.

JSON
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "Path parameter :id must be a positive integer"
  }
}

Causes:

  • An invalid path parameter value (e.g. a non-number where a number is expected).
  • Bitrix24 rejected a request parameter (e.g. an unsupported enum field value).

Fix:

  • Check the endpoint page: which values are valid for each parameter.
  • For filter, use the field list from GET /v1/<entity>/fields.

`MISSING_REQUIRED_FILTER` (400)

A required filter was not passed on a list endpoint that needs context.

JSON
{
  "success": false,
  "error": {
    "code": "MISSING_REQUIRED_FILTER",
    "message": "filter[entityType] and filter[entityId] are required for /v1/timelines"
  }
}

Causes:

  • The list of timeline records, comments, and other "nested" data requires a pair of parent identifiers.

Fix:

  • Add the required filter parameters listed in message or on the endpoint page.

`BATCH_LIMIT_EXCEEDED` (400)

The request exceeds the element limit in a bulk operation. At the /v1/batch level the limit is checked via INVALID_REQUEST referencing Array must contain at most 50 element(s). On domain bulk endpoints (e.g. chats, task-comments) — a dedicated BATCH_LIMIT_EXCEEDED code.

JSON
{
  "success": false,
  "error": {
    "code": "BATCH_LIMIT_EXCEEDED",
    "message": "Maximum 50 dialogs per bulk request (Bitrix24 batch limit)."
  }
}

Causes:

  • The array has more than 50 elements.

Fix:

  • Split the operation into several requests of 50 elements each.
  • Use batch requests for sequential calls from a single key.

`ENTITY_NOT_FOUND` (404)

A CRM entity record with the given id does not exist or was deleted.

JSON
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Item not found"
  }
}

Causes:

  • A record with this id genuinely does not exist.
  • The record was deleted by a concurrent process.
  • The wrong entity: the request goes to /v1/deals/:id, but the ID is from a lead.

Fix:

  • Check that the record exists via the entity's list endpoint.
  • Restore it from the Bitrix24 recycle bin if it was deleted recently (via the Bitrix24 account interface).

`RATE_LIMITED` (429)

Bitrix24 throttled the request rate or an internal Vibecode limit was triggered.

JSON
{
  "success": false,
  "error": {
    "code": "RATE_LIMITED",
    "message": "QUERY_LIMIT_EXCEEDED",
    "hint": "Wait 1-2 seconds and retry. Use POST /v1/batch to combine up to 50 calls in 1 request.",
    "retryAfter": 2
  }
}

Response headers:

Retry-After: 2

Causes:

  • Too many concurrent requests piled up from a single key: the general platform limit is counted per API key. The exceptions are POST /v1/search, POST /v1/research and POST /v1/batch, where the limit is counted per portal and all of its keys share one counter.
  • The requests-per-second limit on the Bitrix24 side was exceeded. It is counted per portal.

Fix:

  • Wait the number of seconds given in error.retryAfter or the Retry-After header.
  • Implement retries with exponential backoff.
  • Combine up to 50 calls via POST /v1/batch.
  • Cache rarely changing reference data — fields, statuses, currencies.

`ERROR_LOOP_DETECTED` (429)

Vibecode detects a series of identical errors on a single key for a single Bitrix24 method — and temporarily blocks the request on the Vibecode side to avoid inflating Bitrix24 counters. Every Nth request is forwarded onward: if the backend has recovered, the block is lifted automatically.

JSON
{
  "success": false,
  "error": {
    "code": "ERROR_LOOP_DETECTED",
    "message": "Vibe-side block (not a Bitrix24 limit). 12 failures on crm.deal.list in the last hour.",
    "hint": "Every 50th request will probe for recovery — keep retrying with backoff. If you suspect a platform-side issue (e.g. 5xx during an outage), platform admin can clear the block via POST /api/platform/analytics/circuit-breaker/<apiKeyId>/clear.",
    "retryAfter": 60
  }
}

Causes:

  • A bug in the client code: a request with identical parameters repeats and consistently fails.
  • A platform outage on the Bitrix24 side during the burst of requests.

Fix:

  • Read message — it names the specific method with the error series.
  • Find the request's source in the code, fix the parameters or logic.
  • During a platform outage — the platform administrator can clear the block via POST /api/platform/analytics/circuit-breaker/<apiKeyId>/clear.

`BILLING_EXHAUSTED` (402)

The billing account dropped into the red zone: the balance is negative, the grace period is exhausted. Requests to create and wake infrastructure are blocked until a top-up.

JSON
{
  "success": false,
  "error": {
    "code": "BILLING_EXHAUSTED",
    "message": "Account is frozen due to negative balance.",
    "userMessage": "The billing account is frozen due to a negative balance. Top up the account to continue working with servers and agents.",
    "hint": "Top up the account at /billing/topup, then call POST /v1/portals/:id/refresh-tariff."
  }
}

Causes:

  • There are no funds on the balance to cover the hourly cost of servers and agents.

Fix:

  • Top up the balance on the /billing/topup page.
  • After topping up, call POST /v1/portals/:id/refresh-tariff to update the status.

`COMMERCIAL_PLAN_REQUIRED` (402)

Creating servers and agents is unavailable on the free Bitrix24 plan after the trial period ends.

JSON
{
  "success": false,
  "error": {
    "code": "COMMERCIAL_PLAN_REQUIRED",
    "message": "Commercial Bitrix24 plan required for infrastructure operations.",
    "userMessage": "Infrastructure creation is available on commercial Bitrix24 plans. The trial period has already been used.",
    "hint": "Upgrade plan at https://www.bitrix24.com/prices/, then call POST /v1/portals/:id/refresh-tariff."
  }
}

Fix:

  • Upgrade the Bitrix24 plan to a commercial one.
  • After upgrading, call POST /v1/portals/:id/refresh-tariff or GET /v1/me?refresh=tariff.

`TRIAL_EXPIRED` (402)

The trial period has ended and the plan is still free.

JSON
{
  "success": false,
  "error": {
    "code": "TRIAL_EXPIRED",
    "message": "Trial period has ended.",
    "userMessage": "The trial period has ended. Switch to a commercial Bitrix24 plan to keep using servers and agents."
  }
}

Fix:

  • Switch to a commercial Bitrix24 plan.
  • Update the status via POST /v1/portals/:id/refresh-tariff.

`BITRIX_ERROR` (422)

Bitrix24 returned a business error that does not fall under narrower categories (ACCESS_DENIED, NOT_FOUND, INVALID_PARAMS, RATE_LIMITED).

JSON
{
  "success": false,
  "error": {
    "code": "BITRIX_ERROR",
    "message": "Invalid filter: field 'NON_EXISTENT_FIELD' is not allowed in filter",
    "hint": "Known Bitrix24 limitation: …"
  }
}

Causes:

  • Bitrix24 rejected the operation for a business reason: incompatible state, unsupported value, business rule.
  • The request runs in a Bitrix24 account where the corresponding module is disabled.

Fix:

  • Read message — it holds the original error text from Bitrix24.
  • If hint is present — use it as the first diagnostic step.

`BITRIX_UNAVAILABLE` (502)

Bitrix24 returned 5xx or did not respond within the allotted time.

JSON
{
  "success": false,
  "error": {
    "code": "BITRIX_UNAVAILABLE",
    "message": "Bitrix24 returned 503 Service Unavailable"
  }
}

Causes:

  • Maintenance or overload on the Bitrix24 side.
  • Network problems between Vibecode and the Bitrix24 portal.

Fix:

  • Retry the request after a few minutes, implementing retries with exponential backoff.
  • ⚠️ For write operations (POST/PATCH) — first check whether the original request applied. A slow portal may process the write AFTER the API already returned a timeout — a blind retry creates a duplicate (task, epic, comment). Before retrying, GET the list/record (e.g. search by the title you just sent) and retry only if the record is absent.
  • Check the portal status at /bitrix/admin/site_checker.php (for the Bitrix24 account administrator).

`QUEUE_OVERFLOW` (429)

The request queue to Bitrix24 for a specific portal is overflowing: too many calls are already pending (more than 100 by default). The response returns instantly, within milliseconds, with the HTTP header Retry-After: N (seconds).

JSON
{
  "success": false,
  "error": {
    "code": "QUEUE_OVERFLOW",
    "message": "Portal queue overloaded — 100 Bitrix24 calls already pending",
    "userMessage": "The portal queue is overflowing. Too many concurrent requests to Bitrix24.",
    "hint": "Honor the Retry-After header. Use exponential backoff with jitter for repeated failures.",
    "retryAfter": 10
  }
}

Fix:

  • The portal queue is overflowing — retry after Retry-After seconds, using backoff with jitter (a random addition to the delay) so retries from different clients don't arrive as one wave.
  • Reduce concurrency on the client side.
  • Combine calls via POST /v1/batch.

`QUEUE_TIMEOUT` (429)

The request queue to Bitrix24 for a specific portal is saturated: more than 30 seconds of waiting.

JSON
{
  "success": false,
  "error": {
    "code": "QUEUE_TIMEOUT",
    "message": "Portal queue saturated — too many concurrent Bitrix24 calls",
    "userMessage": "Requests to Bitrix24 have been queued for over 30 seconds. The portal likely has many concurrent operations.",
    "hint": "If this is a /search request with a wide date range, try adding \"autoWindow\": false OR narrow the date range to <14 days. See /v1/guide for optimization tips.",
    "retryAfter": 10
  }
}

The request was NOT sent to Bitrix24 — safe to retry.

Fix:

  • Retry after retryAfter seconds, using backoff with jitter.
  • Reduce concurrency.
  • For /search endpoints — narrow the date range or pass autoWindow: false.
  • Combine calls via POST /v1/batch.

`BITRIX_TIMEOUT` (503)

Bitrix24 accepted the request but did not respond within 15 seconds — the outcome is unknown: the request MAY have applied on the portal side.

JSON
{
  "success": false,
  "error": {
    "code": "BITRIX_TIMEOUT",
    "message": "Bitrix24 accepted the request but did not respond within 15s",
    "hint": "For WRITE operations, verify whether the change was applied (re-read the entity) before retrying. Reads are safe to retry.",
    "retryAfter": 10
  }
}

Fix:

  • For reads (GET//search) — safe to retry, after a longer backoff than for 429.
  • ⚠️ For write operations (POST/PATCH) — re-read the entity first. The change may have already applied on the Bitrix24 side even though no response arrived. A blind retry creates a duplicate (task, epic, comment). Check whether the record exists (e.g. search by the title you just sent) and retry the write only if it's absent.

`INTERNAL_ERROR` (500)

An unexpected error on the Vibe API side.

JSON
{
  "success": false,
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal server error"
  }
}

Fix:

  • Retry the request.
  • If the error reproduces consistently — submit a ticket via POST /v1/feedback with the request time. The X-Request-Id header from the response speeds up diagnosis.

Retries and backoff

Summary of codes that signal a temporary problem and imply a retry:

Code HTTP Retry strategy
RATE_LIMITED, QUEUE_OVERFLOW, QUEUE_TIMEOUT 429 Retry after Retry-After + backoff with jitter (a random addition to the delay)
BITRIX_TIMEOUT 503 Longer backoff than for 429. For write operations — verify-before-retry first: re-read the entity, the change may have already applied
BITRIX_UNAVAILABLE 502 A retry won't help without changing the request — this is a 5xx from Bitrix24 itself or a network problem between Vibecode and the Bitrix24 portal, not a temporary queue overload

Error handling in code

JavaScript

javascript
async function vibeRequest(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: {
      'X-Api-Key': process.env.VIBE_API_KEY,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });

  const data = await response.json();

  if (!data.success) {
    const { code, message, retryAfter } = data.error;

    switch (code) {
      case 'RATE_LIMITED':
      case 'QUEUE_TIMEOUT': {
        const wait = retryAfter ?? Number(response.headers.get('Retry-After')) ?? 1;
        await new Promise(r => setTimeout(r, wait * 1000));
        return vibeRequest(url, options);
      }

      case 'BITRIX_UNAVAILABLE':
        await new Promise(r => setTimeout(r, 5000));
        return vibeRequest(url, options);

      case 'MISSING_API_KEY':
      case 'INVALID_API_KEY':
        throw new Error('Check the API key');

      default:
        throw new Error(`${code}: ${message}`);
    }
  }

  return data;
}

Python

Python
import os
import time
import requests

def vibe_request(url, method="GET", json_data=None):
    headers = {
        "X-Api-Key": os.environ["VIBE_API_KEY"],
        "Content-Type": "application/json",
    }

    response = requests.request(method, url, headers=headers, json=json_data)
    data = response.json()

    if not data.get("success"):
        err = data.get("error", {})
        code = err.get("code")
        message = err.get("message")
        retry_after = err.get("retryAfter") or int(response.headers.get("Retry-After", 1))

        if code in ("RATE_LIMITED", "QUEUE_TIMEOUT"):
            time.sleep(retry_after)
            return vibe_request(url, method, json_data)

        if code == "BITRIX_UNAVAILABLE":
            time.sleep(5)
            return vibe_request(url, method, json_data)

        raise Exception(f"{code}: {message}")

    return data

PHP

php
function vibeRequest(string $url, string $method = 'GET', ?array $data = null): array {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST => $method,
        CURLOPT_HTTPHEADER => [
            'X-Api-Key: ' . getenv('VIBE_API_KEY'),
            'Content-Type: application/json',
        ],
    ]);
    if ($data !== null) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    }
    $body = json_decode(curl_exec($ch), true);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($body === null) {
        throw new Exception("HTTP error: $httpCode");
    }

    if (empty($body['success'])) {
        $errCode = $body['error']['code'] ?? 'UNKNOWN';
        $errMsg = $body['error']['message'] ?? 'Unknown error';
        $retryAfter = $body['error']['retryAfter'] ?? 1;

        if (in_array($errCode, ['RATE_LIMITED', 'QUEUE_TIMEOUT'], true)) {
            sleep((int) $retryAfter);
            return vibeRequest($url, $method, $data);
        }

        if ($errCode === 'BITRIX_UNAVAILABLE') {
            sleep(5);
            return vibeRequest($url, $method, $data);
        }

        throw new Exception("$errCode: $errMsg");
    }

    return $body;
}

See also