
## Register a bot

New OAuth bots support `fetch` and `webhook`. The platform verifies bot ownership through the same OAuth application and an exact id/code match, without sending `botToken` to the OAuth API. Delivery to `/api/bot/webhook` requires a recent, verified INSTALL/placement event from the linked application; otherwise registration returns `409 BOT_APP_EVENT_ENROLLMENT_REQUIRED`. An earlier application token is not a substitute for this verification. Events received before initial registration completes are retained in a bounded encrypted inbox. Bot-token changes for new application-owned bots are refused (`409 BOT_OAUTH_POLICY_INVALID`); unmarked legacy bots are not automatically converted. A standalone OAuth key without a bound application can use `fetch` or its own receiver, but is not trusted by the platform receiver.

The platform receiver is available to Agent and ManagedBot bots with a verified owner. An application bot without a verified owner receives `409 BOT_APP_EVENT_CONSUMER_REQUIRED` before any data is written to Bitrix24. It can use `fetch` or its own callback. Events for an already published bot after a Bitrix24 account address change may remain in encrypted quarantine until the recovered identity is verified and published. Delivery requires an unchanged callback binding, continued eligibility of the application, author and owner membership, and verified authority to deliver the recovered events. If that basis changes or cannot be verified, held events are permanently discarded while bot identity recovery continues. Bounded retention does not guarantee delivery. Each recovery can retain at most 256 events and 4 MiB of ciphertext for 72 hours. A duplicate event does not extend retention. On overflow, the receiver returns `503` without acknowledging receipt.

`POST /v1/bots`

Registers a bot in your Bitrix24 account. New registrations accept a personal key backed by an incoming webhook or an OAuth application key. Repeating registration for a bot already known to the platform preserves the bot's token. Ambiguous recovery and registration during an account address change return `409`. Do not treat this response as confirmation that the bot works.

## Request fields (body)

| Parameter | Type | Required | Default | Description |
|----------|-----|:-----:|-----------|---------|
| `code` | string | yes | — | Unique bot code (Latin letters, digits, underscores) |
| `name` | string | yes | — | Bot display name, at most 50 Unicode code points. Longer names are refused before registration, without truncation |
| `type` | string | no | `bot` | [Bot type](#bot-types): `bot`, `personal`, `supervisor`, `openline`. Cannot be changed after registration. The type governs access to [reading messages](/docs/bots/messages) |
| `eventMode` | string | no | `fetch` | Event mode: `fetch` (polling) or `webhook` (events are delivered to your address) |
| `webhookUrl` | string | no | — | URL for event delivery (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 Channels support (only for `type: "openline"`) |

## Bot types

| Type | Description |
|-----|---------|
| `bot` | Standard bot — reacts to @mentions and direct messages |
| `personal` | AI assistant — receives all messages without an @mention. [`GET /v1/bots/:botId/messages/:messageId`](/docs/bots/messages/get) and [`GET /v1/bots/:botId/messages/:messageId/context`](/docs/bots/messages/context) are available |
| `supervisor` | System observer — receives all messages in the chats it belongs to |
| `openline` | Open Channels 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.

Bot registration is performed on behalf of a Bitrix24 account administrator, regardless of the bot type. If the key owner does not have that role, Bitrix24 denies access even when the key carries the `imbot` scope.

A Bitrix24 plan that includes Vibecode is also required. On a Bitrix24 account without such a plan, registration returns `422 BITRIX_ERROR` with `error.b24Code` set to `FEATURE_NOT_AVAILABLE_ON_CURRENT_PLAN`, and retrying the request does not help. You can check the account's plan before the call: it is returned in the `data.tariff` field of [`GET /v1/me`](/docs/keys-auth/me).

## 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

Use a key from the same OAuth application for both initial registration and repeat requests. The platform verifies bot ownership before saving it.

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

Use a key from the same OAuth application for both initial registration and repeat requests. The platform verifies bot ownership before saving it.

```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 |
| `users[].id` | number | Identifier of the bot user in the Bitrix24 account. Matches `botId` |
| `users[].name` | string | Display name of the bot — what chat participants see |
| `users[].workPosition` | string | Job title shown under the bot name |
| `users[].active` | boolean | Whether the bot user is active |
| `users[].bot` | boolean | Bot flag, always `true` |

## 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 contains `botId`, `code`, and `name` only when the record is already known locally. Absence from `GET /v1/bots` does not prove that no earlier registration exists in the Bitrix24 account. If you know of another key belonging to the owner, see [Bot access recovery](/docs/bots/ownership-recovery).

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `CODE_REQUIRED` | The `code` parameter was not provided |
| 400 | `NAME_REQUIRED` | The `name` parameter was not provided |
| 400 | `BOT_NAME_TOO_LONG` | The name exceeds 50 Unicode code points. No registration is attempted; supply a shorter name |
| 409 | `BOT_EFFECT_DESIRED_STATE_NOT_PROVED` | Registration awaits proof. Retry after `Retry-After`: 30 seconds, or 1–300 until its scheduled check. Use `POST /v1/bots/registrations/{code}/recover` with the same key and code; do not create another bot. |
| 409 | `BOT_RECOVERY_IN_PROGRESS` | Recovery owns the bot. Wait for `Retry-After: 5` before retrying. |
| 409 | `BOT_REGISTRATION_PROJECTION_CONFLICT` | Local registration projection changed concurrently. No `Retry-After`; reload state before retrying. |
| 409 | `BOT_EFFECT_IN_PROGRESS` | Registration is still being reconciled. Wait for `Retry-After`: 30 seconds, or 1–300 until its scheduled check, or use `POST /v1/bots/registrations/{code}/recover` with the same key and code. Do not choose a new code. |
| 409 | `BOT_UNAVAILABLE` | The bot policy or lifecycle state requires repair. A Bitrix24 call may already have occurred and its outcome may be uncertain. No `Retry-After` is returned. Stop automatic retries and contact support with the request time; check the key and owning application. |
| 409 | `BOT_ALREADY_EXISTS` | The code is already in use. `data` with `botId` is present only for a known local record |
| 409 | `BOT_REGISTRATION_ORIGIN_UNPROVEN` | Registration origin is unproven. No local record was changed |
| 409 | `BOT_OAUTH_POLICY_INVALID` | Invalid application identity, conflicting aliases or a bot-token change |
| 409 | `BOT_APP_EVENT_ENROLLMENT_REQUIRED` | The platform receiver requires a recent, verified INSTALL/placement event from the linked application |
| 409 | `BOT_APP_EVENT_CONSUMER_REQUIRED` | The platform receiver requires verified Agent or ManagedBot ownership. Use that owner's key, or choose `fetch` or your own receiver |
| 409 | `BOT_APP_EVENT_CREDENTIAL_CHANGED` | The application's verified callback binding changed before the bot was published. Reload the bot state before retrying |
| 409 | `BOT_REGISTRATION_CONTEXT_CHANGED` | Account address or key binding changed, or legacy OAuth needs a refresh. Refresh authorization before retrying. No `Retry-After`. |
| 409 | `BOT_REGISTRATION_CONCURRENT` | A concurrent operation changed the record. Reload state before retrying |
| 409 | `BOT_DOMAIN_REREGISTRATION_REQUIRED` | Automatic registration recovery after an address change. When `data` is present, it contains `botId`, `code`, `needsReregistration: true`; wait for `Retry-After: 5`. A move detected during this request has no `data` or `Retry-After`. Read the error code in both cases, wait for recovery and contact support if it persists |
| 422 | `BITRIX_ERROR` | Bitrix24 returned an error during registration (error text in `message`) |
| 422 | `BITRIX_ERROR` | `error.b24Code` is `FEATURE_NOT_AVAILABLE_ON_CURRENT_PLAN`: the Bitrix24 account's plan does not include Vibecode. Retrying does not help. The account's plan is in the `data.tariff` field of `GET /v1/me` |
| 502 | `REGISTRATION_FAILED` | Bitrix24 did not return a bot ID |
| 403 | `SCOPE_DENIED` | The API key does not have the `imbot` scope |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is in read-only mode |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |
| 422 | `APP_HOST_NOT_ALLOWED_HERE` | `webhookUrl` points to a named address in the platform's app domain (`<name>.<domain>`, not `app-…`), but the name is not bound to a server in your Bitrix24 account. Nothing is stored and Bitrix24 is not called. Your own server's name is accepted and stored as that server's `app-…` address |

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

## Known specifics

**Recovery after a desync.** Without a local record, an existing ID or a code already in use does not prove bot ownership. For a personal key, Vibecode verifies acceptance of the new token. For OAuth, it verifies ownership by the same application. If ownership cannot be confirmed, the method returns `409 BOT_REGISTRATION_ORIGIN_UNPROVEN` without creating a record. Repeat requests from the same OAuth application are accepted once ownership is confirmed.

**Repeat requests that return `201`.** The previous token is preserved when the bot was known locally before the request and Bitrix24 returns the same registration. After an account address change, replaying that registration does not clear `needsReregistration`: the response is `409 BOT_DOMAIN_REREGISTRATION_REQUIRED`. A retained local record carries `data: { botId, code, needsReregistration: true }` and `Retry-After: 5`; a move detected during the request has neither `data` nor `Retry-After`. Wait for recovery in both cases. Never delete Agent or Managed Bot identities through the Bot API. Recover them through their owner resource, or contact support if that recovery is unavailable.

**Request body format.** When creating a bot, pass parameters at the top level (`code`, `name`, `color`). `PATCH` accepts flat parameters or 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. The maximum size is ~50 KB: above that the request still succeeds, but the avatar is not saved and stays empty.

**OAuth and caller-provided tokens.** A new OAuth registration is accepted once ownership by the same application is verified. If no previous local record exists, a caller-provided token is still rejected with `409 BOT_REGISTRATION_ORIGIN_UNPROVEN` before the platform contacts Bitrix24. An expired legacy OAuth token requires a separate authorization refresh. Registration does not refresh these tokens and returns `409 BOT_REGISTRATION_CONTEXT_CHANGED`. Previously created bots reporting `BOT_OWNERSHIP_ERROR` are not recovered automatically.

**Bot lifecycle.** A bot lives exactly as long as the local application through which it was registered. 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. Fetching events, sending messages, and updating the bot all use that same key — a request using a different key returns `403 BOT_ACCESS_DENIED`. If a different key is the one that still works, see [Bot access recovery](/docs/bots/ownership-recovery). An app-owned OAuth bot can transfer only to an eligible key of the same OAuth application (`client_id`). Restore access to that matching application and key; a recreated application with another `client_id` cannot take ownership: `400 TARGET_KEY_INVALID` with `error.reason=application_mismatch`. If the matching application cannot be restored, contact support. Unmarked legacy/token-based and personal-webhook bots retain their existing transfer rules and can use an eligible key of the same Bitrix24 account. Transfer to a compatible key preserves `botId`, chats and history.

**`webhook` mode requires a public `webhookUrl`.** With `eventMode: "webhook"`, Bitrix24 sends events directly to `webhookUrl`, so the address must be publicly reachable. If `webhookUrl` points at a Black Hole server with a personal `vibe_api_…` key, only the `PUBLIC` access policy accepts the event — under `OWNER_ONLY` (the default), `NAMED_USERS`, `DEPARTMENT`, `PORTAL`, and `AUTHENTICATED` it never reaches the app, and `eventMode: "fetch"` suits such a server better. For an Agent or ManagedBot bot with verified ownership and application enrollment, `/api/bot/webhook` receives events on the platform and delivers them through the owner's tunnel without making the server public. Details and solutions are in the [Troubleshooting](/docs/bots/troubleshooting) section. The incoming event body and its authenticity check are in [A webhook-delivered event](/docs/bots/events/webhook).

For your own receiver, choose the verification method based on how the bot was registered: personal-key bots and OAuth bots registered under the previous contract use the string `custom` followed immediately by the bot token; new application-owned OAuth bots use the top-level application token from verified enrollment, compared with trusted server-side configuration; `data.bot.id` is routing data, not an authentication pin. The platform separately verifies the bot ID and code when confirming ownership during registration. Using an OAuth key does not migrate a legacy bot. See [Webhook authenticity](/docs/bots/events/webhook).

## See also

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