For AI agents: markdown of this page — /docs-content-en/apps/placements/bind.md documentation index — /llms.txt
Bind a placement
POST /v1/placements/bind
Registers the application at the selected interface point of a Bitrix24 account — a card tab, a menu item, a chat panel. After the call, the placement appears in the interface under the title passed in the request.
Call preconditions — what is required before binding.
On a cloud account, the platform first uses the transport selected for that account. If Bitrix24 rejects the developer key with a credential-only HTTP 401 and the app key is accompanied by a live Authorization: Bearer session, the bind is retried through OAuth automatically. A response that explicitly names a non-credential cause, such as an account-policy refusal or a missing scope, remains authoritative at every HTTP status and is never retried through OAuth. A successful response means one of these independent channels confirmed the write.
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
Fieldplacement |
Typestring | Requiredyes | DescriptionPlacement code. The list of codes available to the account — Available placements |
Fieldhandler |
Typestring | Requiredyes | DescriptionAbsolute URL of the application page that opens at this placement |
Fieldtitle |
Typestring | Requiredyes | DescriptionPlacement title in the account interface, from 1 to 255 characters, not whitespace only |
Fieldoptions |
Typeobject | Requiredno | DescriptionPlacement settings. Besides the fields listed below, any other fields are accepted — for example context, role, extranet for chat widgets. The value of each field is a string, a number or a boolean. Nested objects and arrays are not accepted |
Fieldoptions.iconName |
Typestring | Requiredno | DescriptionFont Awesome icon name with the fa- prefix — for example fa-comment. Bitrix24 rejects a name longer than 50 characters. The list of names — the Font Awesome 6 gallery. An icon is required for the IM_SIDEBAR, IM_NAVIGATION, IM_TEXTAREA placements, but the platform fills one in when the field is absent and reports it in the optionsDefaulted response field. Your own value always wins over the filled-in one. The IM_CONTEXT_MENU placement needs no icon |
Fieldoptions.errorHandlerUrl |
Typestring | Requiredno | DescriptionError page URL for the PAGE_BACKGROUND_WORKER placement. If the field is not passed, the platform substitutes the current handler URL |
Fieldoptions.iconSvg |
Typestring | Requiredno | DescriptionIcon in SVG format, up to 10,000 characters |
Fieldoptions.width |
Typenumber | Requiredno | DescriptionWidth of the IM_TEXTAREA panel, in pixels. A positive integer |
Fieldoptions.height |
Typenumber | Requiredno | DescriptionHeight of the IM_TEXTAREA panel, in pixels. A positive integer |
Fieldoptions.color |
Typestring | Requiredno | DescriptionIcon color for the IM_TEXTAREA and IM_SIDEBAR placements, from the Bitrix24 chat palette: RED, GREEN, MINT, LIGHT_BLUE, DARK_BLUE, PURPLE, AQUA, PINK, LIME, BROWN, AZURE, KHAKI, SAND, ORANGE, MARENGO, GRAY, GRAPHITE. Not a hexadecimal code |
Examples
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/placements/bind \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"placement": "CRM_DEAL_DETAIL_TAB",
"handler": "https://example.com/deal-tab",
"title": "Deal analytics"
}'
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/placements/bind', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
placement: 'CRM_DEAL_DETAIL_TAB',
handler: 'https://example.com/deal-tab',
title: 'Deal analytics',
}),
})
const { data } = await res.json()
console.log('Registered handler URL:', data.handler)
Response fields
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | Descriptiontrue on a successful binding |
Fielddata.placement |
Typestring | DescriptionCode of the bound placement |
Fielddata.handler |
Typestring | DescriptionHandler URL registered on the account |
Fielddata.title |
Typestring | DescriptionPlacement title in the account interface |
Fielddata.options |
Typeobject | DescriptionEffective set of placement settings. Returned when the settings are passed in the request or substituted by the platform |
Fielddata.alreadyBound |
Typeboolean | Descriptiontrue when the placement was already listed as bound and the registration was performed again |
Fielddata.handlerRewritten |
Typeboolean | Descriptiontrue when the passed handler URL was replaced with the platform one |
Fielddata.requestedHandler |
Typestring | DescriptionHandler URL from the request. Returned together with handlerRewritten |
Response example
The passed handler URL was replaced with the platform one:
{
"success": true,
"data": {
"placement": "CRM_DEAL_DETAIL_TAB",
"handler": "https://vibecode.bitrix24.com/v1/bitrix-handler",
"title": "Deal analytics",
"requestedHandler": "https://app-a1b2c3d4.vibecode.bitrix24.com/deal-tab",
"handlerRewritten": true
}
}
Rebinding the same code:
{
"success": true,
"data": {
"placement": "CRM_DEAL_DETAIL_TAB",
"handler": "https://example.com/deal-tab",
"title": "Deal: summary",
"alreadyBound": true
}
}
Binding the PAGE_BACKGROUND_WORKER placement without options — the platform substituted the error page URL:
{
"success": true,
"data": {
"placement": "PAGE_BACKGROUND_WORKER",
"handler": "https://example.com/worker",
"title": "Background worker",
"options": {
"errorHandlerUrl": "https://example.com/worker"
}
}
}
Error response example
400 — a required field is missing in the request body:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "title: Required"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP400 | CodeOAUTH_APP_REQUIRED |
DescriptionThe call was made with a personal key. Binding works only with an application authorization key |
| HTTP400 | CodeVALIDATION_ERROR |
DescriptionThe request body failed validation — a required field is missing, title is whitespace only, or the placement code is not in the list of allowed ones |
| HTTP400 | CodePLATFORM_HANDLER_UNRESOLVABLE |
DescriptionThe passed URL points to the technical URL of the application server, and the platform handler could not be resolved. The placement is not registered |
| HTTP400 | CodeAPP_NOT_REGISTERED |
DescriptionThe application has no Bitrix24 application identifier |
| HTTP400 | CodeBOX_NO_DEVELOPER_KEY |
DescriptionThe application author has no developer key configured |
| HTTP401 | CodeSESSION_REQUIRED |
DescriptionThe Authorization: Bearer header with a session token is missing |
| HTTP403 | CodePLACEMENT_SCOPE_MISSING |
DescriptionThe key has no placement scope |
| HTTP403 | CodeWRITE_BLOCKED_READONLY_KEY |
DescriptionThe key works in read-only mode. In the Vibecode dashboard, open the page at the path from error.details.switchUrl and switch the mode to read and write there. Where the path leads for each kind of key — Access mode |
| HTTP403 | CodeWRITE_BLOCKED_READONLY_KEY |
DescriptionThe key does not change Bitrix24 data, and the placement embeds into an employee work screen, or its handler after the Black Hole address rewrite is not the platform handler |
| HTTP403 | CodeBOX_WEBHOOK_NOT_DEVELOPER_KEY |
DescriptionThe developer key used for the binding lacks the rest.developer scope. A key's scopes are fixed when it is issued — reconnect the account so the key is issued again. Returned before the account-access checks: a missing scope is not a question of the account's plan |
| HTTP403 | CodeSESSION_REQUIRES_ADMIN |
DescriptionThe developer key belongs to a user without account administrator rights |
| HTTP403 | CodePLACEMENT_APP_GRANT_MISSING |
DescriptionThe placement is not available to the Bitrix24 application: its grant lacks the required scope. details carries the required scope in requiredScope, the placements available to the application (availablePlacements, availablePlacementsTotal) and the way to widen the grant in remediation. An application's scopes are fixed when it is installed — widening them requires re-issuing the authorization key or creating an application that requests the scope up front. Vibecode key scopes do not affect this |
| HTTP400 | CodePLACEMENT_OPTIONS_REQUIRED |
DescriptionThe placement has a required option that is absent from the request and that the platform could not fill in. details carries missing — the list of those fields |
| HTTP400 | CodePLACEMENT_NOT_REST_BINDABLE |
DescriptionThe placement cannot be bound over the API: Bitrix24 does not declare it an embedding point. Pick another code from available placements — placements like this one are marked there with restBindable: false |
| HTTP403 | CodeB24_ACCESS_DENIED |
DescriptionBitrix24 rejected the developer-key credential with HTTP 401, and either no OAuth session was supplied or the OAuth retry also failed. This is a credential refusal, not a plan paywall. The safe error.details fields are documented below; the raw Bitrix24 response text and the developer-key URL are never returned |
| HTTP403 | CodeINT_TARIFF_REQUIRED |
DescriptionThe account gets access through its Bitrix24 plan — a commercial plan is required. error.details.upgradeUrl is not returned. For accounts where access is narrowed to the Vibe+ plan line, infrastructure and key issuance additionally require a Vibe+ plan (INT_VIBE_PLUS_REQUIRED) |
| HTTP404 | CodeAPP_NOT_FOUND |
DescriptionNo application is linked to the key |
| HTTP404 | CodeB24_EMBEDDING_APP_NOT_FOUND |
DescriptionBitrix24 does not know the application ID: the local application was deleted or reinstalled on the account. Create the local application again and call POST /v1/apps/:id/relink-oauth with the new bitrixClientId and bitrixClientSecret. Not to be confused with APP_NOT_FOUND, which is about the key-to-application link on the Vibecode side |
| HTTP413 | CodePAYLOAD_TOO_LARGE |
DescriptionThe body was not sent as JSON and is longer than one byte. Set the Content-Type: application/json header |
| HTTP415 | CodeFST_ERR_CTP_INVALID_MEDIA_TYPE |
DescriptionThe body was not sent as JSON and is exactly one byte — the same cause, a different validation branch |
| HTTP422 | CodeAPP_HOST_NOT_ALLOWED_HERE |
Descriptionhandler or options.errorHandlerUrl points at a named address of the platform app domain (<name>.<domain>, not app-…) whose name is not bound to a server of your Bitrix24 account. Nothing is stored and Bitrix24 is not called. A name of your own server is accepted and stored as that server's app-… address |
| HTTP502 | CodeBITRIX_UNAVAILABLE |
DescriptionBitrix24 rejected the placement registration and the reason could not be determined. The Bitrix24 response code and status are returned in details, alongside placementInAppList when the placement is available to the application, and diagnostics — "placement_list_skipped" when the reason could not be checked with the account, or "placement_list_empty" when it answered with an empty list, which proves nothing |
| HTTP503 | CodeNETWORK_DEVKEY_REQUIRED |
DescriptionThe developer key for the application author has not been issued yet |
`B24_ACCESS_DENIED` fields
| Field | Type | Description |
|---|---|---|
Fielderror.details.bitrixCode |
Typestring | DescriptionSafe machine code from the rejected developer-key attempt |
Fielderror.details.bitrixStatus |
Typenumber | DescriptionHTTP status returned by Bitrix24 |
Fielderror.details.oauthFallback |
Typestring | Descriptionunavailable when there was no OAuth session, or failed when the OAuth retry was also rejected |
Fielderror.details.oauthCode |
Typestring | DescriptionOptional safe machine code from the rejected OAuth retry |
Fielderror.details.oauthStatus |
Typenumber | DescriptionOptional HTTP status from the rejected OAuth retry |
These fields are diagnostics, not a selector for another client-side transport attempt: the platform has already performed or declined the OAuth fallback. Clients branch on the outer error.code; the set of internal Bitrix24 codes is not a stable API enum.
The full list of common API errors — Errors.
The error table is segment-specific and documents the codes of this deployment. On the international surface, an account-access refusal is represented by INT_TARIFF_REQUIRED; do not copy codes from another deployment segment into a shared client enum.
Known specifics
- A placement can require a scope on the Bitrix24 application, not on the key. Bitrix24 offers an embedding point only to applications whose grant covers the module that placement belongs to: task card tabs need the tasks scope, profile menu items need the users scope, and so on. The scope each code requires is returned per placement in available placements as
requiredScope, and the summary of the gates in key self-description asplacements.bindPrerequisite. An application's scopes are fixed when it is installed: they cannot be changed on a live application — re-issue the authorization key instead. - The platform fills in the options a placement requires. A chat widget's icon and the background worker's error page URL are filled in when you omit them. The list of filled-in fields is returned as
optionsDefaulted. - Rebinding re-registers the placement. A call for an already bound code is not rejected: the platform removes the previous registration and binds the placement again, so the new handler URL and title take effect. This is the only way to change the title of an already bound placement.
LEFT_MENUadds a second menu item. The application appears in the account menu as soon as it is created. BindingLEFT_MENUadds a second item with its own URL rather than replacing the first one. To remove the extra item, unbind theLEFT_MENUcode — the item that appeared at creation stays in place.- A credential-only developer-key HTTP 401 does not mean a different plan is required. It rejects that credential channel. With a live OAuth session the platform tries the independent channel; without one it returns
B24_ACCESS_DENIEDwith the safe Bitrix24 machine code and status. A named account-policy or missing-scope refusal remains authoritative regardless of HTTP status and never enters the OAuth fallback. - The technical URL of the application server is replaced with the platform one. If
handlerpoints to the technical URL of the application server, the platform application handler is registered on the account. External URLs are registered unchanged. - Bitrix24 augments
optionswith its own values. For chat widgets the account stores its own settings alongside the passed ones — display area, role and the extranet flag. They are returned in bound placements even when you did not pass them. - One title for all interface languages. The
titlevalue goes to the account as a single label. This call does not set a separate translation. In bound placements thelangAllfield returns the same title for every language. - A successful response means the account accepted the write, not that the record stayed in place. Check the actual account state at any moment after binding with the
portalSyncfield in bound placements:ok— the account returned the code,drift— the code is listed in Vibecode but the account does not have it. - One placement can be occupied by several applications. Bitrix24 distinguishes registrations by application, so binding the same code from a second application on the same account is not rejected and does not remove the first registration. Sharing the same platform handler URL across applications does not change that.