Broadcast batches
One template, many recipients, one API call. Runs on a dedicated queue so broadcasts cannot starve transactional sends.
Create a batch
curl https://api.tyxter.com/v1/batches \
-H "authorization: Bearer $TYXTER_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "April promo",
"from": "pn_...",
"template": { "name": "promo_april", "language": "pt_BR" },
"recipients": [
{ "to": "+5511999999001", "variables": { "1": "Diego" } },
{ "to": "+5511999999002", "variables": { "1": "Ana" } }
]
}'Returns 202 with a message_batch.
Target a saved audience
Use audience_id instead of inline recipients when you want to reuse a saved contact list.
curl https://api.tyxter.com/v1/batches \
-H "authorization: Bearer $TYXTER_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "April promo",
"from": "pn_...",
"template": { "name": "promo_april", "language": "pt_BR" },
"audience_id": "aud_..."
}'Audience membership is snapshotted when the batch is created. Existing batches are not affected by later audience edits.
Lifecycle
pending → just accepted, nothing enqueued yet
enqueuing → worker is walking the recipient list
sending → every recipient has been enqueued; sends are in flight
paused → enqueue cursor is preserved until resume
completed → every send terminal (sent / failed / opted_out)
failed → the batch itself failed before enqueuing could complete
cancelled → manual cancel; no more recipients are enqueuedWhat the worker does
- Pulls the
MessageBatchby id. - Pages through
recipients100 at a time, resuming fromenqueued_counton retry. - For each recipient, checks consent. Opted-out recipients get a
failedMessagerow witherror_code: contact_opted_out— no send is ever attempted. - Allowed recipients get a fresh
acceptedMessagerow and abroadcast.sendjob on theoutbound.broadcastqueue.
SendOutboundMessageUseCase processes both transactional and broadcast jobs. The separation is purely queue-level, which is enough: a broadcast of 50k messages can't delay a time-sensitive OTP because they never share a worker.Pause, resume, cancel
Pause stops future enqueue pages while preserving enqueued_count. Resume requests the enqueue worker again and continues from that cursor. Cancel is terminal for the batch enqueue worker.
Scheduling
Pass scheduled_for (ISO-8601) to delay the batch. The outbox publisher respects available_at, so the job simply won't be picked up until that time.
Tracking progress
Poll the batch row for enqueued_count, sent_count, and failed_count. Individual per-recipient messages carry the batch id in their metadata.batch_id so you can query GET /v1/messages for the full picture.
The failure export returns failed per-recipient rows for CSV or support workflows.