Download OpenAPI specification:
Send SMS, check message status, manage sender IDs, and check your balance programmatically.
The BliboSMS API is a JSON REST API. All requests go to the base URL below,
must be made over HTTPS, and should send Accept: application/json (plus
Content-Type: application/json on requests with a body).
https://sms.blibosolutions.com/api/v1
Every endpoint requires an API key, sent as a bearer token:
Authorization: Bearer bsms_YOUR_API_KEY
Generate a key from Settings → API Keys in your BliboSMS dashboard.
A missing, invalid, revoked or expired key returns 401 with the error
code unauthorized.
Successful responses wrap the result in a data object:
{ "data": { "sms_balance": 4200 } }
Failed requests return an error object with a machine-readable code,
a human-readable message, and — for validation failures — per-field
details:
{
"error": {
"code": "validation_error",
"message": "The sender id field is required.",
"details": { "sender_id": ["The sender id field is required."] }
}
}
| Status | Meaning |
|---|---|
200 / 201 |
Success |
401 |
Missing or invalid API key |
404 |
The message or OTP reference doesn't exist on your account |
422 |
Validation failed, or the request can't be processed as sent |
429 |
Rate limit, OTP cooldown or OTP daily limit reached |
Requests are limited to 60 per minute per API key. Every response
carries X-RateLimit-Limit and X-RateLimit-Remaining headers; once the
limit is exceeded you receive 429 with a Retry-After header giving the
number of seconds to wait.
POST /messages, POST /otp/generate and POST /otp/resend accept an
optional Idempotency-Key header. Replaying a request with the same key
and the same body returns the original response instead of sending again,
so it is safe to retry after a network failure. Reusing a key with a
different body returns 422 with the code idempotency_key_reused.
Sends to one recipient, or many when recipient is an array (the same
message is queued individually for each; duplicates are removed).
Pass scheduled_at to send later instead of immediately. Supports the
Idempotency-Key header.
| Idempotency-Key | string Example: 7c1d1a52-0a55-4d2b-9f0e-3a4d7a2c9b10 A unique value (for example a UUID) identifying this request. Replaying the same key with the same body returns the original response instead of sending twice. |
| sender_id required | string <= 11 characters Must be an approved sender ID on your account. |
required | Single recipient (string) or Array of Multiple recipients (strings) One phone number, or an array of phone numbers. |
| message required | string <= 500 characters The message body. |
| scheduled_at | string or null <date-time> An ISO 8601 datetime in the future. Omit to send right away. |
object |
{- "sender_id": "BLIBO",
- "recipient": "+233241234567",
- "message": "Your order has shipped."
}{- "data": {
- "messages": [
- {
- "message_id": "9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21",
- "recipient": "+233241234567",
- "status": "queued"
}
]
}
}Paginated history of sent messages, newest first, 20 per page.
Messages that are still waiting to be sent (queued or scheduled) aren't
included here — check those individually with
GET /messages/{reference}.
| status | string Enum: "queued" "submitted" "processing" "delivered" "failed" "expired" "rejected" Example: status=delivered Only return messages with this status. |
| search | string Example: search=233241234567 Filter by recipient, message text, or sender ID. |
| page | integer >= 1 Default: 1 Example: page=1 Page number. |
Array of objects (MessageSummary) | |
object (Pagination) |
curl -G "https://sms.blibosolutions.com/api/v1/messages" \ -H "Authorization: Bearer bsms_YOUR_API_KEY" \ -H "Accept: application/json" \ -d status=delivered \ -d page=1
{- "data": [
- {
- "message_id": "9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21",
- "status": "delivered",
- "sender_id": "BLIBO",
- "recipient": "+233241234567",
- "cost": "0.0350",
- "sent_at": "2026-07-19T10:00:00+00:00",
- "delivered_at": "2026-07-19T10:00:05+00:00"
}
], - "meta": {
- "current_page": 1,
- "per_page": 20,
- "total": 1,
- "last_page": 1
}
}Looks up a message by the message_id returned when it was sent. The ID is
stable across the message's whole lifecycle — while it is waiting to be
sent, and once the network reports back.
| reference required | string <uuid> Example: 9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21 The |
object (Message) |
curl "https://sms.blibosolutions.com/api/v1/messages/9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21" \ -H "Authorization: Bearer bsms_YOUR_API_KEY" \ -H "Accept: application/json"
{- "data": {
- "message_id": "9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21",
- "status": "delivered",
- "sender_id": "BLIBO",
- "recipient": "+233241234567",
- "scheduled_at": null,
- "cost": "0.0350",
- "sent_at": "2026-07-19T10:00:00+00:00",
- "delivered_at": "2026-07-19T10:00:05+00:00",
- "error_message": null
}
}Generate and verify one-time passcodes. Codes are sent immediately (not
queued) and are never returned in any API response — only a reference
for status lookups. A code can only be verified against the phone number
it was sent to.
Generates a code and texts it to the recipient straight away. Generating a
new OTP for the same recipient and purpose replaces any that is still
pending.
To protect recipients, a number can only be sent one OTP every 60 seconds
and 5 OTPs per day. Supports the Idempotency-Key header.
| Idempotency-Key | string Example: 7c1d1a52-0a55-4d2b-9f0e-3a4d7a2c9b10 A unique value (for example a UUID) identifying this request. Replaying the same key with the same body returns the original response instead of sending twice. |
| recipient required | string The phone number to send the code to. |
| sender_id required | string <= 11 characters Must be an approved sender ID on your account. |
| purpose | string <= 100 characters Default: "default" A tag that lets one number hold separate OTPs for different flows at the same time. |
| message | string <= 500 characters Custom message template. Must contain the |
| length | integer [ 4 .. 10 ] Default: 6 Code length. Values outside 4–10 are clamped to the nearest bound. |
| type | string Default: "numeric" Enum: "numeric" "alphanumeric" |
| expiry_minutes | integer [ 1 .. 60 ] Default: 10 How long the code is valid for. |
| max_attempts | integer [ 3 .. 10 ] Default: 5 Verify attempts allowed before the code is locked. |
object (OtpIssued) |
{- "recipient": "233241234567",
- "sender_id": "BLIBO",
- "purpose": "login"
}{- "data": {
- "reference": "5a8e0f3c-7b1d-4f6a-8c2e-1d9b7a4e6f30",
- "recipient": "233241234567",
- "status": "pending",
- "expires_at": "2026-07-19T21:30:00+00:00"
}
}Invalidates any still-pending OTP for the same recipient and purpose and
issues a new one. Accepts the same body as
Generate and send an OTP and is subject
to the same cooldown and daily limit. Supports the Idempotency-Key
header.
| Idempotency-Key | string Example: 7c1d1a52-0a55-4d2b-9f0e-3a4d7a2c9b10 A unique value (for example a UUID) identifying this request. Replaying the same key with the same body returns the original response instead of sending twice. |
| recipient required | string The phone number to send the code to. |
| sender_id required | string <= 11 characters Must be an approved sender ID on your account. |
| purpose | string <= 100 characters Default: "default" Must match the purpose of the OTP being replaced. |
object (OtpIssued) |
{- "recipient": "233241234567",
- "sender_id": "BLIBO",
- "purpose": "login"
}{- "data": {
- "reference": "5a8e0f3c-7b1d-4f6a-8c2e-1d9b7a4e6f30",
- "recipient": "233241234567",
- "status": "pending",
- "expires_at": "2026-07-19T21:30:00+00:00"
}
}Checks the code your user entered against the most recent OTP sent to that
recipient for the given purpose. Each incorrect attempt counts towards
the OTP's max_attempts.
| recipient required | string The phone number the code was sent to. A leading |
| code required | string The code the end-user entered. |
| purpose | string or null <= 100 characters Default: "default" Must match the purpose used when generating. |
object |
{- "recipient": "233241234567",
- "code": "482913",
- "purpose": "login"
}{- "data": {
- "status": "verified",
- "message": "OTP verified successfully."
}
}Looks up an OTP by the reference returned when it was generated. The code itself is never returned.
| reference required | string <uuid> Example: 5a8e0f3c-7b1d-4f6a-8c2e-1d9b7a4e6f30 The |
object (Otp) |
curl "https://sms.blibosolutions.com/api/v1/otp/5a8e0f3c-7b1d-4f6a-8c2e-1d9b7a4e6f30" \ -H "Authorization: Bearer bsms_YOUR_API_KEY" \ -H "Accept: application/json"
{- "data": {
- "reference": "5a8e0f3c-7b1d-4f6a-8c2e-1d9b7a4e6f30",
- "recipient": "233241234567",
- "purpose": "default",
- "status": "pending",
- "attempts_used": 1,
- "expires_at": "2026-07-19T21:30:00+00:00"
}
}List and request Sender IDs. A message can only be sent once its sender
ID has status approved.
Every sender ID requested on your account, newest first.
Array of objects (SenderId) |
curl "https://sms.blibosolutions.com/api/v1/sender-ids" \ -H "Authorization: Bearer bsms_YOUR_API_KEY" \ -H "Accept: application/json"
{- "data": [
- {
- "sender_id": "BLIBO",
- "purpose": "OTP and account alerts",
- "status": "approved",
- "rejection_reason": null,
- "requested_at": "2026-07-19T10:00:00+00:00"
}
]
}Submits a sender ID for review. New sender IDs always start as pending
and can be used to send once they are approved. The ID is stored in
upper case.
| sender_id required | string <= 11 characters ^[A-Za-z0-9]+$ Up to 11 letters and digits, no spaces. |
| purpose required | string <= 500 characters What this sender ID will be used for. |
object |
{- "sender_id": "BLIBO",
- "purpose": "OTP and account alerts"
}{- "data": {
- "sender_id": "BLIBO",
- "purpose": "OTP and account alerts",
- "status": "pending"
}
}Returns the SMS credits remaining on your account.
object (Balance) |
curl "https://sms.blibosolutions.com/api/v1/balance" \ -H "Authorization: Bearer bsms_YOUR_API_KEY" \ -H "Accept: application/json"
{- "data": {
- "sms_balance": 4200,
- "low_credits": false,
- "credits_expiry": null
}
}Get events pushed to your own systems instead of polling. Register a callback URL under Settings → WebHook Settings in your dashboard.
Each delivery is a POST with a JSON body, signed so you can verify it
came from BliboSMS: the X-Blibo-Signature header is the hex-encoded
HMAC-SHA256 of the raw request body, keyed with your webhook's
secret. Compute the same value on your side and compare it before
trusting the payload.
Respond with any 2xx status within 5 seconds. Failed deliveries are
not retried, so treat webhooks as a notification and use
GET /messages/{reference} as the source of truth.
Sent to your callback URL whenever the network reports a new status for a message. Subscribe a webhook to Delivery Report or All Events to receive it.
| X-Blibo-Signature required | string Example: 3f1c0b6e9a4d2f7c8b5e1a0d9c3f6b2e7a4d1c8f5b2e9a6d3c0f7b4e1a8d5c2f Hex-encoded HMAC-SHA256 of the raw request body, keyed with your webhook's secret. |
| event | string Value: "delivery_report" |
object | |
| timestamp | string <date-time> When the event was sent. |
{- "event": "delivery_report",
- "data": {
- "message_id": "9b2f6c1e-4d1a-4c57-9d0a-6f3f0c1e8a21",
- "status": "delivered",
- "recipient": "+233241234567",
- "sender_id": "BLIBO"
}, - "timestamp": "2026-07-19T10:00:05+00:00"
}