## Create a subscription

`POST /v1/infra/servers/:id/event-subscriptions`

Registers a Bitrix24 event handler under the server's OAuth application. After creation, the platform delivers every event of the specified type to the application at the `appPath` path. The server must be backed by a `vibe_app_` authorization key — the prerequisites and the order for creating such a server are described in the [Portal event subscriptions](/docs/infra/event-subscriptions) section.

## Parameters

| Parameter | In | Type | Required | Description |
|----------|---|-----|:-----:|----------|
| `id` | path | string (UUID) | yes | Server ID. List: [`GET /v1/infra/servers`](/docs/infra/servers) |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `event` | string | yes | Bitrix24 event code. Format `^[A-Z][A-Z0-9_]+$` — uppercase Latin letters, digits, underscore. Examples: `ONTASKADD`, `ONTASKUPDATE`, `ONCRMDEALADD` |
| `appPath` | string | yes | Path on the application where the event is delivered. Starts with `/`. Example: `/api/webhooks/b24` |

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/event-subscriptions \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "event": "ONTASKADD", "appPath": "/api/webhooks/b24" }'
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/v1/infra/servers/SERVER_ID/event-subscriptions \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "event": "ONTASKADD", "appPath": "/api/webhooks/b24" }'
```

### JavaScript — personal key

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/event-subscriptions`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ event: 'ONTASKADD', appPath: '/api/webhooks/b24' }),
  }
)
const { success, data } = await res.json()
console.log('Subscription ID:', data.id, '— handler:', data.b24Handler)
```

### JavaScript — OAuth application

```javascript
const res = await fetch(
  `https://vibecode.bitrix24.com/v1/infra/servers/${serverId}/event-subscriptions`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': 'YOUR_APP_KEY',
      'Authorization': 'Bearer USER_SESSION_TOKEN',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ event: 'ONTASKADD', appPath: '/api/webhooks/b24' }),
  }
)
const { success, data } = await res.json()
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on success |
| `data.id` | string (UUID) | Subscription ID |
| `data.appId` | string | ID of the OAuth application the handler is registered under |
| `data.serverId` | string (UUID) | Server ID |
| `data.portalId` | string | Bitrix24 portal ID |
| `data.event` | string | Event code |
| `data.appPath` | string | Delivery path on the application |
| `data.authType` | string | Bitrix24 ID of the user who installed the application |
| `data.b24Handler` | string | Handler URL on the platform where Bitrix24 sends the event |
| `data.status` | string | Subscription status: `ACTIVE`, `DISABLED`, `DEGRADED`. `DEGRADED` — after a series of failed deliveries |
| `data.createdById` | string \| null | ID of the Vibecode user who created the subscription |
| `data.createdAt` | string | Creation date (ISO 8601) |
| `data.updatedAt` | string | Last change date (ISO 8601) |

## Response example

```json
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "appId": "9a1c2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "serverId": "e765edfc-ba0a-43de-b8ea-838dd872c522",
    "portalId": "8b1f0e2a-3c4d-5e6f-7a8b-9c0d1e2f3a4b",
    "event": "ONTASKADD",
    "appPath": "/api/webhooks/b24",
    "authType": "1",
    "b24Handler": "https://vibecode.bitrix24.com/v1/portal-events/9a1c2b3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
    "status": "ACTIVE",
    "createdById": "7f3a1c2b-9d8e-4a6f-b1c2-3d4e5f6a7b8c",
    "createdAt": "2026-06-07T10:00:00.000Z",
    "updatedAt": "2026-06-07T10:00:00.000Z"
  }
}
```

## Error response example

400 — the server is not backed by an OAuth application:

```json
{
  "success": false,
  "error": {
    "code": "NOT_OAUTH_APP",
    "message": "Server is not backed by an OAuth app with a B24 application token"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_EVENT` | The event code is empty or does not match the format `^[A-Z][A-Z0-9_]+$` |
| 400 | `INVALID_APP_PATH` | `appPath` does not start with `/` or contains control characters |
| 400 | `NOT_OAUTH_APP` | The server is not backed by an OAuth application with an `application_token`. The response contains a `hint` field with the order for creating such a server |
| 400 | `NO_USER_TOKEN` | The application has no OAuth token — authorize the application on the portal first. The response contains a `hint` field |
| 404 | `NOT_FOUND` | The server was not found or belongs to another API key |
| 409 | `EVENT_BOUND_ELSEWHERE` | This event is already bound to another server of the same application — delete the previous subscription first |
| 502 | `BIND_FAILED` | Bitrix24 rejected the event registration — for example, the portal is not on a commercial plan |

For the full list of common API errors, see [Errors](/docs/errors).

## Known specifics

- **Calling again with the same `(server, event)` pair updates the subscription.** If a subscription for this event already exists on the same server, calling again updates `appPath` and returns `200` — suitable for re-running setup scripts.

## See also

- [Portal event subscriptions](/docs/infra/event-subscriptions)
- [List subscriptions](/docs/infra/event-subscriptions/list)
- [Application-side handler](/docs/infra/event-subscriptions/handler)
- [Keys and authorization](/docs/keys-auth)
- [Errors](/docs/errors)
