# Ошибки и ограничения

Все эндпоинты Tenant API используют единый формат ошибок и стандартные HTTP-коды состояния. Полный перечень эндпоинтов и примеры ответов приведены в [Справочнике API (OpenAPI)](/ru/api/api-reference).

## Формат ошибок [#формат-ошибок]

Ответы об ошибках возвращаются в формате JSON с единой структурой:

```json
{
  "success": false,
  "error": {
    "type": "invalid_request_error",
    "code": "validation_error",
    "message": "Request validation failed",
    "param": "flow_id",
    "details": [
      {
        "field": "flow_id",
        "code": "required",
        "message": "flow_id is required"
      }
    ],
    "request_id": "req_abc123",
    "retryable": false
  }
}
```

**Описание полей:**

| Поле | Описание |
|------|----------|
| `success` | Всегда `false` при ошибке |
| `error.type` | Категория ошибки, определяемая HTTP-кодом: `authentication_error` (401), `authorization_error` (403), `not_found_error` (404), `rate_limit_error` (429), `service_unavailable` (503), `api_error` (5xx), `invalid_request_error` (прочие 4xx) |
| `error.code` | Код ошибки (например, `validation_error`, `not_found`, `unauthorized`, `conflict`) |
| `error.message` | Краткое описание ошибки (для разработчиков и журналирования) |
| `error.param` | Параметр, вызвавший ошибку (при валидации) |
| `error.details` | Массив ошибок по отдельным полям (при валидации) |
| `error.request_id` | Идентификатор запроса (для обращений в службу поддержки) |
| `error.doc_url` | Ссылка на соответствующий раздел документации (при наличии) |
| `error.retryable` | Допустимость безопасного повтора запроса (`true` — для ряда ошибок 5xx и таймаутов) |

## HTTP-коды состояния [#http-коды-состояния]

| Код | Описание |
|-----|----------|
| **200** | Запрос выполнен успешно |
| **201** | Ресурс создан |
| **400** | Некорректный запрос (ошибка в теле или параметрах) |
| **401** | Аутентификация не пройдена (отсутствует или некорректна HMAC-подпись / JWT-токен) |
| **403** | Доступ запрещён (недостаточно прав по scope или попытка доступа к ресурсу другого тенанта) |
| **404** | Ресурс не найден (сессия, аппликант, ссылка и т.д.) |
| **409** | Конфликт (например, задача ревью уже назначена или решение уже принято) |
| **410** | Ресурс более недоступен (например, сессия истекла) |
| **422** | Ошибка валидации полей запроса |
| **429** | Превышен лимит запросов (rate limit); заголовок **Retry-After** указывает время ожидания |
| **500** | Внутренняя ошибка сервера; при `error.retryable = true` допускается повтор запроса |

## Ограничения частоты запросов (rate limiting) [#ограничения-частоты-запросов-rate-limiting]

Лимиты применяются по IP-адресу и по API-ключу. Значения по умолчанию:

| Уровень | Запросов/сек | Запросов/мин |
|---------|-------------|-------------|
| По IP-адресу | 20 | 200 |
| По API-ключу | 40 | 400 |

При превышении лимита возвращается HTTP 429 Too Many Requests. Заголовки ответа:

| Заголовок | Описание |
|-----------|----------|
| `X-RateLimit-Limit` | Максимальное количество запросов в текущем окне |
| `X-RateLimit-Remaining` | Количество оставшихся запросов |
| `X-RateLimit-Reset` | Unix-время сброса лимита |
| `Retry-After` | Количество секунд до следующей допустимой попытки |

**Рекомендация:** реализуйте экспоненциальный backoff при повторных попытках и учитывайте значение заголовка `Retry-After`.

## Типичные ошибки [#типичные-ошибки]

### `invalid_signature` (401) [#invalid_signature-401]
Некорректная HMAC-подпись. Проверьте правильность формирования подписи (см. раздел [Аутентификация](/ru/api/authentication)).

### `invalid_signature` (401) — расхождение времени [#invalid_signature-401--расхождение-времени]

Если отклонение между значением `X-Timestamp` и серверным временем превышает 5 минут, сервер также возвращает код `invalid_signature` (отдельного кода `timestamp_expired` нет). Убедитесь в корректной синхронизации времени (NTP) на стороне клиента.

### `unauthorized` (403) [#unauthorized-403]
Недостаточно прав доступа (scope) у API-ключа. Проверьте настройки scopes в административной панели.

### `not_found` (404) [#not_found-404]
Запрошенный ресурс (аппликант, сессия, ссылка и т.д.) не найден либо принадлежит другому тенанту.

### `link_already_consumed` (409) [#link_already_consumed-409]
Ссылка верификации уже использована. Необходимо создать новую ссылку.

### `link_expired` (410) [#link_expired-410]
Срок действия ссылки верификации истёк. Создайте новую ссылку с увеличенным значением `ttl_seconds`.

### `validation_error` (422) [#validation_error-422]
Поля запроса не прошли валидацию. Детализация ошибок содержится в массиве `error.details`.

### `rate_limit_exceeded` (429) [#rate_limit_exceeded-429]
Превышен лимит запросов. Используйте заголовок `Retry-After` и экспоненциальный backoff.

### `internal_server_error` (500) [#internal_server_error-500]
Внутренняя ошибка сервера. Проверьте значение `error.retryable` — при `true` допускается повтор запроса.

## OTP-верификация: ограничения и ошибки [#otp-верификация-ограничения-и-ошибки]

OTP используется для подтверждения номера телефона или адреса электронной почты в рамках KYC-сессии.

### Параметры OTP-кода [#параметры-otp-кода]

| Параметр | Значение |
|----------|----------|
| Длина кода | 6 цифр |
| Срок действия кода | По умолчанию: телефон — 10 минут, email — 15 минут. Конфигурация шага флоу может переопределить срок в поддерживаемом диапазоне. |
| Минимальный интервал повторной отправки | 15 секунд по умолчанию; конфигурация шага флоу может переопределить интервал |
| Максимальное количество попыток ввода | 10 |

### Ошибки OTP [#ошибки-otp]

При неуспешной верификации OTP-эндпоинты возвращают стандартный error envelope с кодом OTP-ошибки и текстовым сообщением, поясняющим причину. Когда доступно количество оставшихся попыток, оно передается в `error.details` как `attempts_remaining`.

#### `rate_limit_exceeded` (429) [#rate_limit_exceeded-429-1]
Превышен лимит запросов на отправку OTP. Необходимо дождаться истечения ограничения (см. заголовок `Retry-After`).

#### `otp_invalid` / `otp_expired` (400/422) [#otp_invalid--otp_expired-400422]
Срок действия кода истёк (более 10 минут). Запросите новый код через `POST .../otp/send`.

#### `otp_invalid` (400/422) [#otp_invalid-400422]
Введён некорректный код. Количество оставшихся попыток указано в `error.details`, если эндпоинт возвращает это значение.

#### `otp_invalid` (400/422), превышен лимит попыток [#otp_invalid-400422-превышен-лимит-попыток]
Исчерпаны все 10 попыток ввода. Код аннулирован — необходимо запросить новый через `POST .../otp/send`.

---

**См. также:** [Аутентификация](/ru/api/authentication) (коды 401, 403), [Справочник API (OpenAPI)](/ru/api/api-reference) (полная спецификация эндпоинтов и кодов ответов).
