Skip to content

Send an SMS

POSThttps://api.9bits.net/ng/v1/sendsms

Queues a message for one or more recipients.

FieldTypeRequiredDescription
fromstringYour approved sender ID — the name recipients see. Unapproved IDs fail with sender_id_invalid. See Sender IDs.
toarrayDestinations in international format. Strings or integers both accepted; strings preferred. See Phone numbers.
contentstringThe message text.
delivery_reportbooleanRequest delivery receipts. Defaults to false.
callback_urlstringHTTPS endpoint for receipts. Overrides the account webhook for this batch.
HeaderRequiredDescription
AuthorizationBearer YOUR_API_TOKEN
Content-Typeapplication/json
Idempotency-KeyMakes the request safely retryable. Strongly recommended.
Terminal window
curl -X POST https://api.9bits.net/ng/v1/sendsms \
-H "Authorization: Bearer $NINEBITS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"from": "9bits",
"to": ["2348020000000", "2348030000000"],
"content": "Flash sale: 20% off everything today only.",
"delivery_report": true,
"callback_url": "https://example.com/webhooks/9bits/dlr"
}'
{
"reference_id": "fdab8f46df049e58b0af7c2d7",
"status": "accepted",
"accepted_at": "2026-07-14T18:48:14+01:00",
"recipients_accepted": 2,
"status_url": "/ng/v1/sendsms/status/fdab8f46df049e58b0af7c2d7",
"cost_estimate": {
"total_cost": 6.4,
"currency": "NGN",
"pages": 1,
"accepted_recipients": 2,
"unknown_operator_count": 0,
"sufficient": true,
"per_operator": {
"mtn": { "recipients": 1, "cost": 3.2 },
"airtel": { "recipients": 1, "cost": 3.2 }
}
}
}
FieldMeaning
reference_idStore this. It’s how you track the batch.
statusAlways accepted here. Queued, not delivered.
accepted_atRFC-3339, Africa/Lagos.
recipients_acceptedCount after normalisation and de-duplication — may be lower than what you sent.
status_urlRelative path to poll.
cost_estimateWhat this batch costs. See below.
FieldMeaning
total_costTotal for the batch — all recipients × all pages.
currencyAccount currency, e.g. NGN.
pagesPages one message consumes. 160 chars (GSM-7) or 70 (UCS-2).
accepted_recipientsRecipients priced into total_cost.
unknown_operator_countUnroutable prefixes. Rejected, not charged — but never delivered.
sufficientWhether your balance covers total_cost.
per_operatorBreakdown by network.
{
"error": {
"type": "validation_error",
"code": "sender_id_invalid",
"message": "sender ID '9bits' is not approved for this account"
}
}

Branch on code. Full list in the Error reference.

Now that you can send, learn how to find out whether it actually arrived.