Массовые рассылки¶
Страница для интегратора: как отправить тысячу сообщений так, чтобы потом можно было объяснить каждое.
Пакет¶
POST /v1/messages/batch — до 1000 сообщений за раз. Больше — 422
batch_too_large.
{
"messages": [
{"to": "+79012223344", "class": "service", "template": "visit-reminder",
"variables": {"time": "18:30"}, "client_ref": "visit-84213"},
{"to": "+79012223355", "class": "service", "template": "visit-reminder",
"variables": {"time": "19:00"}, "client_ref": "visit-84214"}
]
}
client_ref обязателен у каждого элемента. Без него результат элемента не
с чем сопоставить у себя, а повтор пакета перестаёт быть безопасным.
Ответ¶
Пакет не «уходит целиком или никак»: каждый элемент получает свой результат.
| Результат | Что означает |
|---|---|
accepted |
принято, дальше живёт как обычное сообщение |
duplicate |
такой client_ref уже был; в ответе — ссылка на созданное ранее сообщение |
rejected |
отказ на приёме: номер, шаблон, переменные, лимит. Причина — обычный объект ошибки |
Отказ одного элемента не отменяет остальные. Пакет с тысячей элементов, где десять номеров кривые, примет девятьсот девяносто.
Элемент-одноразовый код, который не удалось поставить в очередь отправки
(брокер не подтвердил публикацию), получает rejected с кодом
provider_unavailable: код, текст которого мы не храним, иначе закончился бы
expired, так и не уйдя. Такой элемент повторяется — тем же пакетом, с тем же
Idempotency-Key: принятые вернутся duplicate, отвергнутый примется.
Повтор¶
Повторите пакет с теми же client_ref — вторых сообщений не будет: элементы
вернутся как duplicate со ссылками на созданные. Это главное свойство,
ради которого client_ref и обязателен: джоба, упавшая на середине и
перезапущенная, не удвоит рассылку.
По этой же причине client_ref должен быть вашим идентификатором записи
(visit-84213), а не случайным числом: при повторе он обязан совпасть.
Отслеживание¶
GET /v1/batches/{id}— счётчики: сколько принято, доставлено, не доставлено, отклонено, и закрыт ли пакет;GET /v1/messages?batch=bat_…— сами сообщения, страницами;- событие
batch.completed— все сообщения пакета достигли терминального статуса. Приходит ровно один раз: повторная отправка пакета его не переиздаёт.
Сколько это будет стоить¶
POST /v1/messages/estimate считает число частей и цену до отправки —
по тому же шаблону и тем же значениям.
Считать стоит всегда, когда текст меняется. Латиница помещается в 160 символов на часть, кириллица — в 70: одно и то же сообщение на русском занимает вдвое больше частей и стоит вдвое дороже. Две ссылки в кириллическом тексте почти гарантированно дают две части.
Если объём важнее вида — транслит или сокращение текста; если важнее вид — считайте заранее и закладывайте в бюджет.
Темп¶
Пакет принимается одним запросом, но отправка идёт со скоростью, которую позволяет оператор. Тысяча сообщений уходит не мгновенно — планируйте рассылку с запасом.
Ключ ограничен по числу запросов в секунду, поэтому подавать пакеты подряд без пауз не нужно: см. Лимиты и квоты.
Laravel: чанкование¶
Разбивайте на пакеты по несколько сотен и ставьте по джобе на пакет.
client_ref — идентификатор вашей записи; тогда повтор джобы после сбоя
безопасен, а не создаёт вторую рассылку.
foreach ($recipients->chunk(500) as $chunk) {
SendSmsBatch::dispatch($chunk->pluck('id')->all());
}
Внутри джобы собирайте элементы из своих записей по идентификаторам и отправляйте одним пакетом. Повтор джобы Horizon'ом — обычное дело; вторых сообщений он не создаст.