# История стадий

`GET /v1/stage-history`

Возвращает историю переходов CRM-записей по стадиям и статусам — когда запись попала на каждую стадию воронки. Применяется для отчётов по скорости движения сделок и лидов и для анализа конверсии по воронкам.

Битрикс24 API: `crm.stagehistory.list`
Скоуп: `crm`

## Параметры

Набор полей фильтра по стадии зависит от типа записи. Для stage-типов `deal` и `invoice` доступны `stageId`, `stageSemanticId`, `categoryId`. Для status-типа `lead` доступны `statusId`, `statusSemanticId`. Поле не от своего типа возвращает `400 INVALID_FILTER_FIELD`.

| Параметр | Тип | Обяз. | По умолч. | Описание |
|----------|-----|:-----:|-----------|----------|
| `entityType` (query) | string | нет | `deal` | Тип CRM-записи: `deal`, `lead`, `invoice` — счёт |
| `ownerId` (query) | number | нет | — | Идентификатор записи, чью историю переходов вернуть. Зависит от `entityType`. Источники: `GET /v1/deals`, `GET /v1/leads`, `GET /v1/invoices` |
| `typeId` (query) | number | нет | — | Тип перехода: `1` — создание записи, `2` — перевод на промежуточную стадию, `3` — перевод на финальную стадию, `5` — смена воронки |
| `createdAfter` (query) | string | нет | — | Переходы начиная с указанного момента включительно (ISO 8601) |
| `createdBefore` (query) | string | нет | — | Переходы до указанного момента включительно (ISO 8601) |
| `stageId` (query) | string | нет | — | Только `deal`, `invoice`. Фильтр по стадии. Список: `GET /v1/statuses?filter[entityId]=DEAL_STAGE` |
| `stageSemanticId` (query) | string | нет | — | Только `deal`, `invoice`. Семантика стадии: `P` — промежуточная, `S` — успешная, `F` — провальная |
| `categoryId` (query) | number | нет | — | Только `deal`, `invoice`. Идентификатор воронки. Список: `GET /v1/deal-categories` |
| `statusId` (query) | string | нет | — | Только `lead`. Фильтр по статусу. Список: `GET /v1/statuses?filter[entityId]=STATUS` |
| `statusSemanticId` (query) | string | нет | — | Только `lead`. Семантика статуса: `P` — промежуточный, `S` — успешный, `F` — провальный |
| `limit` (query) | number | нет | `50` | Количество записей за вызов. Максимум `5000` |
| `offset` (query) | number | нет | `0` | Сдвиг выборки. Округляется вниз до кратного `50` |

Для `limit > 50` Вайбкод автоматически пагинирует запрос на стороне сервера. Максимум — 5000 записей за вызов. Поле `meta.hasMore` показывает, есть ли записи за пределами текущей выборки.

## Примеры

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

```bash
curl "https://vibecode.bitrix24.tech/v1/stage-history?entityType=deal&limit=50" \
  -H "X-Api-Key: YOUR_API_KEY"
```

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

```bash
curl "https://vibecode.bitrix24.tech/v1/stage-history?entityType=deal&limit=50" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

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

```javascript
const params = new URLSearchParams({ entityType: 'deal', limit: '50' })
const res = await fetch(`https://vibecode.bitrix24.tech/v1/stage-history?${params}`, {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

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

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

```javascript
const params = new URLSearchParams({ entityType: 'deal', limit: '50' })
const res = await fetch(`https://vibecode.bitrix24.tech/v1/stage-history?${params}`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

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

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

Состав полей записи зависит от типа: stage-типы `deal` и `invoice` возвращают `stageId`, `stageSemanticId`, `categoryId`, а status-тип `lead` — `statusId`, `statusSemanticId`.

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data` | array | Массив записей истории, от новых к старым |
| `data[].id` | number | Идентификатор записи истории |
| `data[].typeId` | number | Тип перехода: `1` — создание, `2` — промежуточная стадия, `3` — финальная стадия, `5` — смена воронки |
| `data[].ownerId` | number | Идентификатор записи, в которой произошёл переход |
| `data[].createdAt` | string | Момент перехода на стадию (ISO 8601) |
| `data[].stageId` | string | Стадия. Только `deal`, `invoice` |
| `data[].stageSemanticId` | string | Семантика стадии: `P`, `S`, `F`. Только `deal`, `invoice` |
| `data[].categoryId` | number | Воронка. Только `deal`, `invoice` |
| `data[].statusId` | string | Статус. Только `lead` |
| `data[].statusSemanticId` | string | Семантика статуса: `P`, `S`, `F`. Только `lead` |
| `meta.total` | number | Общее количество записей под фильтром |
| `meta.hasMore` | boolean | Есть ли записи за пределами текущей выборки |

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

Сделка (`entityType=deal`) — переходы по стадиям воронки:

```json
{
  "success": true,
  "data": [
    {
      "id": 12857,
      "typeId": 1,
      "ownerId": 7913,
      "createdAt": "2026-06-24T00:03:50+03:00",
      "categoryId": 9,
      "stageSemanticId": "P",
      "stageId": "C9:NEW"
    },
    {
      "id": 12855,
      "typeId": 1,
      "ownerId": 7911,
      "createdAt": "2026-06-23T00:02:34+03:00",
      "categoryId": 9,
      "stageSemanticId": "P",
      "stageId": "C9:NEW"
    }
  ],
  "meta": {
    "total": 2941,
    "hasMore": true
  }
}
```

Лид (`entityType=lead`) — переходы по статусам:

```json
{
  "success": true,
  "data": [
    {
      "id": 3689,
      "typeId": 1,
      "ownerId": 1001083,
      "createdAt": "2026-06-10T18:03:12+03:00",
      "statusId": "NEW",
      "statusSemanticId": "P"
    }
  ],
  "meta": {
    "total": 296,
    "hasMore": true
  }
}
```

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

400 — поле фильтра не подходит для типа записи:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_FILTER_FIELD",
    "message": "\"statusId\" is not a valid filter for entityType \"deal\". entityType \"deal\" is stage-based — use stageId."
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `INVALID_ENTITY_TYPE` | Неизвестный `entityType`. Сообщение содержит список поддерживаемых значений |
| 400 | `INVALID_FILTER_FIELD` | Поле фильтра не подходит для указанного `entityType` — например `statusId` для `deal` |
| 403 | `SCOPE_DENIED` | Ключу не хватает скоупа `crm` |
| 401 | `TOKEN_MISSING` | У ключа не настроены токены доступа |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |

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

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

**Сортировка не настраивается.** Параметр сортировки не принимается — порядок записей изменить нельзя.

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

- [Сделки](/docs/entities/deals)
- [Лиды](/docs/entities/leads)
- [Статусы и стадии](/docs/entities/statuses)
- [Воронки сделок](/docs/entities/deal-categories)
- [Справочник сущностей](/docs/entity-api)
- [Ошибки](/docs/errors)
