Send an instant SMS
sending_type: "immediate" (the default) queues the SMS for immediate
carrier dispatch. The body shape is the same whether you’re sending to
one number or a thousand — only the size of the to array changes.
One recipient
Section titled “One recipient”curl $BASE_URL/api/v1/lisoloo/sms-api/send \ -X POST \ -H "app-key: $LISOLOO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+243998857000"], "message": "Your OTP is 482194. Valid for 5 minutes.", "sender_id": "MYAPP" }'import os, requests
requests.post( "$BASE_URL/api/v1/lisoloo/sms-api/send", headers={"app-key": os.environ["LISOLOO_API_KEY"]}, json={ "to": ["+243998857000"], "message": "Your OTP is 482194. Valid for 5 minutes.", "sender_id": "MYAPP", }, timeout=10,).raise_for_status()await fetch("$BASE_URL/api/v1/lisoloo/sms-api/send", { method: "POST", headers: { "app-key": process.env.LISOLOO_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ to: ["+243998857000"], message: "Your OTP is 482194. Valid for 5 minutes.", sender_id: "MYAPP", }),});Many recipients
Section titled “Many recipients”to is always an array. Pass up to 1 000 numbers in a single call.
Each number is billed independently against your unit_price.
curl $BASE_URL/api/v1/lisoloo/sms-api/send \ -X POST \ -H "app-key: $LISOLOO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": [ "+243998857000", "+243998857001", "+243998857002" ], "message": "Class is cancelled today. See you next week.", "sender_id": "SCHOOL" }'recipients = [f"+24399885700{i}" for i in range(3)]
requests.post( SEND_URL, headers=HEADERS, json={ "to": recipients, "message": "Class is cancelled today. See you next week.", "sender_id": "SCHOOL", }, timeout=10,)const recipients = ["+243998857000", "+243998857001", "+243998857002"];
await fetch(SEND_URL, { method: "POST", headers: HEADERS, body: JSON.stringify({ to: recipients, message: "Class is cancelled today. See you next week.", sender_id: "SCHOOL", }),});The response includes total_recipients and total_messages:
{ "status_code": 201, "success": true, "data": { "message_id": "507f1f77bcf86cd799439011", "total_recipients": 3, "total_messages": 3, "total_cost": 0.06, "currency": "USD", "status": "pending" }}Beyond 1 000 recipients
Section titled “Beyond 1 000 recipients”For larger campaigns split into batches of ≤1 000, spaced ≥1 second
apart to stay under the 60/min rate limit on POST /send. A simple
chunked sender:
def chunks(seq, size): for i in range(0, len(seq), size): yield seq[i:i + size]
for batch in chunks(all_recipients, 1000): requests.post(SEND_URL, headers=HEADERS, json={ "to": batch, "message": MESSAGE, "sender_id": SENDER, }).raise_for_status() time.sleep(1.1)Each batch returns its own message_id. Track them all if you need
cross-batch reporting.
Per-request callback URL
Section titled “Per-request callback URL”If you want this specific batch’s delivery receipts to go to a
different endpoint than the merchant-wide webhook, set callback_url
on the request:
{ "to": ["+243998857000"], "message": "Your delivery is on the way.", "sender_id": "SHOP", "callback_url": "https://my-shop.example.com/lisoloo/webhook"}The callback_url is per-message; it does not override the
merchant-wide webhook (both fire if both are set). See
Webhooks overview.
Sender ID
Section titled “Sender ID”sender_id is the alphanumeric origin string the carrier displays on
the recipient’s handset. Constraints:
- 3–11 characters (carrier-imposed; longer values are truncated by the network).
- A–Z, 0–9. No spaces, no punctuation.
- Pre-registered with your Bloonio account. Unregistered IDs may be rewritten by the carrier to a generic shortcode.
If omitted, the gateway uses your merchant default (set in the dashboard).
See also
Section titled “See also”- Schedule an SMS — same body shape +
scheduled_dates - Recurring SMS — same body shape +
recurring_schedule - Rate limits — pacing patterns
- Character limits — segment counting