Official Python SDK for the SendAfrica SMS Infrastructure-as-a-Service API
Project description
SendAfrica Python SDK
Official Python client for the SendAfrica SMS Infrastructure-as-a-Service API. Designed to feel like Stripe's Python library: simple for a first integration, enough control for production use.
Install
pip install sendafrica
# for the async client:
pip install "sendafrica[async]"
Quickstart
from sendafrica import SendAfrica
client = SendAfrica(api_key="sk_live_xxxxx")
result = client.sms.send(to="0712345678", message="Welcome to SendAfrica")
print(result.message_id, result.status, result.credits_used)
The API key can also be set via the SENDAFRICA_API_KEY environment
variable, in which case SendAfrica() needs no arguments.
Configuration
client = SendAfrica(
api_key="key",
timeout=30, # seconds, default 10
max_retries=3, # default 3, retries on 429/5xx and connection errors
environment="production",
debug=True, # logs each request/response to stdout
)
Resources
| Resource | Methods |
|---|---|
client.sms |
send, send_many, analyze |
client.credits |
balance, history |
client.packages |
list |
client.payments |
create |
client.webhooks |
parse |
packages.get(id) and payments.get/list don't exist: the API only
exposes GET /v1/packages (list) and POST /v1/payments/ (create) to API
key callers — fetching/listing individual payment orders is an
admin-console (JWT + is_admin) feature with no API-key equivalent.
SMS
client.sms.send(to="0712345678", message="Your OTP is 123456", sender="MyBrand")
results = client.sms.send_many([
{"to": "0711111111", "message": "Hello John"},
{"to": "0722222222", "message": "Hello Mary"},
])
print(results.sent_count, results.failed_count)
analysis = client.sms.analyze("Habari 😊")
# SMSAnalysis(encoding="UCS-2", characters=8, parts=1, credits=1)
Phone numbers are normalized locally (e.g. 0712345678 → +255712345678)
before any network call, and invalid numbers raise InvalidPhoneError
without hitting the API.
Credits & Packages
balance = client.credits.balance()
history = client.credits.history(page=1, per_page=20)
packages = client.packages.list()
Payments
payment = client.payments.create(
package_id="pkg-pro",
provider="mpesa",
amount=50000,
phone="+255712345678",
)
Webhooks (FastAPI example)
Status: speculative. The SendAfrica API does not yet forward signed events to customer endpoints — this resource is ready for when that ships server-side.
from fastapi import Request
@app.post("/webhooks/sendafrica")
async def webhook(request: Request):
event = client.webhooks.parse(
await request.body(),
signature=request.headers.get("X-SendAfrica-Signature"),
)
if event.type == "sms.delivered":
print(event.message_id)
Errors
All errors inherit from SendAfricaError:
from sendafrica.exceptions import InsufficientCreditsError
try:
client.sms.send(to="0712345678", message="hello")
except InsufficientCreditsError:
print("Please buy credits")
| Exception | Meaning |
|---|---|
AuthenticationError |
invalid/missing API key |
ValidationError |
bad request payload |
InvalidPhoneError |
phone number failed validation |
InsufficientCreditsError |
not enough SMS credits |
RateLimitError |
too many requests (.retry_after in seconds) |
NotFoundError |
resource does not exist |
ServerError |
5xx from the API |
APIConnectionError |
network/timeout failure |
WebhookSignatureError |
webhook signature mismatch |
CLI
export SENDAFRICA_API_KEY="SA_d10f5f01a8fc34415522edef675fc3e3b4487c11"
sendafrica balance
sendafrica sms send --to 0712345678 --message "Hello"
Async
from sendafrica import AsyncSendAfrica
client = AsyncSendAfrica(api_key="key")
result = await client.sms.send(to="0712345678", message="Hello")
await client.aclose()
Status: the async transport (
AsyncSendAfrica, httpx-based, with retries/backoff) is implemented. Resource classes currently calltransport.request(...)withoutawaitinternally, which works for the sync client but not yet for async — Phase 2 work is wiringawaitthroughSMSResource/CreditsResource/etc. (or splitting async-aware resource variants). Tracked as the next task before shipping async support.
Project layout
sendafrica/
├── client.py # SendAfrica, AsyncSendAfrica
├── http.py # HTTPTransport, AsyncHTTPTransport (retries, auth, error mapping)
├── auth.py # API key resolution
├── exceptions.py # error hierarchy
├── models.py # response dataclasses
├── cli.py # `sendafrica` command
├── resources/
│ ├── sms.py
│ ├── credits.py
│ ├── payments.py
│ ├── packages.py
│ └── webhooks.py
└── utils/
├── phone.py # E.164 normalization
├── sms.py # GSM-7/UCS-2 encoding + segment analysis
└── validators.py
Roadmap
- Phase 1 (done): client, auth, SMS send, balance, packages, payments, errors, types
- Phase 2: finish async resource wiring, bulk SMS rate-limiting polish, CLI expansion
- Phase 3: campaigns, contacts, templates, scheduling
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sendafrica-1.0.1.tar.gz.
File metadata
- Download URL: sendafrica-1.0.1.tar.gz
- Upload date:
- Size: 17.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abe452d70eb27e0096eb8726051bc81af5f0c199a4dec49bc3ea14f1cdb07073
|
|
| MD5 |
59cea498bbbac5f915ed06dac5897b68
|
|
| BLAKE2b-256 |
fea298930085eaea5525ee10a1940498447341c93047bab4aa6a618d635ab9f9
|
File details
Details for the file sendafrica-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sendafrica-1.0.1-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97ae6bf7f307bf3ad0840c228f11578d05ea7598183c209cb875316d5c020470
|
|
| MD5 |
bd1eb25a3cdc6da9361204c7a8f4d43a
|
|
| BLAKE2b-256 |
193cb8fc6cd115d210674bd5c5d751d1c16ce8d625100b5ca420b276771ac2dc
|