Skip to content

Send individual (personalized bulk)

Copy page

Send a personalized bulk of SMS in a single request: every recipient gets its own message text and its own sender ID. This is the difference from /sms/send, which fans one message out to many recipients.

POST /api/v1/sms/send-individual · Permission: sms.send

Each accepted recipient is queued, billed and tracked exactly like a normal send, and gets its own message_id in the response — so you can correlate delivery by message_id or by phone number via GET /sms/messages. A blocked_country recipient is returned in results[] without a message_id and is not queued. Missing local pricing does not reject a valid live recipient: it is accepted and queued with a provisional local cost.

Terminal window
curl -X POST https://restlink23telecom.com/api/v1/sms/send-individual \
-H "X-API-Key: $API_KEY" \
-H "Idempotency-Key: send-20260627-batch-001" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"to": "+14155551234",
"message": "Hi John, your code is 847291",
"sender_id": "MyApp"
},
{
"to": "+447911123456",
"message": "Hi Anna, your code is 113355",
"sender_id": "MyApp"
}
]
}'
Field Type Required Description
Idempotency-Key header string Yes Stable key for this logical batch. Reuse it after a timeout or 5xx. Completed responses are retained for 24 hours and replayed byte-for-byte with Idempotent-Replayed: true; a replay is not a new send. A key used with a different body returns 409 IDEMPOTENCY_KEY_REUSED
messages object[] Yes 1 to 1000 messages
messages[].to string Yes Recipient phone number in E.164 format (+ optional, 6-15 digits)
messages[].message string Yes Message text for this recipient — encoding is detected automatically; max 10 SMS segments
messages[].sender_id string Yes Sender ID for this recipient: 3-11 ASCII alphanumeric characters, first character cannot be a number

The API trims leading and trailing whitespace from each to, message and sender_id before validation. Values that are blank after trimming, malformed phone numbers, over-10-segment messages, and invalid senders return 400.

The response shape is identical to /sms/send: each accepted recipient appears in both messages and results with its own message_id. When a completed request is retried with the same Idempotency-Key, the API returns the stored response, does not consume batch tokens again, and includes Idempotent-Replayed: true.

200 OK
{
"status": true,
"messages": [
{"dnis": "+14155551234", "message_id": "api_42_1743667200123456789_a3f8b2c1d9e45f67", "segment_num": 1},
{"dnis": "+447911123456", "message_id": "api_42_1743667200123456789_b7c4e8f1a2d3690b", "segment_num": 1}
],
"results": [
{"dnis": "+14155551234", "message_id": "api_42_1743667200123456789_a3f8b2c1d9e45f67", "segments": 1, "status": "accepted"},
{"dnis": "+447911123456", "message_id": "api_42_1743667200123456789_b7c4e8f1a2d3690b", "segments": 1, "status": "accepted"}
],
"summary": {
"total_recipients": 2,
"total_segments": 2,
"total_cost": 0.02,
"encoding": "GSM-7",
"accepted_count": 2,
"blocked_count": 0,
"unpriced_count": 0,
"queue_error_count": 0,
"config_error_count": 0,
"db_error_count": 0
}
}
Field Description
messages Accepted messages only (one entry per recipient)
results All recipients with their individual status
summary Totals: accepted, blocked, errors, cost and batch encoding. encoding is GSM-7 or UCS-2 when at least one recipient is accepted, and can be empty when no recipient is accepted
results[].status Meaning
accepted Queued for delivery
blocked_country Recipient’s country is in your blocked list
unpriced Legacy/sandbox non-acceptance status retained for compatibility. Current live pricing misses are accepted and queued with a provisional local cost
queue_error Sandbox simulator storage failure (sk_test_ only); live Redis enqueue failures stay accepted and are recovered from the durable outbox
config_error SMS sending not configured on the account
db_error The recipient’s outbox row could not be written
HTTP Code Description
400 INVALID_BODY Cannot parse request body
400 INVALID_MESSAGES Missing or empty messages array
400 IDEMPOTENCY_KEY_REQUIRED / INVALID_IDEMPOTENCY_KEY Missing or invalid Idempotency-Key header
400 TOO_MANY_MESSAGES Over 1000 messages
400 INVALID_TO A messages[i].to is missing or not E.164-style
400 INVALID_MESSAGE A messages[i].message is missing or exceeds 10 SMS segments
400 INVALID_SENDER A messages[i].sender_id is missing or not 3-11 ASCII alphanumeric characters
403 NO_SMS_ACCESS SMS not enabled on your account
403 CONFIG_ERROR SMS credentials incomplete — contact support
403 WORKSPACE_NOT_AVAILABLE Target workspace was deleted — use a live workspace
409 IDEMPOTENCY_KEY_REUSED Same key was already used with a different request body
409 IDEMPOTENCY_REQUEST_IN_PROGRESS Same key is still processing; retry later with the same key
429 RATE_LIMIT_EXCEEDED The batch exceeds your per-second message budget — see the note below
500 DB_ERROR Could not queue (atomic rollback) — retry the whole request
503 SANDBOX_UNAVAILABLE / RATE_LIMIT_UNAVAILABLE / QUEUE_UNAVAILABLE Sandbox simulator not enabled (sk_test_), rate limiter unavailable, or SMS queue unavailable — retry shortly with the same Idempotency-Key

The send response confirms acceptance, not delivery. Because every recipient gets a distinct message_id, you can track each one precisely:

  • Webhooks (recommended): receive a delivery report per recipient the moment the carrier reports it.
  • Per message: call GET /sms/status/:message_id for any message_id returned above.
  • By phone: call GET /sms/messages with phone=, from= and to= to pull every message to a number over a date range and match results by recipient.