safcom
M-Pesa API — the way it should be.
STK push, payment queries, B2C, account balance — all in a clean Python package that doesn't make you read raw JSON.
pip install safcom
Quick Start
from safcom import Mpesa
mpesa = Mpesa(
consumer_key="your_key",
consumer_secret="your_secret",
passkey="your_passkey",
shortcode="174379",
env="sandbox", # or "production"
)
# One line. STK push. Done.
resp = mpesa.stk_push(
phone="254712345678",
amount=100,
account_ref="INV-001",
)
print(resp.checkout_request_id) # → "ws_CO_...202507..."
print(resp.customer_message) # → "Please enter your M-Pesa PIN"
Features
- STK Push — Initiate Lipa Na M-Pesa Online payments with one call
- STK Push Query — Check if a payment went through
- B2C — Send money to customers (BusinessPayment)
- Account Balance — Query your M-Pesa balance
- Callback handling — Decorator-based handler for M-Pesa notifications
- Automatic auth — Tokens refresh automatically; you never think about it
- Typed responses — Every response is a dataclass, not raw dicts
- CLI included — Test payments from the terminal
Usage
STK Push
# Minimal
resp = mpesa.stk_push(phone="254712345678", amount=500, account_ref="INV-001")
# With all options
resp = mpesa.stk_push(
phone="254712345678",
amount=500,
account_ref="INV-001",
transaction_desc="Payment for invoice INV-001",
callback_url="https://your-app.com/mpesa/callback",
)
Check Payment Status
status = mpesa.stk_push_query("ws_CO_...202507...")
if status.success:
print(f"Paid! Receipt: {status.receipt}")
else:
print(f"Not paid: {status.result_description}")
Send Money (B2C)
resp = mpesa.b2c(
phone="254712345678",
amount=500,
remarks="refund",
initiator_name="testapi",
security_credential="...",
)
Account Balance
resp = mpesa.account_balance(
initiator_name="testapi",
security_credential="...",
)
From the CLI
# Set credentials (or use SAFCOM_* env vars)
export SAFCOM_CONSUMER_KEY=your_key
export SAFCOM_CONSUMER_SECRET=your_secret
export SAFCOM_PASSKEY=your_passkey
export SAFCOM_SHORTCODE=174379
# Send STK push
safcom stkpush 254712345678 100 --ref INV-001
# Query payment status
safcom query ws_CO_...202507...
Why safcom?
The M-Pesa API is powerful but painful:
- Authentication is manual and easy to mess up
- Responses come in inconsistent formats between sandbox and production
- Error messages are cryptic
- Every Kenyan dev rewrites the same wrapper
safcom fixes all of that. Sensible defaults, typed responses, clear errors. One package, one pip install, done.
Roadmap
- STK Push
- STK Push Query
- B2C (BusinessPayment)
- Account Balance
- CLI
- C2B Register URL
- C2B Simulate
- Reversal
- Transaction Status
- Async support (httpx.AsyncClient)
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
safcom-0.1.0.tar.gz
(9.3 kB
view details)
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 safcom-0.1.0.tar.gz.
File metadata
- Download URL: safcom-0.1.0.tar.gz
- Upload date:
- Size: 9.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f8e45b1421e49ffcf597e447c166bbaa26de674c3c63fd968e8acd7aec2b3475
|
|
| MD5 |
c32fee8675825fe832a71aebbd311085
|
|
| BLAKE2b-256 |
ae18a44c2d93dd6728c6be3d0bdcc75053dc9d4b1a5bdbfbf9959ceccb559b51
|
File details
Details for the file safcom-0.1.0-py3-none-any.whl.
File metadata
- Download URL: safcom-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de3b7791a4eee7065bf7c27b89f6e291d087ec76f3f8244d6c7d1cb429316455
|
|
| MD5 |
1c690262c4b5669597a2bf47a5c2b6da
|
|
| BLAKE2b-256 |
95d062cb3ac0b54045a8c2d01cde638b2796ac9a9cccecc937928b5a5162cbd0
|