Bulk SMS
Send messages to many recipients in a single API call. Bulk send is optimised for high-throughput campaigns, multi-recipient alerts, and personalised batches, and it returns a per-recipient breakdown so you can track each message independently.
๐ก Endpointโ
POST /v1/sms/bulk
Base URL: https://api.afriroute.ai
๐ Authenticationโ
Authorization: Bearer $AFRIROUTE_API_KEY
Content-Type: application/json
๐ฅ Request Parametersโ
| Field | Type | Required | Description |
|---|---|---|---|
from | string | Yes | Default sender ID for all messages in the batch |
messages | array | Yes | List of message objects (max 1,000 per request) |
messages[].to | string | Yes | Recipient in E.164 format |
messages[].text | string | Yes | Message content for this recipient |
messages[].from | string | No | Per-message sender ID override |
callback_url | string | No | Webhook URL for delivery reports on all messages |
scheduled_at | string | No | ISO 8601 timestamp to schedule the whole batch |
๐ค Example Requestโ
curl -X POST https://api.afriroute.ai/api/v1/sms/bulk \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "AFRIROUTE",
"callback_url": "https://yourapp.com/webhooks/sms",
"messages": [
{ "to": "+251911111111", "text": "Hi Alice, order #123 shipped!" },
{ "to": "+251922222222", "text": "Hi Bob, your payment was received!" }
]
}'
const response = await fetch('https://api.afriroute.ai/api/v1/sms/bulk', {
method: 'POST',
headers: {
'Authorization': 'Bearer $AFRIROUTE_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'AFRIROUTE',
callback_url: 'https://yourapp.com/webhooks/sms',
messages: [
{ to: '+251911111111', text: 'Hi Alice, order #123 shipped!' },
{ to: '+251922222222', text: 'Hi Bob, your payment was received!' }
]
})
});
const data = await response.json();
console.log(data.batch_id, data.accepted, data.rejected);
import requests
response = requests.post(
'https://api.afriroute.ai/api/v1/sms/bulk',
headers={'Authorization': 'Bearer $AFRIROUTE_API_KEY'},
json={
'from': 'AFRIROUTE',
'callback_url': 'https://yourapp.com/webhooks/sms',
'messages': [
{'to': '+251911111111', 'text': 'Hi Alice, order #123 shipped!'},
{'to': '+251922222222', 'text': 'Hi Bob, your payment was received!'},
],
},
)
print(response.json()['batch_id'])
โ Responseโ
200 OK
{
"batch_id": "batch_7K8L9M0N",
"status": "queued",
"accepted": 2,
"rejected": 0,
"total_cost": 0.10,
"currency": "ETB",
"created_at": "2026-05-28T10:30:00Z",
"messages": [
{ "message_id": "msg_aaa111", "to": "+251911111111", "status": "queued", "parts": 1 },
{ "message_id": "msg_bbb222", "to": "+251922222222", "status": "queued", "parts": 1 }
]
}
| Field | Description |
|---|---|
batch_id | Identifier for the whole batch |
accepted / rejected | Count of valid vs invalid messages |
messages[] | Per-recipient result, each with its own message_id |
๐ก Best Practicesโ
- Batch up to 1,000 messages per request; split larger campaigns into multiple calls.
- Personalise the
textper recipient where possible for higher engagement. - Set a single
callback_urlfor the batch to track every message's delivery. - Use
scheduled_atto send during local business hours. - Inspect
rejectedin the response โ rejected messages are not billed or sent. - Include opt-out instructions in marketing messages where legally required.
โ ๏ธ Error Handlingโ
Individual invalid recipients are reported in the messages[] array with a failed status and an error code, while the rest of the batch still sends. A top-level 4xx is returned only when the whole request is malformed.
| HTTP | Code | Resolution |
|---|---|---|
| 400 | BATCH_TOO_LARGE | Reduce to 1,000 messages or fewer |
| 400 | INVALID_PHONE | Correct the offending recipient(s) |
| 402 | INSUFFICIENT_BALANCE | Top up before sending large batches |
| 429 | RATE_LIMITED | Retry with exponential backoff |
See Error Codes for the complete list.
๐ Related Resourcesโ
Last Updated: May 2026 ยท Need help? Contact Support โ