
## Статистика звонков

`GET /v1/calls/statistics`

Возвращает список записей о прошедших звонках с поддержкой фильтрации по полям, сортировки и пагинации с фиксированной страницей до 50 записей.

## Параметры

| Параметр | Тип | По умолч. | Описание |
|----------|-----|-----------|---------|
| `filter` (query) | object | — | Фильтрация по полям записи (UPPER_SNAKE_CASE). Поддерживаются операторы `>`, `>=`, `<`, `<=`, `!` в виде префикса к имени поля. Пример: `?filter[CALL_TYPE]=1`, `?filter[>CALL_START_DATE]=2026-01-01T00:00:00` |
| `sort` (query) | string | — | Поле для сортировки в UPPER_SNAKE_CASE. Пример: `CALL_START_DATE` |
| `order` (query) | string | — | Направление сортировки: `ASC` или `DESC` |
| `limit` (query) | number | `50` | Параметр совместимости; используйте `50`. Маршрут возвращает одну страницу Bitrix24 — до 50 записей |
| `offset` (query) | number | `0` | Смещение для пагинации |

Диапазон дат задаётся двумя операторами одновременно. Пример: `filter[>CALL_START_DATE]=2026-04-01T00:00:00&filter[<CALL_START_DATE]=2026-04-30T23:59:59`.

## Примеры

### curl — личный ключ

```bash
curl --globoff "https://vibecode.bitrix24.tech/v1/calls/statistics?limit=50&sort=CALL_START_DATE&order=DESC&filter[CALL_TYPE]=1" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth-приложение

```bash
curl --globoff "https://vibecode.bitrix24.tech/v1/calls/statistics?limit=50&sort=CALL_START_DATE&order=DESC&filter[CALL_TYPE]=1" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — личный ключ

```javascript
const params = new URLSearchParams({
  limit: '50',
  sort: 'CALL_START_DATE',
  order: 'DESC',
  'filter[CALL_TYPE]': '1',
})

const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/statistics?${params}`, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const { success, data, total } = await res.json()
console.log(`Найдено звонков: ${total}`)
```

### JavaScript — OAuth-приложение

```javascript
const params = new URLSearchParams({
  limit: '50',
  sort: 'CALL_START_DATE',
  order: 'DESC',
  'filter[CALL_TYPE]': '1',
})

const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/statistics?${params}`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

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

### JavaScript — перебор всех страниц

```javascript
const pageSize = 50
let offset = 0
const allCalls = []

while (true) {
  const params = new URLSearchParams({
    limit: String(pageSize),
    offset: String(offset),
    sort: 'CALL_START_DATE',
    order: 'DESC',
  })

  const res = await fetch(`https://vibecode.bitrix24.tech/v1/calls/statistics?${params}`, {
    headers: { 'X-Api-Key': 'YOUR_API_KEY' },
  })
  // total лежит в корне ответа — общее число записей под фильтром
  const { data, total } = await res.json()

  allCalls.push(...data)
  offset += data.length

  // берём следующую страницу, пока не собрали все записи
  if (offset >= total || data.length === 0) break
}

console.log(`Собрано записей: ${allCalls.length}`)
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|---------|
| `success` | boolean | Всегда `true` при успехе |
| `data` | array | Массив записей о звонках |
| `data[].id` | string | Внутренний идентификатор записи |
| `data[].portalUserId` | string | ID оператора. Список: [`GET /v1/users`](/docs/entities/users) |
| `data[].portalNumber` | string | Идентификатор линии: `reg<id>` — арендованная линия Voximplant, `sip<id>` — SIP-линия, `REST_APP:<id>` — линия через REST-приложение |
| `data[].phoneNumber` | string | Номер телефона клиента |
| `data[].callId` | string | Идентификатор звонка. Префиксы: `externalCall.` — от [`register`](../crm/register.md), `callback.` — от [обратного звонка](../outbound/callback.md), `infocall.` — от [автозвонка](../outbound/auto-call.md) |
| `data[].externalCallId` | string \| null | Внешний идентификатор, переданный при регистрации |
| `data[].callCategory` | string | Категория: `external` для звонков через REST API |
| `data[].callLog` | string \| null | URL детального лога Voximplant. `null` для звонков через REST-приложение |
| `data[].callDuration` | string | Длительность звонка в секундах (строка) |
| `data[].callStartDate` | string | Дата начала звонка, ISO 8601 с тайм-зоной портала |
| `data[].callRecordUrl` | string | URL аудиозаписи звонка |
| `data[].callVote` | string \| null | Оценка звонка от `1` до `5` |
| `data[].cost` | string | Стоимость звонка (десятичная строка) |
| `data[].costCurrency` | string | Код валюты (`RUR` и др.) |
| `data[].callFailedCode` | string | Код результата: `200` — успех, `603-S` — отменён, `304` — пропущен, `500` — ошибка сценария, `402` — недостаточно средств, `403` — запрещено |
| `data[].callFailedReason` | string | Текстовая причина результата |
| `data[].crmEntityType` | string | Тип привязанной CRM-сущности: `LEAD`, `CONTACT` или пустая строка. Источник: [лиды](/docs/entities/leads), [контакты](/docs/entities/contacts) |
| `data[].crmEntityId` | string | ID привязанной CRM-сущности |
| `data[].crmActivityId` | string | ID CRM-активности. `"0"` — активность не создана |
| `data[].restAppId` | string \| null | ID приложения-инициатора звонка |
| `data[].restAppName` | string \| null | Название приложения-инициатора звонка |
| `data[].transcriptId` | string \| null | ID прикреплённой транскрипции. Прикрепить: [`POST /v1/calls/:callId/transcription`](../crm/transcription.md) |
| `data[].transcriptPending` | string | `Y` — транскрипция в обработке, `N` — транскрипция готова или отсутствует |
| `data[].sessionId` | string | Идентификатор сессии Voximplant |
| `data[].redialAttempt` | string \| null | Номер попытки перенабора |
| `data[].comment` | string \| null | Комментарий оператора |
| `data[].recordDuration` | string \| null | Длительность записи разговора в секундах |
| `data[].recordFileId` | string \| null | ID файла записи на Диске |
| `data[].callType` | string | Тип звонка: `"1"` — исходящий, `"2"` — входящий, `"3"` — входящий с перенаправлением, `"4"` — [обратный звонок](../outbound/callback.md), `"5"` — информационный ([автозвонок](../outbound/auto-call.md)) |
| `total` | number | Общее количество записей, соответствующих фильтру |

## Пример ответа

```json
{
  "success": true,
  "data": [
    {
      "id": "1",
      "portalUserId": "1",
      "portalNumber": "reg133788",
      "phoneNumber": "+79638835976",
      "callId": "11018129443EB80D.1754478520.11438214",
      "externalCallId": null,
      "callCategory": "external",
      "callLog": "https://storage-gw-ru-02.voximplant.com/voximplant-logs/2025/08/06/...",
      "callDuration": "0",
      "callStartDate": "2025-08-06T14:08:40+03:00",
      "callRecordUrl": "",
      "callVote": null,
      "cost": "0.0000",
      "costCurrency": "RUR",
      "callFailedCode": "603-S",
      "callFailedReason": "Decline self",
      "crmEntityType": "CONTACT",
      "crmEntityId": "275",
      "crmActivityId": "7739",
      "restAppId": null,
      "restAppName": null,
      "transcriptId": null,
      "transcriptPending": "N",
      "sessionId": "3841557776",
      "redialAttempt": null,
      "comment": null,
      "recordDuration": null,
      "recordFileId": null,
      "callType": "1"
    }
  ],
  "total": 30
}
```

## Пример ответа при ошибке

403 — нет скоупа `telephony`:

```json
{
  "success": false,
  "error": {
    "code": "SCOPE_DENIED",
    "message": "This endpoint requires 'telephony' scope"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Неверный API-ключ |
| 401 | `TOKEN_MISSING` | Ключ не имеет настроенных токенов Битрикс24 |
| 401 | `KEY_INACTIVE` | API-ключ неактивен или отозван |
| 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `telephony` |
| 422 | `BITRIX_ERROR` | Битрикс24 вернул ошибку (текст в `error.message`) |
| 429 | `RATE_LIMITED` | Превышен лимит запросов |
| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Известные особенности

**Имена полей в фильтре и сортировке — UPPER_SNAKE_CASE, а в ответе — camelCase.** Параметры `filter` и `sort` принимают исходные имена Битрикс24 (`CALL_TYPE`, `CALL_START_DATE`), а поля ответа приходят в camelCase (`callType`, `callStartDate`). Фильтр по camelCase-имени молча игнорируется — возвращаются все записи.

**`total` находится в корне ответа.** В отличие от других list-эндпоинтов Вайбкод, поле `total` расположено непосредственно в корне ответа, а не в `meta.total`.

**Фильтр по несуществующему полю** не возвращает ошибку — некорректное имя поля молча игнорируется и возвращаются все записи.

## Смотрите также

- [Зарегистрировать звонок](../crm/register.md)
- [Обратный звонок](../outbound/callback.md)
- [Автозвонок с синтезом речи](../outbound/auto-call.md)
- [Автозвонок с аудиофайлом](../outbound/auto-call-audio.md)
- [Справочник голосов](./voices.md)
- [Лиды](/docs/entities/leads)
- [Контакты](/docs/entities/contacts)
- [Телефония — обзор](/docs/telephony)
