Перейти к содержанию

Ошибки

Публичный API возвращает стандартные HTTP-коды. Текущие два эндпоинта (POST /verifications/, GET /verifications/{id}/) сохраняют исходные форматы тел ответов (legacy-формат DRF) для обратной совместимости — новые эндпоинты будут использовать единый envelope (см. ниже).

Каталог HTTP-кодов

Код Значение Когда
400 Bad Request Валидация запроса Невалидный JSON, отсутствуют обязательные поля, плохой формат phone или webhook_url.
401 Unauthorized Аутентификация Нет заголовка, неверный / отозванный токен.
403 Forbidden Авторизация Аутентификация прошла, но не Bearer (например, сессия).
404 Not Found Ресурс не найден Несуществующий verification_id или принадлежит другой компании.
405 Method Not Allowed Неверный метод Например, PUT на /verifications/.
429 Too Many Requests Лимит Превышен 120 req/min на ключ. Заголовок Retry-After.
500 Internal Server Error Бага на нашей стороне Сообщите в саппорт с verification_id и временем.
503 Service Unavailable Сервис занят Нет свободного номера, подходящего абоненту по коду страны. Заголовок Retry-After: 60.

Форматы тел ответа

Валидация (400)

DRF-формат: ключ — имя поля, значение — массив строк-ошибок.

{
  "phone": ["Некорректный номер телефона"]
}

Возможные ошибки полей:

Поле Сообщения
phone Некорректный номер телефона — единое нормализованное сообщение (детали парсера не раскрываются, чтобы нельзя было энумерировать валидные форматы).
webhook_url Введите корректный URL. (невалидный синтаксис); webhook_url scheme must be http or https, got '<scheme>'; webhook_url must not contain embedded credentials; webhook_url resolves to a private/internal address (<ip>); webhook_url host cannot be resolved: …
client_ref Убедитесь, что это значение содержит не более 120 символов.
ttl_seconds Убедитесь, что это значение больше либо равно 1.; Убедитесь, что это значение меньше либо равно 3600.

Язык сообщений

Стандартные сообщения DRF (валидация полей, URL) локализованы на русский. Сообщения SSRF-гарда webhook_url приходят на английском — они генерируются отдельным валидатором (см. Безопасность).

Если в теле битый JSON — вернётся 400 с {"detail": "<сообщение о разборе JSON>"}.

Аутентификация (401)

{
  "detail": "Недействительный API-ключ"
}

Конкретный текст зависит от причины (нет заголовка, неверный формат, неизвестный ключ, отозванный ключ) — полный список в Аутентификации. В заголовках: WWW-Authenticate: Bearer.

Авторизация (403)

{
  "detail": "Требуется API-ключ."
}

Возникает, если запрос прошёл другую аутентификацию (не Bearer API-ключ) — публичные эндпоинты требуют именно ключ API.

Не найдено (404)

{
  "detail": "Не найдено."
}

Лимит (429)

{
  "detail": "Запрос был отклонён. Ожидается доступность через 23 сек."
}

В заголовках: Retry-After: 23. Подробнее — Лимиты.

Сервис занят (503)

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

Номер подбирается по коду страны из phone — абоненту с +7 выдаётся российский номер, остальным международный, — поэтому пулы заканчиваются независимо друг от друга. 503 на международный номер не означает, что российские номера тоже заняты. Подробнее — Все линии заняты.

{
  "error": "no_dial_number_available",
  "message": "Сервис временно занят, все линии заняты. Попробуйте позже.",
  "retry_after": 60
}

В заголовках: Retry-After: 60. Это единственный legacy-эндпоинт с машинно-читаемым error-кодом. Рекомендуется ловить именно этот HTTP-код (503) и/или строку "no_dial_number_available"; поле message предназначено для человекочитаемого вывода и может меняться в будущих версиях, не завязывайте на него логику.

Свободная линия появится автоматически, как только одна из текущих верификаций завершится звонком, истечёт по TTL (по умолчанию до минуты) или будет отменена через POST /verifications/{id}/cancel/. Каждое событие исчерпания пула логируется на стороне сервера на уровне WARNING — оператор видит частоту и при устойчивом росте расширяет пул линий.

Отказ также записывается в ваш дашборд отдельной верификацией со статусом failed и причиной «Все линии заняты» — без номера и без webhook'а.

Детальный разбор — что делать в коде, как реже упираться в отказ и как отличить занятость от аварии: Все линии заняты.


Новый envelope (для будущих эндпоинтов)

При добавлении новых эндпоинтов мы будем использовать единый формат:

{
  "error": {
    "code": "<machine_code>",
    "message": "<human-readable>",
    "fields": {
      "<field>": ["<msg>", "..."]
    }
  }
}

Поле fields — опциональное (только для ошибок валидации).

Машинно-читаемые коды

code HTTP Описание
invalid_request 400 Ошибка валидации
authentication_failed 401 Аутентификация
permission_denied 403 Авторизация
not_found 404 Не найдено
method_not_allowed 405 Метод не разрешён
conflict 409 Конфликт состояния
rate_limited 429 Превышен лимит
no_dial_number_available 503 Нет свободных DID для страны абонента
idempotency_conflict 409 Idempotency-ключ переиспользован с другим телом
service_unavailable 503 Временно недоступно
internal_error 500 Внутренняя ошибка

Существующие два эндпоинта продолжают использовать legacy-формат. Документация конкретного эндпоинта точно указывает, какой формат возвращается.


Рекомендации по обработке

  • Ретраить автоматически только 429 (с уважением к Retry-After) и 503. Максимум 3 попытки с экспоненциальным backoff.
  • Не ретраить 4xx кроме 429 — это ошибка на вашей стороне.
  • Алертить 5xx (кроме 503 при попытках с backoff) — это может быть инцидент на стороне TrueNum.
  • Логировать все ответы вместе с verification_id (если получен) — упростит дебаг.