## Карточки менеджерского ревью

`GET /v1/performan/review/manager/reviews`

Возвращает карточки менеджерского этапа кампании, где владелец ключа выступает оценивающим: ответы, статус, итоговую оценку и шкалу. Идентификатор карточки из ответа — это `relationId` для записи ответа.

## Параметры

| Параметр | Тип | Обяз. | По умолч. | Описание |
|----------|-----|:-----:|-----------|----------|
| `campaignId` (query) | number | да | — | Идентификатор кампании. Список кампаний — [`GET /v1/performan/review/campaigns`](./campaigns.md) |
| `revieweeUserId` (query) | number | нет | — | Сузить выдачу до одного оцениваемого сотрудника. Список сотрудников — `GET /v1/users` |
| `limit` (query) | number | нет | 50 | Записей на страницу, максимум 200 |
| `afterCursorId` (query) | number | нет | — | Курсор следующей страницы. Значение берётся из `meta.nextCursor.id` предыдущего ответа. В первом запросе не передаётся |

## Навигация

1. Первый запрос идёт без `afterCursorId` — приходит первая страница.
2. Значение `meta.nextCursor.id` из ответа передаётся параметром `afterCursorId` следующего запроса. Курсор копируется целиком, собирать его из полей записи нельзя.
3. Ответ, у которого `meta.nextCursor` равен `null`, означает конец выдачи. Параметра `offset` и общего количества записей у метода нет.

## Примеры

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

```bash
curl "https://vibecode.bitrix24.tech/v1/performan/review/manager/reviews?campaignId=1&revieweeUserId=42" \
  -H "X-Api-Key: YOUR_API_KEY"
```

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

```bash
curl "https://vibecode.bitrix24.tech/v1/performan/review/manager/reviews?campaignId=1&revieweeUserId=42" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/performan/review/manager/reviews?campaignId=1&revieweeUserId=42', {
  headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})

const body = await res.json()

if (!body.success) {
  throw new Error(`${body.error.code}: ${body.error.message}`)
}

for (const card of body.data) {
  // id карточки — это relationId в теле записи ответа
  console.log(card.id, card.revieweeUserName, card.status, card.rate)
}

console.log(body.meta.nextCursor)
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/performan/review/manager/reviews?campaignId=1&revieweeUserId=42', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const body = await res.json()

if (!body.success) {
  throw new Error(`${body.error.code}: ${body.error.message}`)
}

console.log(body.data, body.meta.nextCursor)
```

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

| Поле | Тип | Описание |
|------|-----|---------|
| `success` | boolean | Всегда `true` при успехе |
| `data` | array | Массив карточек менеджерского ревью |
| `data[].id` | number | Идентификатор карточки. Он же `relationId` в теле [записи ответа](./manager-answer.md) — в адресе метода его нет |
| `data[].campaignId` | number | Кампания карточки. Список — [`GET /v1/performan/review/campaigns`](./campaigns.md) |
| `data[].campaignStageId` | number | Этап кампании, к которому относится карточка |
| `data[].stageType` | string | Тип этапа. У этого метода — `managersReview` |
| `data[].revieweeUserId` | number | Оцениваемый сотрудник. Карточка сотрудника — `GET /v1/users/:id` |
| `data[].revieweeUserName` | string | Имя оцениваемого сотрудника |
| `data[].reviewerUserId` | number | Оценивающий сотрудник. На менеджерском этапе совпадает с `managerUserId` |
| `data[].reviewerUserName` | string | Имя оценивающего сотрудника |
| `data[].managerUserId` | number | Руководитель оцениваемого. Карточка сотрудника — `GET /v1/users/:id` |
| `data[].managerUserName` | string | Имя руководителя |
| `data[].status` | string | Состояние карточки: `new` — не заполнена, `completed` — завершена, `rejected` — отклонена, `published` — опубликована |
| `data[].rate` | number | Итоговая оценка по рейтинговому вопросу. `0` — оценка не выставлена |
| `data[].comment` | string | Комментарий к карточке |
| `data[].answers` | array | Ответы по вопросам этапа. У незаполненной карточки массив пустой |
| `data[].answers[].questionId` | number | Идентификатор вопроса. Список вопросов — [`GET /v1/performan/review/manager/questions`](./manager-questions.md) |
| `data[].answers[].questionTitle` | string | Формулировка вопроса |
| `data[].answers[].questionDescription` | string | Пояснение к вопросу |
| `data[].answers[].questionType` | string | Тип вопроса строкой: `1` — одиночный выбор, `2` — множественный выбор, `3` — текстовый ответ |
| `data[].answers[].questionTypeLabel` | string | Название типа вопроса на языке портала |
| `data[].answers[].isRating` | boolean | Формирует ли ответ итоговую оценку карточки |
| `data[].answers[].answerText` | string | Текст ответа. У вопроса с выбором варианта пустой |
| `data[].answers[].selectedOptions` | array | Выбранные варианты. У текстового вопроса массив пустой |
| `data[].answers[].selectedOptions[].id` | number | Идентификатор варианта |
| `data[].answers[].selectedOptions[].text` | string | Текст варианта |
| `data[].answers[].selectedOptions[].value` | number | Числовое значение варианта, по нему считается `rate` |
| `data[].ratingScale` | array | Шкала оценки этапа |
| `data[].ratingScale[].value` | number | Значение шкалы |
| `data[].ratingScale[].label` | string | Подпись значения |
| `meta.nextCursor` | object \| null | Курсор следующей страницы. `null` — записей больше нет |
| `meta.nextCursor.id` | number | Значение для параметра `afterCursorId` следующего запроса |

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

Завершённая карточка: заполнены текстовые ответы и рейтинговый вопрос, `rate` выведен из значения выбранного варианта.

```json
{
  "success": true,
  "data": [
    {
      "id": 4,
      "campaignId": 1,
      "campaignStageId": 5,
      "stageType": "managersReview",
      "revieweeUserId": 42,
      "revieweeUserName": "Мария Иванова",
      "reviewerUserId": 7,
      "reviewerUserName": "Иван Петров",
      "managerUserId": 7,
      "managerUserName": "Иван Петров",
      "status": "completed",
      "rate": 4,
      "comment": "",
      "answers": [
        {
          "questionId": 15,
          "questionTitle": "Ключевые результаты и выполнение целей",
          "questionDescription": "",
          "questionType": "3",
          "questionTypeLabel": "Текстовый ответ",
          "isRating": false,
          "answerText": "Закрыл цели квартала",
          "selectedOptions": []
        },
        {
          "questionId": 21,
          "questionTitle": "Итоговая оценка",
          "questionDescription": "",
          "questionType": "1",
          "questionTypeLabel": "Одиночный выбор",
          "isRating": true,
          "answerText": "",
          "selectedOptions": [
            { "id": 18, "text": "Выше ожиданий", "value": 4 }
          ]
        }
      ],
      "ratingScale": [
        { "value": 1, "label": "Значительно ниже ожиданий" },
        { "value": 2, "label": "Ниже ожиданий" },
        { "value": 3, "label": "Соответствует ожиданиям" },
        { "value": 4, "label": "Выше ожиданий" },
        { "value": 5, "label": "Значительно выше ожиданий" }
      ]
    }
  ],
  "meta": { "nextCursor": null }
}
```

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

400 — не передан обязательный параметр:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "`campaignId` is required and must be a positive integer"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|---------|
| 400 | `INVALID_PARAMS` | Не передан `campaignId` либо значение `campaignId`, `revieweeUserId` или `afterCursorId` не является положительным целым числом либо `limit` выходит за диапазон 1–200 |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `TOKEN_MISSING` | У ключа нет токенов портала. Ключ OAuth-приложения требует заголовок `Authorization: Bearer` |
| 403 | `SCOPE_DENIED` | У ключа нет скоупа `performan` |
| 404 | `ROUTE_NOT_FOUND` | Раздел «Перформанс ревью» порталу не включён. Ответ неотличим от ответа на любой несуществующий адрес |
| 404 | `ENTITY_NOT_FOUND` | Раздел включён, но модуля «Перформанс ревью» на портале нет: Битрикс24 отвечает «Метод `performan.review.*` не найден» |
| 403 | `BITRIX_ACCESS_DENIED` | Битрикс24 отказал в доступе. Набор прав, с которым ключ обращается к порталу, не содержит `performan` |
| 409 | `PERFORMAN_SCOPE_JUST_GRANTED` | Ключу Коворка выдан скоуп `performan` этим же запросом. Повторите запрос — он пройдёт |
| 422 | `BITRIX_ERROR` | Битрикс24 отклонил запрос. Причина — в `error.message`, машинный код Битрикс24 — в `error.b24Code` |
| 429 | `RATE_LIMITED` | Превышена частота запросов на стороне Битрикс24 |
| 429 | `QUEUE_OVERFLOW`, `QUEUE_TIMEOUT` | Очередь запросов портала переполнена или запрос не дождался очереди. Заголовок `Retry-After` подсказывает задержку |
| 503 | `BITRIX_TIMEOUT` | Битрикс24 принял запрос, но не ответил за отведённое время. Для чтения повтор безопасен |
| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен |

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

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

**Неизвестные параметры строки запроса игнорируются.** Метод читает `campaignId`, `revieweeUserId`, `limit` и `afterCursorId`, остальные отбрасывает без ошибки: запрос с опечаткой в имени параметра отвечает `200` и несуженным списком.

**Только карточки подчинённых, которых оцениваете вы.** Метод отдаёт карточки, где владелец ключа записан в `reviewerUserId`. Оценки, которые ставят ему самому, в ответ не попадают. Пустой массив `data` означает, что оценивать в этой кампании ему некого.

**Фильтр по оцениваемому не проверяет, существует ли сотрудник.** Значение `revieweeUserId`, по которому у владельца ключа нет карточки, даёт `200` с пустым `data`, а не отказ.

**Хэш состояния карточки метод не возвращает.** Значение `expectedStateHash` для оптимистичной блокировки приходит только в ответе на запись, поэтому первый вызов [`POST /v1/performan/review/manager/answers`](./manager-answer.md) по карточке идёт без него.

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

- [Ответ менеджера](/docs/performan/manager-answer)
- [Вопросы менеджерского этапа](/docs/performan/manager-questions)
- [Кампании ревью](/docs/performan/campaigns)
- [Операции перформанс-ревью](/docs/performan/endpoints)
- [Ошибки](/docs/errors)
