
# Bot access 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.

A bot is bound to the key it was registered with, so another key does not see it in the list and cannot claim the same code. Access is restored by transferring ownership to a compatible working key — the bot is not re-created, and chats and message history are preserved.

## What a loss of access looks like

The symptoms appear all at once:

- `GET /v1/bots` returns success and an empty `bots` array, even though the bot is running on the Bitrix24 account.
- `POST /v1/bots` with the same `code` returns `409 BOT_ALREADY_EXISTS` — the code is taken.
- `GET /v1/bots/:botId` with the identifier from the `409` response returns `403 BOT_ACCESS_DENIED`.
- At the same time, `GET /v1/me` confirms that the key itself is valid: `accessMode` equals `READWRITE`, and the `imbot` scope is present.

The bot list returned to a key that does not manage those bots:

```json
{
  "success": true,
  "data": {
    "bots": [],
    "users": [],
    "hasNextPage": false
  }
}
```

Repeated registration with the same code — the existing bot is returned in the `data` field:

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

A request to this bot with the same key:

```json
{
  "success": false,
  "error": {
    "code": "BOT_ACCESS_DENIED",
    "message": "This bot belongs to a different API key"
  }
}
```

## Why the bot is not visible

A bot has two different bindings. Ownership is assigned to a Vibecode user and does not change when keys expire or are revoked. The binding to a key means something else — which key manages the bot right now.

`GET /v1/bots` returns records from the Vibecode database filtered by the calling key, so a bot registered with another key does not appear in the list. The other operations — events, messages and updates — are authorized the same way and return `403 BOT_ACCESS_DENIED`.

Bot code uniqueness is checked within the Bitrix24 account, not the key. Hence the discrepancy: the list is empty, and the code is taken.

The bot itself is not affected. It stays on the Bitrix24 account, remains in the same chats and keeps its message history — only managing it through the API is unavailable.

## How to restore access

Four steps. Calls to the bot are made with the key that ownership is transferred to. The transfer is available to the bot owner, that is, the Vibecode user who owns the owner key. A Bitrix24 account administrator can also perform the transfer.

### 1. Get the bot identifier

Repeat the registration with the same `code` and inspect `error.code`. Only `409 BOT_ALREADY_EXISTS` with `data.botId` means that Vibecode has a local record owned by another key. In that case, continue to step 2. `BOT_REGISTRATION_ORIGIN_UNPROVEN` provides no identity to transfer, so contact support to verify the existing identity. `BOT_REGISTRATION_CONCURRENT` requires another `GET /v1/bots` before retrying. Missing `data.botId` in that response does not prove that no local bot exists. Other `409` codes require resolving the reported error rather than transferring a bot. Registration is performed on behalf of a Bitrix24 account administrator — otherwise Bitrix24 denies access.

```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" }'
```

A `201` response means the bot is already stored for the calling key and appears in `GET /v1/bots`. No transfer is needed. Use `data.botId` with the Bot API and do not continue to step 2.

The procedure applies to bots registered through Vibecode. A bot created directly on a Bitrix24 account, bypassing the platform, has no record in the Vibecode database: the `data` field is not present in the `409` response, and the transfer returns `404 BOT_NOT_FOUND`.

### 2. Get the target key identifier

`targetApiKeyId` is the `id` field of the key record, not the key string. The list is returned by [`GET /v1/keys`](/docs/management-keys/list) to a management key with the `vibe:mgmt:keys` scope — a personal key cannot get this list, and the response is `401 WRONG_KEY_TYPE`. A management key is created in your Vibecode account, and a read-only key is enough for this step: the list is returned, while such a key cannot modify keys. After the transfer it can be revoked.

The response contains the keys of the management key owner on the specified Bitrix24 account. You recognize your own key by the `prefix` and `suffix` fields. The `portalId` value arrives in the `data.portalId` field of the [`GET /v1/me`](/docs/keys-auth/me) response — that call needs no management scopes. The same identifier is returned by [`GET /v1/portals`](/docs/management-keys/portals), but it requires its own `vibe:mgmt:portals` scope. A Bitrix24 account administrator who transfers a bot to another user's key gets that key identifier from its owner — other users' keys are not returned in the list.

```bash
curl -H "X-Api-Key: YOUR_MANAGEMENT_KEY" \
  "https://vibecode.bitrix24.com/v1/keys?portalId=PORTAL_ID"
```

If you hold the target key, there is a shorter way: call any operation on the bot with that key. The `403 BOT_ACCESS_DENIED` response carries the identifier of that key in `error.fix.body.targetApiKeyId` and the ready transfer route in `error.fix.path`. The fields are present when this key can run the transfer itself — the conditions are in [`BOT_ACCESS_DENIED`](/docs/errors/auth#bot_access_denied-403).

### 3. Transfer ownership

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots/42/transfer \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "targetApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33" }'
```

```json
{
  "success": true,
  "data": {
    "transferred": true,
    "botId": 42,
    "fromApiKeyId": "8c41d5e7-2b90-4a63-b1f5-6d7e9a0c4b12",
    "toApiKeyId": "3f9a1c20-5e6b-4d18-9a77-0c2b8e4f1d33"
  }
}
```

After this response the bot appears in `GET /v1/bots` for the new key.

### 4. Check the binding

The transfer changes the binding on the Vibecode side. A separate call checks the new key's access to the bot on the Bitrix24 account. It responds only to the owner key, so this step is performed by the owner of the target key: a Bitrix24 account administrator who transferred the bot to another user's key gets `403 BOT_ACCESS_DENIED`.

```bash
curl -X POST https://vibecode.bitrix24.com/v1/bots/42/reauth \
  -H "X-Api-Key: YOUR_API_KEY"
```

This check is allowed for an active bot after a transfer. If the bot is already disabled, call it
only after `410 BOT_DISABLED` with `error.details.reauthAllowed=true`. Otherwise it returns
`409 BOT_REAUTH_NOT_ALLOWED`. A concurrent ownership or state change returns
`409 BOT_REAUTH_STATE_CHANGED`, and the server preserves the newer state.

```json
{
  "success": true,
  "data": {
    "validated": true,
    "refreshed": false
  }
}
```

`validated: true` confirms that the new key manages the bot on the Bitrix24 account — events, messages and updates work with it again.

## Target key requirements

For app-owned OAuth bots, the target must also belong to the same `client_id`; a different application returns `400 TARGET_KEY_INVALID` with `error.reason=application_mismatch`. A key is accepted when all conditions are met:

| Condition | Value |
|---------|----------|
| State | `ACTIVE` |
| Account | The same Bitrix24 account as the bot |
| Owner | The same Vibecode user who performs the transfer. A Bitrix24 account administrator transfers a bot to the key of any user of the same account — this path works from a personal `vibe_api_` key, and the role on the account is determined by it |
| Scope | `imbot` |
| Expiration | Not expired |
| Purpose | A general-purpose key. Service keys issued by the platform are not accepted: they have their own lifecycle, and after their rotation the bot is left unmanaged again |

The transfer does not check the target key's access mode — a read-only key is accepted. You still cannot manage the bot with such a key: step 4 and every later call return `403 WRITE_BLOCKED_READONLY_KEY`. Transfer ownership to a key in `READWRITE` mode.

You can check the key before the call using its record from the `GET /v1/keys` call in step 2: the state is in the `status` field, the Bitrix24 account in `portalId`, the owner in `userId`, the scopes in `scopes`, the expiration in `expiresAt`, the access mode in `accessMode`.

A key that fails the check is rejected with `400 TARGET_KEY_INVALID`, and the cause is returned in the `reason` field — the causes are listed in the error table of the [Bot ownership transfer](/docs/bots/management/transfer) page.

## When this is needed

Three situations lead to the same symptoms — the bot works, but the key does not see it.

**The owner key stopped working.** The key value was not saved at creation, the key was revoked, or its validity period ended. The bot binding is intact — access is restored by a transfer to a new key.

**The bot is registered with another key.** The deployment uses a different key from registration. Choose a compatible target key under the rules above; replacing the OAuth application does not restore access to its bot.

**The bot belongs to a platform resource.** The bot of an AI agent or a managed bot is governed by that resource itself, so a direct transfer returns `409 BOT_TRANSFER_NOT_ALLOWED`. Such a bot is restored through its own resource — see [AI agents](/docs/agents).

## Errors

| HTTP | Code | When it is returned |
|------|-----|---------------------|
| 409 | `BOT_ALREADY_EXISTS` | The code is taken by a bot registered with another key. For a bot created through Vibecode, its identifier is returned in `data.botId` |
| 409 | `BOT_REGISTRATION_ORIGIN_UNPROVEN` | Ownership is unproven; no transfer is authorized. Contact support to verify the existing registration |
| 409 | `BOT_REGISTRATION_CONCURRENT` | While the registration ran, a bot of another key took the code. Request `GET /v1/bots` again before retrying. The absence of `data.botId` in this response does not prove that no local bot exists |
| 403 | `BOT_ACCESS_DENIED` | A request to the bot with a key that does not manage it |
| 401 | `WRONG_KEY_TYPE` | The key list is requested with a personal key — `GET /v1/keys` responds only to a management key |
| 403 | `NOT_BOT_OWNER` | The transfer is performed by someone other than the bot owner — the same Vibecode user that owns the owner key, or a portal admin, is required |
| 400 | `TARGET_KEY_INVALID` | The target key failed the check. The cause is in the `reason` field |
| 404 | `TARGET_KEY_NOT_FOUND` | No key exists with this `targetApiKeyId` |
| 409 | `BOT_TRANSFER_NOT_ALLOWED` | The bot belongs to an AI agent or another platform resource |
| 409 | `BOT_TRANSFER_CONFLICT` | Ownership was changed by a parallel request — re-read the current binding and repeat if needed |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | A write call was made with a read-only key: registration, transfer or binding check |
| 401 | `TOKEN_MISSING` | The `vibe_app_` authorization key is sent without the `Authorization: Bearer` header |
| 410 | `REAUTH_REQUIRED` | The check at step 4 did not confirm access: the key credentials are invalid and are not refreshed automatically. Authorize the key again through OAuth or create a new personal key |
| 409 | `BOT_REAUTH_NOT_ALLOWED` | The bot is disabled by a state for which re-authorization is forbidden |
| 409 | `BOT_REAUTH_STATE_CHANGED` | Ownership or state changed during the probe. The newer state is preserved |

For the full code reference, see [Error codes](/docs/errors).

## Known specifics

**The procedure is safe to repeat from the start.** A transfer to a key that already owns the bot does not change the binding. You do not need to check the current state before repeating it.

**The previous key stops seeing the bot immediately.** After the transfer the bot disappears from the previous key's `GET /v1/bots` — its other bots stay in the list. If two processes were polling the bot, only the one working with the new key continues polling.

**Registering under a new code creates a different bot.** It has its own `botId`, its own chats and history, while the previous bot stays on the Bitrix24 account and continues to occupy its code.

## See also

- [Bot ownership transfer](/docs/bots/management/transfer)
- [Bot re-authorization](/docs/bots/management/reauth)
- [Bot list](/docs/bots/management/list)
- [Troubleshooting](/docs/bots/troubleshooting)
- [Management keys](/docs/management-keys)
