SMS
The client.sms resource handles single sends, client-side send-many, server-side bulk, message logs, and local message analysis.
Send a single message
Phone numbers are normalized to E.164 automatically; invalid numbers raise InvalidPhoneError before any network call:
result = client.sms.send(
to="0712345678",
message="Welcome to SendAfrica!",
sender="SENDAFRICA", # optional registered sender ID
)
print(result.message_id, result.credits_used)| Parameter | Type | Required | Notes |
|---|---|---|---|
to | string | Yes | Accepted formats: 0712345678, 255..., +255... |
message | string | Yes | Required |
sender | string | No | Registered sender ID; omits from from the payload when absent |
Returns an SMSResult dataclass: message_id, status, credits_used, cost, to.
Send many (client-side, paced)
N distinct messages, rate limited, with per-message failure collection instead of aborting on the first error:
results = client.sms.send_many(
messages=[
{"to": "0712345678", "message": "Hi Ali"},
{"to": "0765432109", "message": "Hi Zainab"},
],
rate_limit_per_sec=10.0, # default 10
sender="MYBRAND", # applied to all unless per-message overrides
)
print(results.sent_count, results.failed_count)
for r in results.results:
print(r.message_id, r.to)
for f in results.failed:
print(f["index"], f["to"], f["error"])Use this when your recipients each need a different message. For the same message to many numbers, prefer server-side bulk below.
Server-side bulk SMS
Send one message to many recipients in a single API call. The SDK caps at 100 recipients; the server returns partial failures per recipient and refunds them individually.
bulk = client.sms.bulk(
to=["0712345678", "0765432109"],
message="Black Friday starts now!",
sender="MYBRAND",
)
print(bulk.total, bulk.sent, bulk.failed)
for r in bulk.results:
print(r.to, r.status, r.message_id, r.error)The returned BulkSendResult exposes total, sent, failed, and results (per-recipient to, status, message_id, credits_used, error).
Message logs
logs = client.sms.logs(
page=1, per_page=25,
status="delivered", # pending | sent | delivered | failed
search="0712345678",
date_from="2026-09-01T00:00:00Z",
)
print(logs.total, logs.page, logs.total_pages)
for entry in logs.items:
print(entry.to_phone, entry.status, entry.credits_used, entry.sent_at)Client-side SMS analysis
Analyze a message locally — no network call — to predict encoding, part count, and credits:
analysis = client.sms.analyze("Hello world from SendAfrica 🇹🇿")
print(analysis.encoding, analysis.parts, analysis.credits)
# UCS-2 1 1 (emoji forces Unicode encoding)Returns an SMSAnalysis dataclass: encoding (“GSM-7” or “UCS-2”), characters, septets, parts, credits.
Reference
| Method | Endpoint | Returns |
|---|---|---|
sms.send(to, message, *, sender) | POST /sms | SMSResult |
sms.send_many(messages, *, sender, rate_limit_per_sec) | Loops POST /sms | BulkSMSResult |
sms.bulk(to, message, *, sender) | POST /sms/bulk | BulkSendResult |
sms.logs(page, per_page, status, search, date_from) | GET /sms/logs | MessageLogListResponse |
sms.analyze(message) | — (local) | SMSAnalysis |
Delivery confirmation is asynchronous — see Webhooks and Delivery Status.