Modern Python client for the Safaricom M-PESA Daraja API.
- Complete API Coverage: STK Push, C2B, B2C, B2B, Reversals, Balance queries, and more
- Automatic Token Management: Handles OAuth token refresh automatically
- Type Hints: Full type annotations for better IDE support
- CLI Tool: Interactive command-line interface for testing and quick operations
- Modern Python: Built for Python 3.10+ with modern best practices
pip install pympesapip install pympesa[cli]from pympesa import Pympesa
# Initialize client
client = Pympesa(
consumer_key="your_consumer_key",
consumer_secret="your_consumer_secret",
env="sandbox" # or "production"
)
# Initiate STK Push
response = client.stk_push(
shortcode="174379",
passkey="your_passkey",
amount=100,
phone="254712345678",
callback_url="https://example.com/callback",
account_reference="Order123",
description="Payment for order"
)
print(response)
# {'MerchantRequestID': '...', 'CheckoutRequestID': '...', 'ResponseCode': '0', ...}First, set your credentials as environment variables:
export MPESA_CONSUMER_KEY=your_consumer_key
export MPESA_CONSUMER_SECRET=your_consumer_secretThen configure the CLI:
pympesa initNow you can use the CLI commands:
# Generate access token
pympesa auth
# Initiate STK Push
pympesa stk-push --phone 254712345678 --amount 100
# Query STK Push status
pympesa stk-query --checkout-id ws_CO_123456789
# View configuration
pympesa config --showfrom pympesa import Pympesa, Environment
client = Pympesa(
consumer_key="your_key",
consumer_secret="your_secret",
env=Environment.SANDBOX, # or Environment.PRODUCTION
timeout=30 # request timeout in seconds
)# Initiate payment
response = client.stk_push(
shortcode="174379",
passkey="your_passkey",
amount=100,
phone="254712345678",
callback_url="https://example.com/callback",
account_reference="Order123",
description="Payment",
transaction_type="CustomerPayBillOnline" # or "CustomerBuyGoodsOnline"
)
# Query status
status = client.stk_query(
shortcode="174379",
passkey="your_passkey",
checkout_request_id="ws_CO_123456789"
)# Register URLs
client.c2b_register_urls(
shortcode="600000",
confirmation_url="https://example.com/confirm",
validation_url="https://example.com/validate",
response_type="Completed" # or "Cancelled"
)
# Simulate (sandbox only)
client.c2b_simulate(
shortcode="600000",
phone="254712345678",
amount=100,
bill_ref_number="INV001"
)response = client.b2c_payment(
initiator_name="testapi",
security_credential="encrypted_credential",
shortcode="600000",
phone="254712345678",
amount=100,
result_url="https://example.com/result",
timeout_url="https://example.com/timeout",
command_id="BusinessPayment",
remarks="Salary payment"
)response = client.b2b_payment(
initiator_name="testapi",
security_credential="encrypted_credential",
sender_shortcode="600000",
receiver_shortcode="600001",
amount=1000,
result_url="https://example.com/result",
timeout_url="https://example.com/timeout",
command_id="BusinessPayBill",
account_reference="INV001"
)response = client.account_balance(
initiator_name="testapi",
security_credential="encrypted_credential",
shortcode="600000",
result_url="https://example.com/result",
timeout_url="https://example.com/timeout"
)response = client.transaction_status(
initiator_name="testapi",
security_credential="encrypted_credential",
shortcode="600000",
transaction_id="OEI2AK4Q16",
result_url="https://example.com/result",
timeout_url="https://example.com/timeout"
)response = client.reversal(
initiator_name="testapi",
security_credential="encrypted_credential",
shortcode="600000",
transaction_id="OEI2AK4Q16",
amount=100,
result_url="https://example.com/result",
timeout_url="https://example.com/timeout"
)response = client.tax_remittance(
initiator_name="testapi",
security_credential="encrypted_credential",
sender_shortcode="600000",
amount=500,
account_reference="PRN123456",
result_url="https://example.com/result",
timeout_url="https://example.com/timeout"
)from pympesa import Pympesa
from pympesa.cli.output import save_qr_code
client = Pympesa(...)
response = client.dynamic_qr(
merchant_name="My Store",
ref_no="INV123",
amount=100,
shortcode="174379",
transaction_type="BG", # BG=Buy Goods, PB=Pay Bill
size="300"
)
# Save the QR code image to a file
if "QRCode" in response:
file_path = save_qr_code(response["QRCode"], "my_qr_code.png")
print(f"QR code saved to: {file_path}")| Command | Description |
|---|---|
pympesa init |
Interactive setup wizard |
pympesa auth |
Generate and display access token |
pympesa stk-push |
Initiate STK Push payment |
pympesa stk-query |
Query STK Push status |
pympesa c2b-register |
Register C2B URLs |
pympesa c2b-simulate |
Simulate C2B transaction (sandbox) |
pympesa balance |
Query account balance |
pympesa reversal |
Reverse a transaction |
pympesa tax |
Remit tax to KRA |
pympesa b2b |
B2B payment |
pympesa dynamic-qr |
Generate a dynamic M-PESA QR code |
pympesa config |
View/manage configuration |
Use pympesa <command> --help for detailed options.
Generate a QR code and save as image:
pympesa dynamic-qr \
--merchant-name "My Store" \
--ref-no "INV001" \
--amount 500 \
--transaction-type BG \
--output qr_code.png \
--open # Opens the QR code image automaticallyThe --open flag will automatically open the generated QR code image in your default image viewer (macOS, Linux, or Windows).
| Variable | Description |
|---|---|
MPESA_CONSUMER_KEY |
Your M-PESA API consumer key |
MPESA_CONSUMER_SECRET |
Your M-PESA API consumer secret |
The CLI stores non-sensitive configuration in ~/.pympesa/config.json:
{
"environment": "sandbox",
"shortcode": "174379",
"passkey": "your_passkey",
"callback_url": "https://example.com/callback"
}Note: Credentials are never stored in the config file. Always use environment variables.
from pympesa import Pympesa, PympesaError, APIError, AuthenticationError
try:
response = client.stk_push(...)
except AuthenticationError as e:
print(f"Auth failed: {e}")
except APIError as e:
print(f"API error: {e}")
print(f"Status code: {e.status_code}")
print(f"Response: {e.response_data}")
except PympesaError as e:
print(f"Error: {e}")# Clone the repository
git clone https://github.com/pythias-io/pympesa.git
cd pympesa
# Create virtual environment
python -m venv .venv-pympesa
source .venv-pympesa/bin/activate
# Install with dev dependencies
pip install -e ".[dev,cli]"# Run all tests
pytest
# Run with coverage
pytest --cov=pympesa --cov-report=html
# Run specific test file
pytest tests/test_client.py -v- Go to Safaricom Developer Portal
- Create an account and log in
- Create a new app to get your Consumer Key and Consumer Secret
- Use sandbox credentials for testing, production for live transactions
MIT License - see LICENSE.txt for details.
Contributions are welcome! Please feel free to submit a Pull Request.