Batch
Send unique SMS or MMS messages to multiple recipients in a single API call. Unlike broadcast (which sends the same message to all recipients), batch allows a different body and/or mediaUrl per recipient.
Endpoint
POST /api/v1/messaging/batch
Request body
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Sender phone number in E.164 format or short code (5-6 digits). Must be active and assigned to your account. |
recipients | array | Yes | List of recipient objects. Min 10, max 5,000. Each phone number must be unique. |
recipients[].to | string | Yes | Recipient phone number in E.164 format |
recipients[].body | string | Conditional | Message text for this recipient, up to 640 characters. Required if no mediaUrl. |
recipients[].mediaUrl | string | No | Publicly accessible media URL for this recipient. When provided, the message is sent as MMS. |
recipients[].idempotencyKey | string | No | Idempotency key for this specific recipient. |
idempotencyKey | string | No | Idempotency key for the entire batch. If not provided, a unique one is auto-generated (no dedup protection without an explicit key). |
Each recipient must have at least a body or a mediaUrl.
Note: Mixed SMS and MMS recipients in a single batch is not yet supported. All recipients must be either SMS-only (body, no mediaUrl) or MMS-only (with mediaUrl). This restriction will be removed in a future release.
Example
SMS batch with personalized messages
curl -X POST https://platform.textingline.com/api/v1/messaging/batch \
-u "your_key_id:your_key_secret" \
-H "Content-Type: application/json" \
-d '{
"from": "+18005559876",
"recipients": [
{"to": "+18005551001", "body": "Hi Alice, your order #1001 has shipped!"},
{"to": "+18005551002", "body": "Hi Bob, your order #1002 is ready for pickup."},
{"to": "+18005551003", "body": "Hi Carol, your appointment is confirmed for 3 PM."}
]
}'Batch with idempotency keys
curl -X POST https://platform.textingline.com/api/v1/messaging/batch \
-u "your_key_id:your_key_secret" \
-H "Content-Type: application/json" \
-d '{
"from": "+18005559876",
"idempotencyKey": "order-batch-2026-05-01",
"recipients": [
{"to": "+18005551001", "body": "Hi Alice, your order shipped!", "idempotencyKey": "order-1001-shipped"},
{"to": "+18005551002", "body": "Hi Bob, your order is ready.", "idempotencyKey": "order-1002-ready"}
]
}'Response
{
"id": "brc_DsAdb4EBYBh3z25sBA1qnv",
"from": "+18005559876",
"totalRecipients": 3,
"status": "queued",
"createdAt": "2026-05-01T14:30:00.000Z"
}The batch is queued as a background job. The response includes the total recipient count and an initial status of queued.
Recipient filtering
Two compliance filters apply to every batch. Recipients caught by either are silently dropped from the send, and the response's totalRecipients reflects only the accepted count — it may be lower than the number of recipients in the request.
Opt-in filter. Recipients that are not opted in to any group owned by your account are filtered out. If every recipient is not opted in, the batch is rejected with error code 33028.
Hard opt-out filter. Recipients who explicitly refused messages (texted STOP, opted out at a kiosk, or were flagged via carrier propagation) are filtered out. This is a permanent compliance signal — re-engaging these contacts requires fresh consent (they must text in again or otherwise affirmatively opt back in). If every recipient is hard-opted-out, the batch is rejected with error code 33029.
Merge tags
Each recipient's body independently supports merge tags like {{contact_first_name}} and {{contact_custom_field_1}}. At send time, each recipient's phone number is looked up against your account's contact book and the matching values are substituted into their specific body.
curl -X POST https://platform.textingline.com/api/v1/messaging/batch \
-u "your_key_id:your_key_secret" \
-H "Content-Type: application/json" \
-d '{
"from": "+18005559876",
"recipients": [
{"to": "+18005551001", "body": "Hi {{contact_first_name}}, your order #1001 shipped!"},
{"to": "+18005551002", "body": "Reminder: appointment at {{dateOffset "0d"}}"},
{"to": "+18005551003", "body": "Your {{contact_custom_field_1}} tier discount is now active."}
]
}'Each recipient sees their own personalized message.
Missing data resolves to an empty string — no error is raised. If a recipient's phone number doesn't match any contact, every merge tag in that recipient's body is replaced with an empty string. The same applies when a contact exists but a specific referenced field is empty. The message is sent in both cases.
Merge tags are substituted in each recipient's body only — recipients[].mediaUrl is not templated. For per-recipient media, compute each recipient's URL yourself before submitting the batch and pass the final value in mediaUrl.
See Merge Tags for the full variable list (contact-scoped, custom fields, date helpers, tracking links) and design guidance for per-recipient templates.
Batch vs. Broadcast
| Feature | Batch | Broadcast |
|---|---|---|
| Message content | Unique body/mediaUrl per recipient | Same message for all recipients |
| Recipients | 10 - 5,000 | 100 - 50,000 |
| Rate limit | 5 requests per minute | 1 request per minute |
| Idempotency | Batch-level + per-recipient keys | Broadcast-level + per-recipient keys |
| Use case | Personalized notifications | Marketing blasts, announcements |
Duplicate recipients
The recipients array must not contain duplicate phone numbers. If duplicates are found, the request is rejected with error code 33024.
Idempotency
Batch supports two levels of idempotency:
- Batch-level: Provide an
idempotencyKeyon the request to prevent duplicate batch submissions. If not provided, a unique key is auto-generated (no dedup protection without an explicit key). - Per-recipient: Provide an
idempotencyKeyon individual recipients to prevent duplicate messages to the same recipient across retries.
See Idempotency for more details.
Credits
Credits are charged per recipient based on message type:
- SMS recipients (body only): 2 credits per recipient (1 message + 1 carrier lookup)
- MMS recipients (with mediaUrl): 1 SMS credit + 1 MMS credit per recipient
Content compliance
Each recipient's message content is validated against messaging compliance rules (SHAFT, phishing, etc.). If any recipient's content violates these rules, the entire batch is rejected with error code 33019. See Compliance for details.
Rate limits
The batch endpoint allows 5 requests per minute. See Rate Limits for details.
Common errors
| Code | Description |
|---|---|
33024 | Duplicate recipients or recipient missing body/mediaUrl |
33004 | The from number is not assigned to your account |
33012 | Daily messaging quota reached |
33016 | A recipient's body contains invalid characters |
33019 | A recipient's body violates compliance rules |
33023 | Insufficient credits |
See Error Codes for the full reference.