## Transfer a session

`POST /v1/bots/:botId/openlines/session/transfer`

The bot transfers the Open Channel session to a selected employee or to a line queue. Call it instead of having the bot leave the chat when the conversation must move to a person in a given queue.

## Parameters

| Parameter | Type | Required | Default | Description |
|----------|-----|:-----:|-----------|----------|
| `botId` (path) | integer | yes | — | ID of a bot registered with this key. List: [`GET /v1/bots`](/docs/bots/management/list) |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `chatId` | integer \| string | yes | Open Channel chat ID: a positive integer, a string of digits or the `chat<N>` form. Source: the `data.chat.id` field of a [bot event](/docs/bots/events/bot-events) or `sessions[].chatId` in [`POST /v1/openlines/sessions/search`](/docs/openlines/sessions/search). Instead of `chatId`, you can pass `dialogId` or `CHAT_ID` |
| `dialogId` | string | no | The same chat, only in the `chat<N>` form, for example `chat2043`. A number without the prefix is not accepted here |
| `CHAT_ID` | integer \| string | no | Alternative name for `chatId` with the same formats |
| `userId` | integer \| string | no | ID of the employee the session is transferred to: a positive integer or a string of digits. List: [`GET /v1/users`](/docs/entities/users/list) |
| `queueId` | integer \| string | no | ID of the line whose queue the session is transferred to: a positive integer or a string of digits. List: [`GET /v1/openline-configs`](/docs/openlines/config/list) |
| `transferId` | integer \| string | no | Target as a single value: `queue<line ID>` is a line queue, for example `queue7`, with the prefix in any case. A number or a string of digits is an employee ID. Line ID from [`GET /v1/openline-configs`](/docs/openlines/config/list), employee ID from [`GET /v1/users`](/docs/entities/users/list) |
| `leave` | boolean \| string | no | Whether the bot leaves the chat after the transfer: `true`, `false`, `"Y"` or `"N"`. Without the field, the bot stays in the chat |

The first filled field among `chatId`, `dialogId` and `CHAT_ID` is read, in exactly this order. A field set to `null` counts as not filled. An invalid value in the first filled field returns `400 INVALID_CHAT_ID`, and the remaining fields are not checked in that case.

Pass exactly one of `userId`, `queueId` and `transferId`. A field set to `null` counts as not passed.

Target fields and `leave` are also accepted under uppercase names: `USER_ID`, `QUEUE_ID`, `TRANSFER_ID`, `LEAVE`. If both name variants are passed, the field with the name from the table above is read: `userId`, `queueId`, `transferId` or `leave`.

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots/621/openlines/session/transfer \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "chatId": 2043,
    "queueId": 7,
    "leave": true
  }'
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots/621/openlines/session/transfer \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "chatId": 2043,
    "queueId": 7,
    "leave": true
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/bots/621/openlines/session/transfer',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ chatId: 2043, queueId: 7, leave: true }),
  }
)

const { success, data, error } = await res.json()
console.log(success ? data.transferred : error.code)
```

### JavaScript — OAuth application

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/bots/621/openlines/session/transfer',
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ chatId: 2043, queueId: 7, leave: true }),
  }
)

const { success, data, error } = await res.json()
console.log(success ? data.transferred : error.code)
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` when Bitrix24 confirmed the call |
| `data.chatId` | integer | ID of the chat the action was applied to. Returned as a number even if the request passed the `chat<N>` form |
| `data.transferred` | boolean | Always `true`: Bitrix24 confirmed the transfer |

## Response example

```json
{
  "success": true,
  "data": {
    "chatId": 2043,
    "transferred": true
  }
}
```

## Error response example

422 — Bitrix24 rejected the transfer:

```json
{
  "success": false,
  "error": {
    "code": "BITRIX_ERROR",
    "message": "You can not redirect to this operator",
    "b24Code": "OPERATOR_WRONG"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_BOT_ID` | `botId` in the path is not a positive integer |
| 400 | `INVALID_PARAMS` | The request body is not a JSON object, for example an array or a string |
| 400 | `INVALID_CHAT_ID` | None of the `chatId`, `dialogId`, `CHAT_ID` fields was passed, the value is invalid, or `dialogId` was passed without the `chat` prefix. A body that cannot be parsed as JSON is treated as empty and also gets this code. `message` says where to get the chat ID |
| 400 | `MISSING_TRANSFER_TARGET` | None of the `userId`, `queueId`, `transferId` fields was passed |
| 400 | `INVALID_TRANSFER_TARGET` | More than one transfer target was passed |
| 400 | `INVALID_TRANSFER_TARGET` | The target is neither a positive integer nor the `queue<N>` form |
| 400 | `INVALID_TRANSFER_TARGET` | `leave` is not one of `true`, `false`, `"Y"` or `"N"` |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not passed |
| 401 | `TOKEN_MISSING` | The key has no portal tokens. For an application key, the user session token was not passed |
| 403 | `SCOPE_DENIED` | The key lacks the `imbot` or `imopenlines` scope — both are required |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is in read-only mode |
| 403 | `BOT_ACCESS_DENIED` | The bot was registered by another key. To regain control, see [Restoring access to a bot](/docs/bots/ownership-recovery) |
| 403 | `BITRIX_ACCESS_DENIED` | Bitrix24 denied access to the chat |
| 404 | `BOT_NOT_FOUND` | No bot with this `botId` on the portal — register it via `POST /v1/bots` |
| 404 | `ENTITY_NOT_FOUND` | Bitrix24 reported that the record was not found |
| 409 | `BOT_ID_REPLACED` | The bot was registered again after the portal address changed. The new ID is in `error.details.botId` |
| 409 | `BOT_RECOVERY_IN_PROGRESS` | The bot is being restored automatically after the portal address changed. Retry after the pause from the `Retry-After` header |
| 410 | `BOT_DISABLED` | The bot is disabled. To bring the bot back, see [Bot disabled](/docs/bots/troubleshooting#bot-disabled-bot_disabled) |
| 422 | `BITRIX_ERROR` | Bitrix24 rejected the transfer. The Bitrix24 code is in `error.b24Code`, for example `OPERATOR_WRONG` |
| 429 | `RATE_LIMITED` | The shared platform ceiling of 30 requests per minute per portal was exceeded. The ceiling is shared by the four bot actions in an Open Channel and the `POST /v1/openlines/operator/answer` and `POST /v1/openlines/operator/finish` calls, and is split between platform replicas, so the code can arrive before the 30th request. The effective value is in the `x-ratelimit-limit` header, and the time until a retry is in `error.message`. A request rejected with `400` because of an error in the body also counts against the limit |
| 429 | `RATE_LIMITED` | Bitrix24 throttled requests to the portal. Retry after the pause from the `Retry-After` header |
| 429 | `QUEUE_OVERFLOW` | The request queue to the portal is full. Retry after the pause from the `Retry-After` header |
| 429 | `QUEUE_TIMEOUT` | The request did not get its turn in the portal queue and was not sent to Bitrix24. Retry after the pause from the `Retry-After` header |
| 502 | `OPENLINE_BOT_SESSION_FAILED` | Bitrix24 did not confirm the transfer: the call result is not `true` |
| 502 | `BITRIX_UNAVAILABLE` | The Bitrix24 portal is unavailable |
| 503 | `BITRIX_TIMEOUT` | The Bitrix24 portal did not respond in time |
| 503 | `user_self_deletion_pending` | The key owner's account on the portal is pending deletion |

Full list of common API errors: [Errors](/docs/errors).

## Known specifics

**`OPERATOR_WRONG` does not distinguish a wrong target from a wrong chat.** A transfer to an existing queue or an existing employee, but in a chat that does not exist, also returns `422 BITRIX_ERROR` with `error.b24Code` equal to `OPERATOR_WRONG`. Check `chatId` against the bot event or [session search](/docs/openlines/sessions/search) before changing the target.

## See also

- [Open Channel bot](/docs/bots/openlines)
- [Hand to an operator](/docs/bots/openlines/operator)
- [Finish a session](/docs/bots/openlines/finish)
- [Send an automatic line message](/docs/bots/openlines/auto-message)
- [List of Open Channel configurations](/docs/openlines/config/list)
