Skip to main content

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 call transport.request(...) without await internally, which works for the sync client but not yet for async — Phase 2 work is wiring await through SMSResource/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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sendafrica-1.0.1.tar.gz (17.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sendafrica-1.0.1-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

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

Hashes for sendafrica-1.0.1.tar.gz
Algorithm Hash digest
SHA256 abe452d70eb27e0096eb8726051bc81af5f0c199a4dec49bc3ea14f1cdb07073
MD5 59cea498bbbac5f915ed06dac5897b68
BLAKE2b-256 fea298930085eaea5525ee10a1940498447341c93047bab4aa6a618d635ab9f9

See more details on using hashes here.

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

Hashes for sendafrica-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 97ae6bf7f307bf3ad0840c228f11578d05ea7598183c209cb875316d5c020470
MD5 bd1eb25a3cdc6da9361204c7a8f4d43a
BLAKE2b-256 193cb8fc6cd115d210674bd5c5d751d1c16ce8d625100b5ca420b276771ac2dc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page