Africa's Talking SMS wrapper for Kenya — bilingual templates, delivery tracking, bulk sending.
Project description
kenya-sms
Africa's Talking SMS wrapper for Kenya — bilingual templates, delivery tracking, bulk sending.
SMS is the primary notification channel for Kenya. This library wraps the Africa's Talking API with the patterns that production Kenya systems actually need: bilingual English/Kiswahili templates, phone number normalisation, delivery receipt tracking, rate-limit backoff, and bulk broadcast sending.
Install
pip install kenya-sms
Quickstart
from kenya_sms import SMSClient, Templates, Language
client = SMSClient(
api_key="your_at_api_key",
username="your_at_username",
sender_id="MYAPP", # Registered with Communications Authority of Kenya
)
# Single message — phone normalised automatically
result = client.send("0712345678", "Your order is confirmed.")
print(result.succeeded, result.cost) # True, "KES 1.0000"
# Bilingual template — user's language preference
result = client.send_template(
"254712345678",
Templates.CONTRIBUTION_RECEIVED,
language=Language.KISWAHILI,
name="Jane", amount="2,000", cycle="January", receipt="NLJ7RT61SV",
)
# → "Habari Jane, mchango wako wa KES 2,000 kwa January umepokelewa. Risiti: NLJ7RT61SV."
Bilingual templates
All templates render in English or Kiswahili with the same variables:
from kenya_sms import Template, Language
# Built-in templates
Templates.CONTRIBUTION_RECEIVED # Chama contribution confirmed
Templates.CONTRIBUTION_REMINDER # Upcoming contribution due
Templates.LOAN_APPROVED # Loan disbursement notice
Templates.DROUGHT_ALERT # OpenResilience early warning
Templates.PAYMENT_PROMPT # M-Pesa payment instructions
Templates.OTP # Verification code
# Custom template
tpl = Template(
en="Dear {name}, your loan repayment of KES {amount} is due on {date}.",
sw="Habari {name}, malipo yako ya mkopo ya KES {amount} yanastahili tarehe {date}.",
)
msg = tpl.render(Language.KISWAHILI, name="John", amount="4,333", date="31 Jan")
parts = tpl.sms_parts(Language.KISWAHILI, name="John", amount="4,333", date="31 Jan")
# → 1 part (within 160 chars)
Phone number normalisation
Accepts any Kenyan format:
from kenya_sms import normalise_phone
normalise_phone("0712345678") # → "254712345678"
normalise_phone("+254712345678") # → "254712345678"
normalise_phone("712345678") # → "254712345678"
normalise_phone("0112345678") # → "254112345678" (Safaricom Home)
Bulk sending
# Different message per recipient
results = client.send_bulk([
("0712345678", "Your contribution for January is confirmed."),
("0723456789", "Mchango wako wa Januari umethibitishwa."),
("0734567890", "Your contribution is pending. Please pay by Friday."),
])
# Same message to many — uses AT's batch endpoint
results = client.send_broadcast(
phones=["0712345678", "0723456789", "0734567890"],
message="Chama meeting Saturday 10am at the usual venue.",
)
successful = [r for r in results if r.succeeded]
Delivery tracking
# Mount at your AT delivery report callback URL
@app.post("/sms/delivery")
async def delivery_report(request: Request):
payload = await request.json()
receipt = client.handle_delivery_receipt(payload)
return {"status": "ok"}
# Query later
store = client.delivery_store
failed = store.failed() # Messages that did not deliver
print(f"{len(failed)} undelivered messages")
Sandbox mode
client = SMSClient(
api_key="sandbox",
username="sandbox",
sandbox=True, # Routes to AT sandbox — no real SMS sent
)
Use with OpenResilience
from kenya_sms import SMSClient, Templates, Language
from kenya_counties import get
# Send drought alert to all Turkana subscribers
turkana = get("Turkana")
client = SMSClient(api_key=AT_KEY, username=AT_USER, sender_id="RESILIENCE")
for subscriber_phone in get_turkana_subscribers():
client.send_template(
subscriber_phone,
Templates.DROUGHT_ALERT,
Language.KISWAHILI,
county=turkana.name,
level="Kali",
deficit="48",
action="kuvuna mapema",
)
Design decisions
Zero runtime dependencies. The Africa's Talking API is a simple REST + form-encoded endpoint. urllib.request handles it without httpx or requests.
Template-first design. In production Kenya systems, the same message goes out in both languages constantly. Encoding this as a first-class type — not a function or a string — means templates are testable, reusable, and auditable.
Phone normalisation is non-negotiable. Kenyan users enter phone numbers in at least four different formats. Failing on anything other than E.164 means real users get dropped. The normaliser accepts all common formats and rejects genuinely invalid input.
Part of the nairobi-stack East Africa engineering ecosystem. Maintained by Gabriel Mahia. Kenya × USA.
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 kenya_sms-1.0.0.tar.gz.
File metadata
- Download URL: kenya_sms-1.0.0.tar.gz
- Upload date:
- Size: 8.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a4da3cb9e1481132fbb543aa5f21baf6d511daf1bc403936197d8e88f4804ab
|
|
| MD5 |
a2c6b506a3a19d84a560b10bf4dad5da
|
|
| BLAKE2b-256 |
6fc4687e1b5a78691bb7f0977605084d809453ac383bedbb0ed09d85b8c8521a
|
Provenance
The following attestation bundles were made for kenya_sms-1.0.0.tar.gz:
Publisher:
publish.yml on gabrielmahia/kenya-sms
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kenya_sms-1.0.0.tar.gz -
Subject digest:
0a4da3cb9e1481132fbb543aa5f21baf6d511daf1bc403936197d8e88f4804ab - Sigstore transparency entry: 1123019773
- Sigstore integration time:
-
Permalink:
gabrielmahia/kenya-sms@e62d21c6716bdee434d6086c5626610426cea955 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/gabrielmahia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e62d21c6716bdee434d6086c5626610426cea955 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kenya_sms-1.0.0-py3-none-any.whl.
File metadata
- Download URL: kenya_sms-1.0.0-py3-none-any.whl
- Upload date:
- Size: 8.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e0a80aa2e8b3d20769e709aa0c3f96e9e35c5597f4f983e1461bb652cdc3e75
|
|
| MD5 |
edae8ed46ef7492b4563d0d66607208d
|
|
| BLAKE2b-256 |
70593a224f3e72e9ce03c5e4b7dcab90cc09cdfb099198375ddf350e83898648
|
Provenance
The following attestation bundles were made for kenya_sms-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on gabrielmahia/kenya-sms
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kenya_sms-1.0.0-py3-none-any.whl -
Subject digest:
2e0a80aa2e8b3d20769e709aa0c3f96e9e35c5597f4f983e1461bb652cdc3e75 - Sigstore transparency entry: 1123019777
- Sigstore integration time:
-
Permalink:
gabrielmahia/kenya-sms@e62d21c6716bdee434d6086c5626610426cea955 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/gabrielmahia
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e62d21c6716bdee434d6086c5626610426cea955 -
Trigger Event:
push
-
Statement type: