Перейти к содержанию
Версия контракта: 0.3.3 — спека

Ошибки

Страница для интегратора: что означает отказ, что с ним делать и куда идти, если непонятно.

Форма отказа

Любой отказ приходит одним и тем же телом:

{
  "error": {
    "type": "invalid_request_error",
    "code": "template_not_active",
    "message": "Шаблон 'otp-login' на модерации у оператора, отправка невозможна.",
    "param": "template",
    "doc_url": "https://docs.sms.termdev.ru/errors#template_not_active",
    "request_id": "req_01J8Z3Q6N2K7V4M9X5T1B8C0DE"
  }
}

Ветвиться следует по code, а не по HTTP-статусу и тем более не по тексту: код стабилен, статус у разных причин совпадает, а текст мы вправе уточнить.

  • type — класс отказа. invalid_request_error чинит клиент, authentication_error и permission_error — про ключ, rate_limit_error — про темп, api_error — про нас.
  • param — какое поле запроса виновато, если виновато конкретное.
  • request_id — идентификатор запроса: req_ и 26 символов. Он есть в каждом ответе, включая успешный (заголовок Request-Id), и это первое, что нужно приложить к вопросу о конкретном запросе. Присланный клиентом Request-Id игнорируется — идентификатор всегда выдаёт хаб.
  • retry_after — секунды до осмысленного повтора. Приходит там, где повтор вообще имеет смысл, и дублируется заголовком Retry-After.

Что повторять

  • 429 — повторить не раньше retry_after. Если отправка шла с Idempotency-Key, повторять следует с тем же ключом: отказ по темпу не приколачивается к ключу, и повтор пройдёт как первый запрос.
  • 409 idempotency_conflict — первый запрос с этим ключом ещё выполняется. Повторить после retry_after. Если первый запрос завершился успехом или окончательным отказом (4xx, кроме 429), повтор получит его сохранённый ответ; если первый кончился 5xx или 429, ключ освобождается и повтор выполняется заново.
  • 5xx — наша неисправность. Повторить с тем же Idempotency-Key; ответы 5xx к ключу не приколачиваются.
  • 422 — запрос понятен, но невыполним. Повтор того же запроса даст тот же отказ: сначала исправить то, на что указывает code и param.

Реестр кодов

Таблица генерируется из реестра в коде: расхождения между ней и поведением хаба быть не может.

error.code HTTP Класс Что произошло
recipient_invalid 422 invalid_request_error Номер получателя должен быть в формате E.164, например +79012223344.
recipient_opted_out 422 invalid_request_error Получатель отказался от сообщений этого отправителя.
recipient_flood_limited 422 invalid_request_error Слишком много сообщений на этот номер за короткое время.
template_not_found 422 invalid_request_error Шаблон не найден.
template_not_active 422 invalid_request_error Шаблон не согласован оператором, отправка по нему невозможна.
template_variables_mismatch 422 invalid_request_error Набор переменных не совпадает с шаблоном.
template_variable_invalid 422 invalid_request_error Значение переменной не соответствует правилам шаблона.
sender_not_registered 422 invalid_request_error Имя отправителя не зарегистрировано у оператора.
class_required 422 invalid_request_error Не указан класс трафика: otp, service или marketing.
class_not_enabled 422 invalid_request_error Класс трафика недоступен для этого аккаунта.
ttl_too_short 422 invalid_request_error Запрошенный срок жизни меньше минимального для этого класса.
ttl_too_long 422 invalid_request_error Запрошенный срок жизни больше максимального для этого класса.
invalid_parameter 422 invalid_request_error Параметр запроса не разбирается.
send_at_not_supported 422 invalid_request_error Отложенная отправка недоступна для этого класса трафика.
send_at_in_past 422 invalid_request_error Момент отложенной отправки уже прошёл.
send_at_too_far 422 invalid_request_error Момент отложенной отправки слишком далеко в будущем.
batch_too_large 422 invalid_request_error В пакете больше сообщений, чем принимает эта ручка.
text_too_long 422 invalid_request_error Текст сообщения превышает допустимую длину.
consent_required 422 invalid_request_error Для рекламного сообщения требуется подтверждённое согласие получателя.
marketing_window_violation 422 invalid_request_error Рекламные сообщения нельзя отправлять в это время суток.
duplicate_rejected 409 invalid_request_error Шаблон с таким именем уже есть.
spend_limit_reached 422 invalid_request_error Квота аккаунта исчерпана.
idempotency_key_reused 422 invalid_request_error Idempotency-Key уже использован с другим телом запроса.
idempotency_conflict 409 invalid_request_error Запрос с этим Idempotency-Key ещё выполняется, повторите позже.
webhook_url_invalid 422 invalid_request_error Адрес эндпоинта вебхука непригоден: нужен доступный https-адрес.
rate_limited 429 rate_limit_error Превышен лимит запросов, повторите позже.
not_found 404 invalid_request_error Объект не найден.
invalid_api_key 401 authentication_error Ключ API отсутствует, отозван или неверен.
insufficient_scope 403 permission_error Ключ не даёт прав на эту операцию.
provider_unavailable 503 api_error Отправка временно недоступна, повторите позже.
hub_daily_limit_reached 429 rate_limit_error Отправка временно недоступна, повторите позже.
internal_error 500 api_error Внутренняя ошибка сервиса.

Все страницы руководства — оглавление.

503 provider_unavailable и 500 internal_error разделены по тому, что делать дальше. Первый означает «запрос не принят, сейчас не можем»: так отвечает приём, когда недоступно наше хранилище или шина, — повтор безопасен, пауза до него в retry_after. Неподтверждённая брокером публикация отвечает 503 только одноразовому коду: код отзывается, и повтор с тем же Idempotency-Key и client_ref примет его заново. Сервисное сообщение в той же ситуации получает обычный 202 и остаётся принятым — его отправит сборщик через одну–три минуты; повторять его не нужно. В пакете такой одноразовый код приходит элементом с результатом rejected. Второй означает нашу неисправность: повтор того же запроса сам по себе её не обойдёт, и правильный шаг — сообщить нам request_id из ответа.

Часть кодов объявлена заранее и сейчас не выдаётся: consent_required и marketing_window_violation относятся к классу marketing, который в MVP выключен, а send_at_in_past и send_at_too_far — к отложенной отправке, которой в MVP нет (любой send_at получает send_at_not_supported). Обработку на них заводить можно, ждать — не стоит. См. Ограничения MVP.

Отдельно от кодов отказа существуют причины недоставки (reason_code): они объясняют судьбу уже принятого сообщения, а не отказ в приёме. Пространства не пересекаются — по одному значению всегда видно, о чём речь. Причины и что с ними делать — на странице «Статусы и их проверка».