API reference

Batches

Broadcast one template to a list of recipients over a dedicated queue.

Create a batch

POST/v1/batches202 Accepted

Request body

FieldTypeNotes
No fields.

Response

FieldTypeNotes
idrequiredstring
objectrequired"message_batch"
statusrequired"pending" | "enqueuing" | "sending" | "paused" | "completed" | "failed" | "cancelled"
environmentrequired"sandbox" | "production"
namerequiredstring | null
template_namerequiredstring | null
recipient_countrequiredinteger
range 0..9007199254740991
pacingrequiredobject | null
Accept-time forecast of how this batch will be paced against WhatsApp’s daily NEW-recipient allowance for the sending number. Returned on the create response. Null means "no estimate", never "no pacing" — either the forecast could not be made (the sending number could not be resolved, or its allowance is not a finite number to divide by, or the number has no finite cap at all), or you are reading the batch back later: the forecast is an accept-time snapshot that Tyxter neither stores nor recomputes, so retrieve and list always report null here. For live progress read enqueued_count / sent_count, and for the per-message reason read status_reason on the batch’s messages.
enqueued_countrequiredinteger
range 0..9007199254740991
sent_countrequiredinteger
range 0..9007199254740991
failed_countrequiredinteger
range 0..9007199254740991
error_messagerequiredstring | null
trace_idrequiredstring
scheduled_forrequiredstring<ISO-8601> | null
started_atrequiredstring<ISO-8601> | null
completed_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

Before a batch is accepted, Tyxter resolves the approved template version. Inline recipient variablescan satisfy modeled BODY values in the approved version's format: exact numeric keys for POSITIONAL or exact parameter-name keys for NAMED. Shared template.header_media can satisfy a modeled media header. A required text-HEADER or dynamic URL-button parameter has no batch request source, so it returns 400 template_param_mismatch with param: template. The audience and audience_id shapes have no per-recipient variable source in either format and likewise cannot supply BODY, text-HEADER, or dynamic URL-button parameters, although shared template.header_media remains available for a modeled media header. A mismatch returns 400 template_param_mismatch with a corrective param such as recipients.0.variables, template.header_media, or template. No batch was accepted, billed, queued, or sent to Meta. A later approval change or unmodeled Meta behavior can still fail an accepted recipient asynchronously with the same code.

The create response carries a pacingforecast when Tyxter can make one: how many recipients are expected to wait for WhatsApp’s daily NEW-recipient allowance on the sending number, and roughly how many daily windows the batch will span. A batch spanning more than one window is normal and not an error — the waiting recipients stay queued and send by themselves as allowance frees up. Both numbers are estimates: they move as other traffic on the same number consumes allowance, and recipients already inside an open conversation window cost nothing against it.

Retrieve a batch

GET/v1/batches/{id}

Response

FieldTypeNotes
idrequiredstring
objectrequired"message_batch"
statusrequired"pending" | "enqueuing" | "sending" | "paused" | "completed" | "failed" | "cancelled"
environmentrequired"sandbox" | "production"
namerequiredstring | null
template_namerequiredstring | null
recipient_countrequiredinteger
range 0..9007199254740991
pacingrequiredobject | null
Accept-time forecast of how this batch will be paced against WhatsApp’s daily NEW-recipient allowance for the sending number. Returned on the create response. Null means "no estimate", never "no pacing" — either the forecast could not be made (the sending number could not be resolved, or its allowance is not a finite number to divide by, or the number has no finite cap at all), or you are reading the batch back later: the forecast is an accept-time snapshot that Tyxter neither stores nor recomputes, so retrieve and list always report null here. For live progress read enqueued_count / sent_count, and for the per-message reason read status_reason on the batch’s messages.
enqueued_countrequiredinteger
range 0..9007199254740991
sent_countrequiredinteger
range 0..9007199254740991
failed_countrequiredinteger
range 0..9007199254740991
error_messagerequiredstring | null
trace_idrequiredstring
scheduled_forrequiredstring<ISO-8601> | null
started_atrequiredstring<ISO-8601> | null
completed_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

pacing is always null here. The forecast is an accept-time snapshot that Tyxter neither stores nor recomputes, so read it from the create response. For live progress use enqueued_count and sent_count; for the per-message reason use status_reasonon the batch’s messages.

List batches

GET/v1/batches

Response

FieldTypeNotes
objectrequired"list"
datarequiredobject[]
has_morerequiredboolean
next_cursorrequiredstring | null

Control a batch

POST/v1/batches/{id}/pause
POST/v1/batches/{id}/resume
POST/v1/batches/{id}/cancel

Response

FieldTypeNotes
idrequiredstring
objectrequired"message_batch"
statusrequired"pending" | "enqueuing" | "sending" | "paused" | "completed" | "failed" | "cancelled"
environmentrequired"sandbox" | "production"
namerequiredstring | null
template_namerequiredstring | null
recipient_countrequiredinteger
range 0..9007199254740991
pacingrequiredobject | null
Accept-time forecast of how this batch will be paced against WhatsApp’s daily NEW-recipient allowance for the sending number. Returned on the create response. Null means "no estimate", never "no pacing" — either the forecast could not be made (the sending number could not be resolved, or its allowance is not a finite number to divide by, or the number has no finite cap at all), or you are reading the batch back later: the forecast is an accept-time snapshot that Tyxter neither stores nor recomputes, so retrieve and list always report null here. For live progress read enqueued_count / sent_count, and for the per-message reason read status_reason on the batch’s messages.
enqueued_countrequiredinteger
range 0..9007199254740991
sent_countrequiredinteger
range 0..9007199254740991
failed_countrequiredinteger
range 0..9007199254740991
error_messagerequiredstring | null
trace_idrequiredstring
scheduled_forrequiredstring<ISO-8601> | null
started_atrequiredstring<ISO-8601> | null
completed_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

Export failures

GET/v1/batches/{id}/failures

Response

FieldTypeNotes
objectrequired"message_batch_failure_export"
batch_idrequiredstring
generated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
rowsrequiredobject[]