
## Register a bot

`POST /v1/bots`

Registers a new bot in a Bitrix24 account. The operation is idempotent on `code` — a repeated call with the same code returns `409 BOT_ALREADY_EXISTS` with the data of the existing bot.

## Request fields (body)

| Parameter | Type | Required | Default | Description |
|----------|-----|:-----:|-----------|---------|
| `code` | string | yes | — | Unique bot code (Latin letters, digits, underscore) |
| `name` | string | yes | — | Bot display name |
| `type` | string | no | `bot` | [Bot type](#bot-types): `bot`, `personal`, `supervisor`, `openline`. Cannot be changed after registration |
| `eventMode` | string | no | `fetch` | Event mode: `fetch` (polling) or `webhook` (push) |
| `webhookUrl` | string | no | — | URL for push notifications (only with `eventMode: "webhook"`) |
| `lastName` | string | no | — | Bot last name |
| `workPosition` | string | no | — | Bot job title (shown under the name) |
| `color` | string | no | — | Avatar color: `RED`, `GREEN`, `MINT`, `LIGHT_BLUE`, `DARK_BLUE`, `PURPLE`, `AQUA`, `PINK`, `LIME`, `BROWN`, `AZURE`, `KHAKI`, `SAND`, `MARENGO`, `GRAY`, `GRAPHITE` |
| `gender` | string | no | — | Gender: `M` or `F` |
| `avatar` | string | no | — | Bot avatar: PNG or JPEG as a base64 string without the `data:image/...;base64,` prefix, up to ~50 KB. See "Avatar format" in "Known specifics" |
| `isHidden` | boolean | no | `false` | Hide the bot from the contact list |
| `isReactionsEnabled` | boolean | no | `true` | Allow reactions to the bot's messages |
| `backgroundId` | string | no | — | Chat background: `azure`, `mint`, `steel`, `slate`, `teal`, `cornflower`, `sky`, `peach`, `frost` |
| `isSupportOpenline` | boolean | no | `false` | Open-channel support (only for `type: "openline"`) |

## Bot types

| Type | Description |
|-----|---------|
| `bot` | Standard bot — reacts to @mention and direct messages |
| `personal` | AI assistant — receives all messages without an @mention. `Message.get` and `Message.getContext` are available |
| `supervisor` | System observer — receives all messages in the chats it belongs to |
| `openline` | Open-channel bot. Requires `isSupportOpenline: true` |

> ⚠ **`personal` and `supervisor` are privileged types:** they receive all messages in the chats they belong to, even without an @mention of the bot. Use them deliberately. Registration via `POST /v1/bots` is allowed and does not require an admin role on the Bitrix24 side — the restriction is set by the permissions of your webhook/OAuth token.

## Available colors

Used in the `color` parameter when creating and updating a bot:

```
RED, GREEN, MINT, LIGHT_BLUE, DARK_BLUE, PURPLE, AQUA, PINK,
LIME, BROWN, AZURE, KHAKI, SAND, MARENGO, GRAY, GRAPHITE
```

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "support_bot",
    "name": "Support",
    "type": "bot",
    "eventMode": "fetch",
    "color": "AZURE",
    "workPosition": "Technical support assistant"
  }'
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "support_bot",
    "name": "Support",
    "type": "bot",
    "eventMode": "fetch",
    "color": "AZURE",
    "workPosition": "Technical support assistant"
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/bots', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    code: 'support_bot',
    name: 'Support',
    type: 'bot',
    eventMode: 'fetch',
    color: 'AZURE',
    workPosition: 'Technical support assistant',
  }),
})

const { success, data } = await res.json()
// `data.botId` mirrors the 409 BOT_ALREADY_EXISTS response — the same path for
// success and conflict. `data.bot.id` is kept for backward compatibility.
console.log('Bot ID:', data.botId)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/bots', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    code: 'support_bot',
    name: 'Support',
    type: 'bot',
    eventMode: 'fetch',
    color: 'AZURE',
    workPosition: 'Technical support assistant',
  }),
})

const { success, data } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `botId` | number | Bot ID in the Bitrix24 account. Mirrors `data.botId` from the 409 response — the same path for success and conflict |
| `bot.id` | number | Duplicate of `botId` for backward compatibility. Bot ID in the Bitrix24 account |
| `bot.code` | string | Unique bot code |
| `bot.type` | string | Bot type |
| `bot.eventMode` | string | Event mode: `fetch` or `webhook` |
| `bot.isHidden` | boolean | Hidden from the contact list |
| `bot.isReactionsEnabled` | boolean | Reactions allowed |
| `users` | array | Array of Bitrix24 users created for the bot |

## Response example

```json
{
  "success": true,
  "data": {
    "botId": 42,
    "bot": {
      "id": 42,
      "code": "support_bot",
      "type": "bot",
      "eventMode": "fetch",
      "isHidden": false,
      "isReactionsEnabled": true
    },
    "users": [
      {
        "id": 42,
        "name": "Support",
        "active": true,
        "bot": true
      }
    ]
  }
}
```

## Error response example

409 — a bot with this code already exists:

```json
{
  "success": false,
  "error": {
    "code": "BOT_ALREADY_EXISTS",
    "message": "Bot with this code already exists"
  },
  "data": {
    "botId": 42,
    "code": "support_bot",
    "name": "Support"
  }
}
```

The `data` field returns the `botId`, `code`, and `name` of the already-registered bot — this is the idempotent path for recovering the record in the Vibecode database after a desync.

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `CODE_REQUIRED` | The `code` parameter was not provided |
| 400 | `NAME_REQUIRED` | The `name` parameter was not provided |
| 409 | `BOT_ALREADY_EXISTS` | A bot with this `code` is already registered. The response contains `data` with `botId` |
| 422 | `BITRIX_ERROR` | Bitrix24 returned an error during registration (error text in `message`) |
| 502 | `REGISTRATION_FAILED` | Bitrix24 did not return a bot ID |
| 403 | `SCOPE_DENIED` | The API key does not have the `imbot` scope |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |

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

## Known specifics

**Type cannot be changed:** after registration, `type` is fixed. `PATCH /v1/bots/:botId` does not accept this field.

**Recovery after a desync:** if the bot exists in the Bitrix24 account but is missing from the Vibecode database (after a failure), a repeated `POST` with the same `code` restores the database record.

**Body format differs from PATCH:** on creation, fields are passed flat (`code`, `name`, `color`). On update — a nested structure `{ fields: { properties: { name, color } } }`.

**Avatar format.** The `avatar` field accepts a PNG or JPEG image as a base64 string **without** the `data:image/...;base64,` prefix — pass only the base64 data itself. An image URL or a string with the `data:` prefix results in a `422 BITRIX_ERROR` response. Size is up to ~50 KB: above that the request succeeds, but the avatar is not saved and stays empty.

**Idempotency on code:** if a bot with this code already exists both in the Vibecode database and in the Bitrix24 account, `409 BOT_ALREADY_EXISTS` is returned with `data: { botId, code, name }` of the existing bot. Suitable for re-running scripts and verifying registration without handling 200/400 separately.

**Bot lifecycle.** A bot exists exactly as long as the local application through which it was registered exists. Removing the application from the Bitrix24 account also removes the bot.

**Bot operations use the same key.** A bot is bound to the API key it was registered with. Polling events, sending messages, and updating run with that same key — a request from a different key returns `403 BOT_ACCESS_DENIED`. To move a bot to another active key of the same user — or by an account admin — use [`POST /v1/bots/:botId/transfer`](/docs/bots/management/transfer).

**`webhook` mode requires a public `webhookUrl`.** With `eventMode: "webhook"`, Bitrix24 sends events directly to `webhookUrl`, so the address must be publicly reachable. A Black Hole server with the `OWNER_ONLY` policy does not accept such a request — details and the solution are in the [Troubleshooting](/docs/bots/troubleshooting) section.

## See also

- [Troubleshooting](/docs/bots/troubleshooting)
- [Events](/docs/bots/events)
- [Messages](/docs/bots/messages)
- [Update a bot](/docs/bots/management)
- [Transfer bot ownership](/docs/bots/management/transfer)
- [Bot platform](/docs/bots)
- [Limits and optimization](/docs/optimization)
