
## Finish a call

`POST /v1/calls/:callId/finish`

Finishes a registered call: records the duration and the final status, and creates an activity in the linked CRM entity. Call it after the conversation ends, before attaching a transcription.

## Parameters

| Parameter | In | Type | Required | Description |
|----------|---|-----|:-----:|---------|
| `callId` | path | string | yes | `callId` from the [`POST /v1/calls/register`](./register.md) response |

## Request fields (body)

| Parameter | Type | Required | Default | Description |
|----------|-----|:-----:|-----------|---------|
| `userId` | number | yes | — | ID of the Bitrix24 user who finished the call. A positive integer. A numeric string such as `"42"` is also accepted. [Employees](/docs/entities/users) |
| `duration` | number | yes | — | Call duration in seconds. A non-negative number. A numeric string is also accepted |
| `statusCode` | string | no | `"200"` when duration > 0, otherwise `"304"` | Completion code: `"200"` success, `"304"` missed, `"403"` forbidden, `"486"` busy, `"603"` declined, `"603-S"` cancelled by the client, `"402"` insufficient funds, `"404"` invalid number, `"423"` blocked, `"480"` temporarily unavailable, `"484"` / `"503"` destination unavailable, `"OTHER"` |
| `add_to_chat` | boolean | no | — | Add a call event to the employee's chat |
| `vote` | number | no | — | Call rating: `1`–`5`. Lands in the `CALL_VOTE` field (rating / stars) of the [Call statistics](/docs/telephony/analytics/statistics) section. The UPPER form `VOTE` is also accepted |

## Examples

### curl — personal key

```bash
curl -X POST https://vibecode.bitrix24.com/v1/calls/CALL_ID/finish \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "duration": 120,
    "statusCode": "200"
  }'
```

### curl — OAuth application

```bash
curl -X POST https://vibecode.bitrix24.com/v1/calls/CALL_ID/finish \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "userId": 1,
    "duration": 120,
    "statusCode": "200"
  }'
```

### JavaScript — personal key

```javascript
const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304'

const res = await fetch(`https://vibecode.bitrix24.com/v1/calls/${callId}/finish`, {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    userId: 1,
    duration: 120,
    statusCode: '200',
  }),
})

const { success, data } = await res.json()
console.log('Activity:', data.crmActivityId)
```

### JavaScript — OAuth application

```javascript
const callId = 'externalCall.00b1e735843c558431be668e3687a58b.1777974304'

const res = await fetch(`https://vibecode.bitrix24.com/v1/calls/${callId}/finish`, {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    userId: 1,
    duration: 120,
    statusCode: '200',
  }),
})

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

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `callId` | string | Call identifier |
| `externalCallId` | string \| null | External identifier passed at registration |
| `portalUserId` | number | Bitrix24 user ID |
| `phoneNumber` | string | Phone number |
| `portalNumber` | string | Line number in the Bitrix24 account |
| `incoming` | string | Call type: `"1"` — outbound, `"2"` — inbound, `"3"` — inbound with redirection, `"4"` — callback, `"5"` — informational |
| `callDuration` | number | Duration in seconds |
| `callStartDate` | object | Call start date. Returned as an empty object `{}` — see [specifics](#known-specifics) |
| `callStatus` | number | Completion status |
| `callVote` | number | Call rating |
| `cost` | number | Call cost |
| `costCurrency` | string | Cost currency |
| `callFailedCode` | string | The passed `statusCode` |
| `callFailedReason` | string | Text description of the completion reason |
| `restAppId` | number \| null | Application ID |
| `restAppName` | string \| false | Application name |
| `crmActivityId` | number \| false | ID of the created activity. `false` if no entity is linked |
| `comment` | string \| null | Comment on the call |
| `id` | number | Internal ID of the call record |
| `ERRORS` | object \| null | Errors that did not interrupt completion (e.g. `ACTIVITY_CREATION`) |
| `crmEntityType` | string | Type of the linked CRM entity (only when a link exists) |
| `crmEntityId` | number | ID of the linked CRM entity (only when a link exists) |

## Response example

HTTP 200 — the call is finished and the activity is created:

```json
{
  "success": true,
  "data": {
    "callId": "externalCall.00b1e735843c558431be668e3687a58b.1777974304",
    "externalCallId": null,
    "portalUserId": 1,
    "phoneNumber": "+12025550123",
    "portalNumber": "REST_APP:",
    "incoming": "2",
    "callDuration": 120,
    "callStartDate": {},
    "callStatus": 1,
    "callVote": 0,
    "cost": 0,
    "costCurrency": "",
    "callFailedCode": "200",
    "callFailedReason": "",
    "restAppId": null,
    "restAppName": false,
    "crmActivityId": 7995,
    "comment": null,
    "crmEntityType": "LEAD",
    "crmEntityId": 1001069,
    "id": 61
  }
}
```

## Error response example

400 — required parameters are missing:

```json
{
  "success": false,
  "error": {
    "code": "MISSING_PARAMS",
    "message": "Required: userId (positive integer), duration (number ≥ 0, seconds)"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `MISSING_PARAMS` | `userId` is missing or is not recognized as a positive integer, or `duration` is missing or is not recognized as a non-negative number |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is missing |
| 401 | `INVALID_API_KEY` | Invalid API key |
| 401 | `TOKEN_MISSING` | The API key has no Bitrix24 tokens configured |
| 401 | `KEY_INACTIVE` | The API key is inactive or revoked |
| 403 | `SCOPE_DENIED` | The key is missing the `telephony` scope |
| 422 | `BITRIX_ERROR` | Bitrix24 returned an error (text in `error.message`) |
| 429 | `RATE_LIMITED` | Request limit exceeded |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 is unavailable |

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

## Known specifics

**`callStartDate` is always returned as an empty object `{}`.** See the actual call start date in the [statistics](/docs/telephony/analytics/statistics).

**`CRM_ACTIVITY_ID: false` when no link exists.** The `ERRORS.ACTIVITY_CREATION` field returns a text description of the reason. The call is still considered finished.

**The `statusCode` value affects the label in CRM.** Passing it explicitly lets you record the completion reason independently of the duration.

## See also

- [Register a call](./register.md)
- [Attach a transcription](./transcription.md)
- [Show the card](./show.md)
- [Call statistics](/docs/telephony/analytics/statistics) — start date and other fields
- [Leads](/docs/entities/leads) — CRM entity created at registration
- [Contacts](/docs/entities/contacts) — CRM entity a call can be linked to
- [Deals](/docs/entities/deals) — the call lands in the timeline of the linked deal
