## Получить месячный отчёт об отсутствиях

`GET /v1/workday/time-control/reports`

Возвращает месячный отчёт контроля рабочего времени по сотруднику: рабочие дни, отработанное время и отсутствия с объяснениями. Вызывайте, чтобы найти отсутствие и объяснить его или проверить, сколько сотрудник отработал за месяц.

Требуется скоуп `timeman`. Права проверяются у владельца учётных данных: для личного ключа это владелец ключа, для ключа приложения — пользователь, чей токен сессии передан в `Authorization`. Доступ к отчётам задают роль и [настройки контроля времени](/docs/workday/time-control-settings-list): администратор и сотрудник с полным отчётом получают отчёт любого сотрудника, руководитель — отчёты сотрудников своих подразделений, сотрудник с простым отчётом — только свой. Какие отчёты доступны владельцу учётных данных, показывает поле `reportViewType` на странице [Получить настройки отчёта контроля времени](/docs/workday/time-control-report-settings). Пока контроль рабочего времени выключен, сотрудник без подчинённых получает `403 BITRIX_ACCESS_DENIED` даже на свой отчёт. Ключ READONLY может читать отчёт.

## Параметры

| Параметр | Тип | Обяз. | По умолч. | Описание |
|----------|-----|:-----:|-----------|----------|
| `userId` (query) | integer | да | — | ID сотрудника, положительное целое. Свой ID — поле `userId` в [настройках отчёта контроля времени](/docs/workday/time-control-report-settings), сотрудники подразделения — [`GET /v1/workday/time-control/users`](/docs/workday/time-control-users) |
| `month` (query) | integer | да | — | Месяц, от 1 до 12 |
| `year` (query) | integer | да | — | Год, положительное целое |
| `idleMinutes` (query) | number | нет | `minimumIdleForReport` из настроек | Перерыв в минутах, начиная с которого он считается отсутствием. Учитывается в запросе руководителя или администратора, в запросе сотрудника игнорируется |
| `workdayHours` (query) | number | нет | `8` | Длина рабочего дня в часах, по ней считаются недоработка и переработка |

## Примеры

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

```bash
curl "https://vibecode.bitrix24.tech/v1/workday/time-control/reports?userId=503&month=5&year=2026" \
  -H "X-Api-Key: YOUR_API_KEY"
```

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

```bash
curl "https://vibecode.bitrix24.tech/v1/workday/time-control/reports?userId=503&month=5&year=2026" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/workday/time-control/reports?userId=503&month=5&year=2026', {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})
const { data } = await res.json()
```

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

```javascript
const res = await fetch('https://vibecode.bitrix24.tech/v1/workday/time-control/reports?userId=503&month=5&year=2026', {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})
const { data } = await res.json()
```

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

Даты приходят в формате ISO 8601 с часовым поясом, длительности — в секундах.

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | `true` при успешном запросе |
| `data.report` | object | Отчёт за месяц |
| `data.report.monthTitle` | string | Название месяца |
| `data.report.dateStart` | string | Начало месяца |
| `data.report.dateFinish` | string | Конец месяца |
| `data.report.days` | array | Дни, в которые сотрудник открывал рабочий день. Для существующего сотрудника пустой массив значит, что данных учёта за месяц нет: сотрудник не открывал рабочий день или контроль рабочего времени на портале не настроен. Проверить: поле `active` в [настройках контроля времени](/docs/workday/time-control-settings-list) |
| `data.report.days[].index` | string | Дата дня в формате `ГГГГММДД` |
| `data.report.days[].dayTitle` | string | Дата дня в формате портала |
| `data.report.days[].workdayDateStart` | string | Начало рабочего дня |
| `data.report.days[].workdayDateFinish` | string | Конец рабочего дня. Если день ещё открыт — время построения отчёта |
| `data.report.days[].workdayComplete` | boolean | Закрыт ли рабочий день |
| `data.report.days[].workdayDuration` | integer | Длительность рабочего дня вместе с перерывами |
| `data.report.days[].workdayDurationFinal` | integer | Отработанное время без перерывов, личных и необъяснённых отсутствий |
| `data.report.days[].workdayDurationConfig` | integer | Длительность рабочего дня по `workdayHours` |
| `data.report.days[].workdayTimeLeaksUser` | integer | Перерывы, которые сотрудник отметил сам |
| `data.report.days[].workdayTimeLeaksReal` | integer | Перерывы по данным автоматического учёта вместе с личными и необъяснёнными отсутствиями |
| `data.report.days[].workdayTimeLeaksFinal` | integer | Недоработка — положительное число или переработка — отрицательное |
| `data.report.days[].reports` | array | Отсутствия и события рабочего дня |
| `data.report.days[].reports[].id` | string | ID записи. Для отсутствия подходит для `absenceId` в [объяснении отсутствия](/docs/workday/time-control-explain) |
| `data.report.days[].reports[].userId` | string | ID сотрудника |
| `data.report.days[].reports[].type` | string | Тип записи: `IDLE` — сотрудник отошёл, `OFFLINE` — не в сети, `TM_START`, `TM_PAUSE`, `TM_CONTINUE`, `TM_END` — начало, пауза, продолжение и конец рабочего дня, `DESKTOP_ONLINE`, `DESKTOP_OFFLINE`, `DESKTOP_START` — работа приложения Битрикс24 для компьютера. Три последних типа видит только руководитель |
| `data.report.days[].reports[].dateStart` | string | Начало записи |
| `data.report.days[].reports[].dateFinish` | string | Конец записи. Если запись активна — время построения отчёта |
| `data.report.days[].reports[].duration` | integer | Длительность записи |
| `data.report.days[].reports[].active` | boolean | Продолжается ли запись сейчас |
| `data.report.days[].reports[].entryId` | string | ID рабочего дня, к которому относится запись |
| `data.report.days[].reports[].reportType` | string | Тип объяснения: `WORK` — рабочее, `PRIVATE` — личное. Другое значение — объяснения нет, отсутствие считается личным |
| `data.report.days[].reports[].reportText` | string | Текст объяснения |
| `data.report.days[].reports[].systemText` | string \| null | Причина, которую указал портал. Видит только руководитель |
| `data.report.days[].reports[].sourceStart` | string | Источник начала записи: `TM_EVENT` — действие с рабочим днём, `IDLE_EVENT` — статус «Отошёл», `ONLINE_EVENT` — вход на портал, `OFFLINE_AGENT` — переход в статус «Не в сети», `DESKTOP_ONLINE_EVENT`, `DESKTOP_START_EVENT`, `DESKTOP_OFFLINE_AGENT` — включение и выключение приложения для компьютера |
| `data.report.days[].reports[].sourceFinish` | string | Источник конца записи, значения как у `sourceStart` |
| `data.report.days[].reports[].ipStart` | string | IP-адрес в начале записи. Видит только руководитель |
| `data.report.days[].reports[].ipFinish` | string | IP-адрес в конце записи. Видит только руководитель |
| `data.report.days[].reports[].ipStartNetwork` | boolean \| object | `false`, если IP-адрес начала записи входит в офисную сеть, иначе объект с полями `ip`, `range` и `name` — адрес, диапазон и название диапазона. Видит только руководитель |
| `data.report.days[].reports[].ipFinishNetwork` | boolean \| object | То же для конца записи |
| `data.user` | object \| false | Сотрудник, по которому построен отчёт, или `false`, если сотрудника нет. Поля `data.user.*` ниже приходят только для объекта сотрудника |
| `data.user.id` | integer | ID сотрудника |
| `data.user.active` | boolean | Активен ли сотрудник |
| `data.user.name` | string | Имя и фамилия |
| `data.user.firstName` | string | Имя |
| `data.user.lastName` | string | Фамилия |
| `data.user.workPosition` | string | Должность |
| `data.user.avatar` | string | Адрес фотографии профиля. Пустая строка, если фотографии нет |
| `data.user.personalGender` | string | Пол: `M` или `F` |
| `data.user.lastActivityDate` | string | Время последней активности на портале |

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

Ответ руководителю, один рабочий день:

```json
{
  "success": true,
  "data": {
    "report": {
      "monthTitle": "Май",
      "dateStart": "2026-05-01T00:00:00+03:00",
      "dateFinish": "2026-05-31T23:59:59+03:00",
      "days": [
        {
          "index": "20260526",
          "dayTitle": "26.05.2026",
          "workdayDateStart": "2026-05-26T09:02:11+03:00",
          "workdayDateFinish": "2026-05-26T18:05:40+03:00",
          "workdayComplete": true,
          "workdayTimeLeaksUser": 3600,
          "workdayTimeLeaksFinal": -9,
          "workdayDuration": 32609,
          "workdayDurationFinal": 28809,
          "workdayDurationConfig": 28800,
          "workdayTimeLeaksReal": 3800,
          "reports": [
            {
              "id": "153",
              "userId": "503",
              "type": "IDLE",
              "dateStart": "2026-05-26T14:10:05+03:00",
              "dateFinish": "2026-05-26T14:30:12+03:00",
              "duration": 1207,
              "active": false,
              "entryId": "2237",
              "reportType": "WORK",
              "reportText": "Встреча с клиентом",
              "systemText": null,
              "sourceStart": "IDLE_EVENT",
              "sourceFinish": "IDLE_EVENT",
              "ipStart": "203.0.113.24",
              "ipFinish": "203.0.113.24",
              "ipStartNetwork": false,
              "ipFinishNetwork": false
            }
          ]
        }
      ]
    },
    "user": {
      "id": 503,
      "active": true,
      "name": "Анна Смирнова",
      "firstName": "Анна",
      "lastName": "Смирнова",
      "workPosition": "Менеджер",
      "avatar": "",
      "personalGender": "F",
      "lastActivityDate": "2026-05-29T17:15:56+03:00"
    }
  }
}
```

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

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

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "userId, month (1..12), year are required; optional thresholds must be numeric"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `INVALID_PARAMS` | `userId`, `month` или `year` не переданы или не положительные целые, `month` больше 12, `idleMinutes` или `workdayHours` не число |
| 403 | `BITRIX_ACCESS_DENIED` | Роль и настройки контроля времени не дают владельцу учётных данных доступа к отчёту этого сотрудника: сотрудник с простым отчётом запросил чужой отчёт, руководитель без полного отчёта — отчёт сотрудника не из своего подразделения, сотрудник без подчинённых — свой отчёт при выключенном контроле рабочего времени |
| 409 | `TIMEMAN_MODULE_NOT_ENABLED` | Учёт рабочего времени недоступен на портале: инструмент «Рабочее время и отчёты» выключен в настройках портала или модуль не входит в тариф |
| 502 | `BITRIX_UNAVAILABLE` | Битрикс24 недоступен или вернул ответ неожиданной формы |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `TOKEN_MISSING` | Ключ приложения передан без токена сессии в `Authorization: Bearer` |
| 401 | `INVALID_SESSION` | Токен сессии неверный или истёк |
| 403 | `SCOPE_DENIED` | У ключа нет скоупа `timeman` |
| 429 | `RATE_LIMITED` | Превышен общий лимит запросов, срок повтора — в заголовке `Retry-After` |

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

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

**Несуществующий сотрудник возвращается без ошибки.** Для несуществующего `userId` метод отвечает `200`: `success` равен `true`, `data.user` — `false`, а `data.report.days` — пустой массив. Признак «сотрудника нет» — `data.user === false`, а не `success`: это поле показывает успех запроса, а не существование сотрудника. Проверяйте `data.user` до интерпретации пустых дней как «отсутствий не было». Проверка прав сохраняется; ошибки доступа описаны выше.

**IP-адреса сотрудников — персональные данные.** Поля `ipStart`, `ipFinish`, `ipStartNetwork` и `ipFinishNetwork` приходят только руководителю и администратору. Храните и показывайте их по правилам обработки персональных данных вашей компании.

**Пороги округляются, год вне диапазона заменяется текущим.** Дробные `idleMinutes` и `workdayHours` приводятся к целым, `workdayHours` меньше 1 считается равным 1. Год меньше 1900 или больше 3000 заменяется текущим годом без ошибки, поэтому сверяйте `dateStart` отчёта с запрошенным месяцем.

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

- [Получить настройки отчёта контроля времени](/docs/workday/time-control-report-settings)
- [Список сотрудников подразделения](/docs/workday/time-control-users)
- [Объяснить отсутствие](/docs/workday/time-control-explain)
- [Настройки контроля времени](/docs/workday/time-control-settings)
- [История рабочего дня](/docs/workday/records)
- [Рабочий день](/docs/workday)
