## 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 point appears in the interface with the title passed in the request.

Call preconditions — [what is needed before binding](/docs/apps#placements).

## Request fields (body)

| Field | Type | Req. | Description |
|------|-----|:-----:|----------|
| `placement` | string | yes | Placement code. The list of codes available to the account — [Available placements](/docs/apps/placements/available) |
| `handler` | string | yes | Absolute address of the application page that opens at this placement |
| `title` | string | yes | Placement title in the account interface, from 1 to 255 characters |
| `options` | object | no | Placement settings. Besides the fields listed below, any other fields are accepted — for example `context`, `role`, `extranet` for the `IM_CONTEXT_MENU` placement. The value of each field is a string, a number or a boolean. Nested objects and arrays are not accepted |
| `options.iconName` | string | no | Icon name, from 1 to 255 characters. Required for the `IM_SIDEBAR`, `IM_NAVIGATION`, `IM_TEXTAREA` placements — without it Bitrix24 rejects the binding. The `IM_CONTEXT_MENU` placement needs no icon |
| `options.errorHandlerUrl` | string | no | Error page address for the `PAGE_BACKGROUND_WORKER` placement. If the field is not passed, the platform substitutes the current handler address |
| `options.iconSvg` | string | no | Icon in SVG format, up to 10,000 characters |
| `options.width` | number | no | Width of the placement area. A positive integer |
| `options.height` | number | no | Height of the placement area. A positive integer |
| `options.color` | string | no | Color name from the Bitrix24 chat palette — for example `AZURE`, `GREEN`, `PURPLE`. Not a hexadecimal code, up to 64 characters |

## Examples

### curl — OAuth application

```bash
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

```javascript
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 address:', data.handler)
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on a successful binding |
| `data.placement` | string | Code of the bound placement |
| `data.handler` | string | Handler address registered on the account |
| `data.title` | string | Placement title in the account interface |
| `data.options` | object | Effective set of placement settings. Returned when the settings are passed in the request or substituted by the platform |
| `data.alreadyBound` | boolean | `true` when the placement was already listed as bound and the registration was performed again |
| `data.handlerRewritten` | boolean | `true` when the passed handler address was replaced with the platform one |
| `data.requestedHandler` | string | Handler address from the request. Returned together with `handlerRewritten` |

## Response example

The passed handler address was replaced with the platform one:

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

Repeated binding of the same code:

```json
{
  "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 address:

```json
{
  "success": true,
  "data": {
    "placement": "PAGE_BACKGROUND_WORKER",
    "handler": "https://example.com/worker",
    "title": "Background scenario",
    "options": {
      "errorHandlerUrl": "https://example.com/worker"
    }
  }
}
```

## Error response example

400 — a required field is missing in the request body:

```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "title: Required"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `OAUTH_APP_REQUIRED` | The call was made with a personal key. Binding works only with an application authorization key |
| 400 | `VALIDATION_ERROR` | The request body failed validation — a required field is missing or the placement code is not in the list of allowed ones |
| 400 | `PLATFORM_HANDLER_UNRESOLVABLE` | The passed address points to the technical address of the application server, and the platform handler could not be resolved. The placement is not registered |
| 400 | `APP_NOT_REGISTERED` | The application has no Bitrix24 application identifier |
| 400 | `BOX_NO_DEVELOPER_KEY` | The application author has no developer key configured |
| 401 | `SESSION_REQUIRED` | The `Authorization: Bearer` header with a session token is missing |
| 403 | `PLACEMENT_SCOPE_MISSING` | The key has no `placement` scope |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key works in read-only mode. Switch it to read and write |
| 403 | `SESSION_REQUIRES_ADMIN` | The developer key belongs to a user without account administrator rights |
| 403 | `INT_TARIFF_REQUIRED` | A commercial Bitrix24 plan is required |
| 404 | `APP_NOT_FOUND` | No application is linked to the key |
| 413 | `FST_ERR_CTP_BODY_TOO_LARGE` | The body was not sent as JSON and is longer than one byte. Set the `Content-Type: application/json` header |
| 415 | `FST_ERR_CTP_INVALID_MEDIA_TYPE` | The body was not sent as JSON and is exactly one byte — the same cause, a different validation branch |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 rejected the placement registration. The Bitrix24 response code and status are returned in `details` |
| 503 | `NETWORK_DEVKEY_REQUIRED` | The developer key for the application author has not been issued yet |

The full list of common API errors — [Errors](/docs/errors).

## Known specifics

- **Repeated binding 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 address and title take effect. This is the only way to change the title of an already bound placement.
- **The technical address of the application server is replaced with the platform one.** If `handler` points to the technical address of the application server, the platform application handler is registered on the account. External addresses are registered unchanged.
- **Bitrix24 augments `options` with 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](/docs/apps/placements/list) even when you did not pass them.
- **One title for all interface languages.** The `title` value goes to the account as a single label. A separate translation is not set by this call. In [bound placements](/docs/apps/placements/list) the `langAll` field returns the same title for every language.

## See also

- [Placements](/docs/apps/placements)
- [Available placements](/docs/apps/placements/available)
- [Bound placements](/docs/apps/placements/list)
- [Unbind a placement](/docs/apps/placements/unbind)
- [Key data](/docs/keys-auth/me)
- [Applications](/docs/apps)
