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

Одноразовые коды

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

Что особенного

Свойство Значение Почему
Текст в базе не хранится текст кода и есть секрет; хранение превратило бы таблицу сообщений в таблицу действующих кодов
Переменные маскируются по той же причине: код не должен остаться нигде, кроме эфира
Отписка не действует код запрашивает сам абонент, стоя перед формой ввода; «отписка от собственного запроса» — это отказ во входе
Срок жизни 5 минут по умолчанию, от 1 до 10 код, живущий дольше формы, — это код, который успеют перехватить
Снижение темпа при перегрузке оператора не применяется режут массовые рассылки; коды режут ровно в тот момент, когда абонент ждёт

Отправка

{
  "to": "+79012223344",
  "class": "otp",
  "template": "otp-login",
  "variables": {"code": "482913"},
  "ttl": 300
}

ttl — секунды. Меньше 60 — 422 ttl_too_short, больше 600 — 422 ttl_too_long. Без него берётся 300.

Если хаб ответил 503

503 provider_unavailable на код означает: код не принят и не уйдёт, в системе его нет. Так бывает, когда очередь отправки на секунды недоступна: текст кода мы не храним, переиздать его позже нечем, и 202 на него был бы обещанием, которое никто не выполнит.

Повторите тот же запрос — с тем же Idempotency-Key и тем же client_ref: ни тот, ни другой такой отказ не запоминают, а окно анти-флуда на него не потрачено. Сервисные сообщения так не отвечают: их текст хранится, и они уходят после восстановления очереди сами.

Анти-флуд

Один номер получает не чаще, чем раз в 60 секунд — и это защита абонента, а не ограничение для вас. Отказ: 422 recipient_flood_limited с retry_after.

Окна общие для всех классов: сервисное сообщение, ушедшее на номер за минуту до запроса кода, задержит код на ту же паузу. Если ваши рассылки и коды идут на одних абонентов — разведите их по времени или договоритесь с нами о своих значениях окон (Лимиты и квоты).

Если счётчик временно недоступен, одноразовый код проходит без проверки окон: лишнее сообщение дешевле сломанного входа. Поэтому отказ по анти-флуду одноразовому коду приходит всегда с retry_after.

Обычный сценарий «пользователь нажал «отправить код» второй раз» упирается в эту паузу. Правильная реакция интерфейса — показать обратный отсчёт из retry_after, а не повторять запрос.

Повтор с тем же client_ref окна не тратит: он не создаёт нового сообщения.

Что делать с исходами

  • delivered — доставлено; ничего делать не надо;
  • undelivered — причина в reason_code. Смотреть таблицу в Статусах и их проверке: часть причин означает «повторять бессмысленно»;
  • expired — смотря по причине: при dlr_timeout_local доставка не подтверждена и не опровергнута, код мог дойти; при dlr_timeout оператор сам перестал ждать — код не дошёл; при ttl_expired_before_submit код оператору вообще не передавался. См. Статусы;
  • rejected — отвергнуто оператором или нашими проверками, в эфир не ушло.

Не переотправляйте код автоматически. Абонент, получивший два кода подряд, вводит первый — и не проходит проверку. Правильно: показать «код не пришёл, отправить ещё раз» и отправлять по нажатию, с новым кодом и новым client_ref.

Проверка интеграции

В песочнице есть номера ровно под этот класс задач: доставка, недоставка по двум разным причинам, молчащий оператор, анти-флуд со второй отправки. См. Песочницу.