Skip to content

Your first SMS

This page exists to be read once. If you already shipped the Quickstart, skip ahead to Send an instant SMS for the multi-recipient patterns.

POST /api/v1/lisoloo/sms-api/send HTTP/1.1
Host: {BASE_URL}
app-key: sk_test_kqz3pX9aB7nT2vR4wY8eD1fH6jM5oU0i
Content-Type: application/json
{
"to": ["+243998857000"],
"message": "Hello from Lisoloo!"
}

{BASE_URL} is the sandbox host from your dev portal → Lisoloo → Developer → API keys.

Two required fields:

  • to is always an array — even for a single recipient. Each entry must be E.164 (+CCNNNNNN…). The gateway will reject the request with 1104 INVALID_PHONE_NUMBER if any entry fails the regex ^\+?\d{1,15}$.
  • message is the SMS body. Plain UTF-8. Length determines how many SMS segments will be billed — see Character limits.

Everything else (sender_id, sending_type, callback_url, scheduled_dates, recurring_schedule) is optional. With none of them set the gateway treats the request as sending_type: "immediate" and queues for immediate dispatch.

{
"status_code": 201,
"data": {
"message_id": "507f1f77bcf86cd799439011",
"total_recipients": 1,
"total_messages": 1,
"total_cost": 0.02,
"currency": "USD",
"status": "pending",
"sending_type": "immediate"
}
}

What each field means:

FieldTypeNotes
status_codeintMirrors the HTTP status — 201 on a successful queue.
data.message_idstringThe canonical ID. Use it on GET /status/{message_id} and to correlate webhook events.
data.total_recipientsintCount of unique numbers in to.
data.total_messagesinttotal_recipients × segments_per_message. See Character limits.
data.total_costfloatPre-VAT cost in currency. Already deducted from your balance.
data.currencystringThree-letter ISO 4217 code.
data.statusstringInitial status. pending for immediate, scheduled for scheduled/recurring. See Message lifecycle.
data.sending_typestringEchoes back the sending_type from the request (immediate, scheduled, or recurring).
  1. The gateway received the request and validated the app-key header.
  2. It checked your balance — available_smstotal_messages.
  3. It enqueued one delivery job per recipient against the carrier connector.
  4. It returned 201 immediately. The actual carrier handoff happens asynchronously; the status transitions through pending → processing → sent → delivered over the next few seconds.
  5. If a callback_url or merchant-level webhook_url was configured, the gateway POSTs a delivery receipt at each transition.
SymptomLikely causeFix
401 Missing or invalid app-keyHeader missing, mistyped, or wrong environment.Re-check the header name (app-key, hyphenated, lowercase) and the key prefix matches the base URL.
400 with 1104 INVALID_PHONE_NUMBEROne of the to entries isn’t E.164.Validate each entry against ^\+?\d{1,15}$ before sending.
400 with 1109 MISSING_REQUIRED_FIELDto or message is missing or empty.Both fields are mandatory; an empty array doesn’t count.
402 with 1402 INSUFFICIENT_BALANCEYour account doesn’t have enough credit.Top up via the Bloonio dashboard.
429 with 1301 RATE_LIMIT_EXCEEDEDMore than the per-minute cap.Honour Retry-After. See Rate limits.

The full code list is at the error catalogue.