Ошибки¶
Публичный 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 |
Некорректный номер телефона — единое нормализованное сообщение (детали парсера не раскрываются, чтобы нельзя было энумерировать валидные форматы). |
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)¶
Конкретный текст зависит от причины (нет заголовка, неверный формат, неизвестный
ключ, отозванный ключ) — полный список в Аутентификации.
В заголовках: WWW-Authenticate: Bearer.
Авторизация (403)¶
Возникает, если запрос прошёл другую аутентификацию (не Bearer API-ключ) — публичные эндпоинты требуют именно ключ API.
Не найдено (404)¶
Лимит (429)¶
В заголовках: 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(если получен) — упростит дебаг.