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

FieldTypeRequiredDescription
fromstringYesSender phone number in E.164 format or short code (5-6 digits). Must be active and assigned to your account.
recipientsarrayYesList of recipient objects. Min 10, max 5,000. Each phone number must be unique.
recipients[].tostringYesRecipient phone number in E.164 format
recipients[].bodystringConditionalMessage text for this recipient, up to 640 characters. Required if no mediaUrl.
recipients[].mediaUrlstringNoPublicly accessible media URL for this recipient. When provided, the message is sent as MMS.
recipients[].idempotencyKeystringNoIdempotency key for this specific recipient.
idempotencyKeystringNoIdempotency 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

FeatureBatchBroadcast
Message contentUnique body/mediaUrl per recipientSame message for all recipients
Recipients10 - 5,000100 - 50,000
Rate limit5 requests per minute1 request per minute
IdempotencyBatch-level + per-recipient keysBroadcast-level + per-recipient keys
Use casePersonalized notificationsMarketing 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 idempotencyKey on 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 idempotencyKey on 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

CodeDescription
33024Duplicate recipients or recipient missing body/mediaUrl
33004The from number is not assigned to your account
33012Daily messaging quota reached
33016A recipient's body contains invalid characters
33019A recipient's body violates compliance rules
33023Insufficient credits

See Error Codes for the full reference.