Send a batch
One body to up to 10,000 recipients, each with its own merge variables (or to contacts by tag), sent as individual messages through the normal pipeline.
Body Parameters
- fromstring
One of your numbers. Optional while the key's mode has one number. Example:
+15005550100. - bodystringrequired
At most 1600 characters. Example:
Hi {{first_name}}, your order {{order_id}} has shipped.. - namestring
At most 80 characters.
- recipientsarray of object
At most 10000 items.
- recipients[].tostringrequired
Example:
+14155550132. - recipients[].variablesobject
- tagsarray of string
Send to contacts carrying any of these tags (instead of recipients).
- contact_idsarray of string
- segment_idstring
Send to the contacts in this saved segment, evaluated when the batch is created (instead of recipients).
- list_idstring
Send to the contacts in this list, as it is when the batch is created (instead of recipients).
- categorymarketing, transactional, otp
Optional. It can make the batch stricter (
marketing), never looser: the sending number's registration and the wording decide (which messages are marketing). From a number with no registration, a batch is marketing. - quiet_hoursblock, defer
Optional. What to do with a message in the recipient's quiet hours:
blockrefuses it (403 quiet_hours),deferholds it until their next 8:00am. Omitted: each recipient in quiet hours is held until their 8:00am. - topic_idstring
Subscription topic. Recipients unsubscribed from it are removed at validation (
topic_unsubscribed) and skipped at send time, like opt-outs. Omit to apply opt-outs only. Example:tp_marketing. - scheduled_atstring
Future ISO timestamp or epoch ms, up to 30 days out.
- dry_runboolean
Validate only: returns a BatchValidation and sends nothing.
- check_line_typesboolean
Reject landlines (first 500 unique numbers are checked).
Details
Numbers are normalized, deduplicated and checked against opt-outs before queueing; rejected rows are returned with reasons. Set dry_run to validate without sending.
Responses
- 200BatchValidation
Dry run result
- 201Batch
Batch created
- 400Error
Invalid request or no valid recipients
- 401Error
Missing, malformed, or revoked API key
- 402Error
Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
- 403Error
fromnot owned, or key mode does not match the number - 429Error
Rate limit or quota exceeded
Response Fields (200)
- objectbatch_validation
- countsobject
- counts.rowsinteger
- counts.validinteger
- counts.invalidinteger
- counts.duplicatesinteger
- counts.opted_outinteger
- counts.topic_unsubscribedinteger
Unsubscribed from the batch topic_id; 0 without a topic
- counts.missing_variableinteger
- counts.landlineinteger
- counts.empty_after_mergeinteger
- unknown_variablesarray of string
- segmentsobject
- segments.totalinteger
- segments.maxinteger
- segments.encodingGSM-7, UCS-2
- estimated_cost_usdnumber
- previewarray of object
- preview[].tostring
- preview[].bodystring
- preview[].segmentsinteger
- rejectedarray of object
- rejected[].rowinteger
0-based index into recipients
- rejected[].tostring
- rejected[].reasoninvalid, duplicate, opted_out, topic_unsubscribed, missing_variable, landline, empty_after_merge
- rejected[].detailstring
- consentobject
Dry run only. What the consent gate would decide at send time for the first 1,000 accepted recipients:
no_opt_inwould be refusedconsent_required(marketing without an opt-in on file, or a recurring message from a registered number). Informational; every message is still checked when it sends. - consent.checkedinteger
- consent.uncheckedinteger
Accepted recipients past the first 1,000, not checked
- consent.no_opt_ininteger
- consent.no_opt_in_samplearray of string
Up to 20 of them
- consent.unknowninteger
Consent could not be read; the send retries these
Response Fields (201)
- idstring
Example:
bc_a1B2c3D4e5F6. - objectbatch
- namestring
- statusscheduled, sending, paused, complete, canceled
- fromstring
- bodystring
- sourceapi, csv, contacts
- testboolean
- scheduled_atstring (date-time)
Nullable.
- created_atstring (date-time)
- completed_atstring (date-time)
Nullable.
- countsobject
total = queued + sent + failed + opted_out + canceled, always. "sent" = accepted by the carrier; what happened next (delivered, failed, replies) is GET /v1/batches/{id}/results. "opted_out" also counts recipients unsubscribed from the batch topic.
- counts.totalinteger
- counts.queuedinteger
- counts.sentinteger
- counts.failedinteger
- counts.opted_outinteger
- counts.canceledinteger
- rejectedobject
Rows dropped at validation (not part of total), by reason. Nullable.
- variablesarray of string
- retriesinteger
Errors
Every error has the same JSON shape, and request_id matches the X-Request-Id response header. Errors lists every code and what to do about it.
- 400
Invalid request or no valid recipients
- 401
Missing, malformed, or revoked API key
- 402
Billable live calls only: the prepaid credit balance cannot cover the call (insufficient_credits); nothing was done or charged
- 403
fromnot owned, or key mode does not match the number - 429
Rate limit or quota exceeded