Статусы и их проверка¶
Страница для интегратора: как устроена судьба сообщения, как о ней узнать и что делать с каждым исходом.
Модель статусов¶
accepted ──▶ sent ──▶ delivered
│ │ └──▶ undelivered
│ │ └──▶ expired
│ └─────▶ rejected
├─────────────────▶ rejected
└─────────────────▶ expired
accepted— хаб принял сообщение и отвечает за него. Это не отправка.sent— оператор принял сообщение в работу.delivered— оператор подтвердил доставку абоненту.undelivered— оператор сообщил, что доставить не удалось; причина вreason_code.expired— срок жизни истёк раньше доставки. Различаются три случая, см. ниже; кроме них,expiredможет выставить вручную администратор хаба (запись истории сsource: admin).rejected— сообщение отвергнуто: оператором на приёме или нашими проверками.
Поле final: true означает, что статус больше не изменится — даже вручную.
После final меняются только отметки, не статус: поздний отчёт о доставке
добавляет delivered_late_at и уточняет списание (событие
message.delivered_late), прочтение у delivered — seen_at.
Переход sent → rejected законен: оператор вправе отвергнуть уже принятое
сообщение отчётом.
Прочтение статусом не является. Оно фиксируется полем seen_at и событием
message.seen: иначе final: true перестал бы что-либо означать.
Четыре способа узнать статус¶
GET /v1/messages/{id}— одно сообщение целиком, вместе сstatus_history[]: каждая запись несётstatus,at,sourceи, если есть,reason_codeс пояснениемreason_message.source— кто применил статус:gate(проверки на приёме; первая записьaccepted— всегдаgate),provider(оператор),reaper(наш срок жизни),late_dlr(поздний отчёт),sandbox(симулятор песочницы),admin(ручной перевод).GET /v1/messages?status=&to=&batch=&client_ref=&created_after=&created_before=— выборка по фильтрам, страницами.GET /v1/events?starting_after=&created_after=&type=— журнал событий, он же способ догнать пропущенное после простоя приёмника. Курсор — идентификатор события (evt_…), а не время: время не уникально.- Вебхуки — события приезжают сами. Это основной способ; журнал нужен, когда приёмник лежал.
Хаб, кроме того, сам спрашивает оператора о молчащих сообщениях (сверка статусов): одноразовые коды — через минуту, сервисные — через десять. Отдельно делать это интегратору не нужно.
Что делать с expired¶
Три причины, и они означают разное (плюс ручной перевод администратором —
source: admin, причина может отсутствовать):
reason_code |
Что случилось | Что делать |
|---|---|---|
ttl_expired_before_submit |
Срок жизни истёк, пока сообщение стояло в очереди: оператору оно не уходило, денег за него не берём | Отправить заново, если код всё ещё нужен |
dlr_timeout_local |
Оператор принял сообщение, но отчёта не прислал до истечения нашего срока | Отправлять заново нельзя вслепую: сообщение могло дойти. Ждать позднего отчёта — только для этой причины он будет принят (message.delivered_late) |
dlr_timeout |
Оператор сам сообщил, что перестал ждать доставки (EXPIRED от оператора) |
Доставки уже не будет, позднего отчёта не придёт. Повторить позже, если сообщение ещё нужно |
Одноразовые коды автоматически переотправлять не следует: абонент, получивший два кода подряд, вводит первый. Для сервисных сообщений повтор допустим, но не раньше, чем через интервал, согласованный с продуктом.
Причины недоставки и отказа¶
Таблица генерируется из реестра в коде: совет в ней — часть контракта, а не пожелание.
Причины, относящиеся к нашему подключению у оператора (реквизиты, лимиты,
баланс), интегратору не показываются: он получает provider_submit_failed, а
разбирается с этим дежурный.