Metadata-Version: 2.4
Name: mainfinity-django-mpesa
Version: 0.1.0
Summary: A production-hardened Django app for Safaricom's Daraja M-PESA API
Project-URL: Homepage, https://github.com/mainfinity/django-mpesa
Project-URL: Documentation, https://django-mpesa.readthedocs.io
Project-URL: Repository, https://github.com/mainfinity/django-mpesa
Project-URL: Issues, https://github.com/mainfinity/django-mpesa/issues
Project-URL: Changelog, https://github.com/mainfinity/django-mpesa/blob/main/CHANGELOG.md
License: MIT
License-File: LICENSE
Keywords: daraja,django,kenya,mpesa,payments,safaricom
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.1
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: django>=4.2
Requires-Dist: djangorestframework>=3.14
Requires-Dist: requests>=2.31
Provides-Extra: celery
Requires-Dist: celery>=5.3; extra == 'celery'
Provides-Extra: dev
Requires-Dist: django-mpesa[celery,docs,test]; extra == 'dev'
Requires-Dist: mypy>=1.5; extra == 'dev'
Requires-Dist: pip-audit>=2.6; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Requires-Dist: tox>=4.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.4; extra == 'docs'
Provides-Extra: test
Requires-Dist: factory-boy>=3.3; extra == 'test'
Requires-Dist: pytest-cov>=4.1; extra == 'test'
Requires-Dist: pytest-django>=4.7; extra == 'test'
Requires-Dist: pytest>=7.4; extra == 'test'
Requires-Dist: responses>=0.24; extra == 'test'
Description-Content-Type: text/markdown

# django-mpesa

[![PyPI version](https://img.shields.io/pypi/v/django-mpesa.svg)](https://pypi.org/project/django-mpesa/)
[![CI](https://github.com/mainfinity/django-mpesa/actions/workflows/test.yml/badge.svg)](https://github.com/mainfinity/django-mpesa/actions/workflows/test.yml)
[![Coverage](https://codecov.io/gh/mainfinity/django-mpesa/branch/main/graph/badge.svg)](https://codecov.io/gh/mainfinity/django-mpesa)
[![Python versions](https://img.shields.io/pypi/pyversions/django-mpesa.svg)](https://pypi.org/project/django-mpesa/)
[![Django versions](https://img.shields.io/badge/django-4.2%20%7C%205.0-blue)](https://pypi.org/project/django-mpesa/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)

A production-hardened Django app for Safaricom's Daraja M-PESA API.

Extracted from production use in [Zaruni](https://zaruni.com) and packaged for reuse across any Django project that needs to collect or send money via M-PESA.

---

## Features

- **STK Push** — trigger the M-PESA PIN prompt on a customer's phone
- **C2B** — receive paybill/till payments with validation and confirmation callbacks
- **B2C** — send payouts, salaries, or refunds to phone numbers
- **Transaction Status** — query stuck payments for reconciliation
- **Account Balance** — check your M-PESA business account balance
- **Reversal** — reverse a transaction programmatically
- **Idempotent callbacks** — Safaricom retries are handled safely; a payment is settled exactly once
- **IP allowlist middleware** — rejects callbacks from non-Safaricom sources
- **Mock client** — full test suite runs with zero network access; ships a `MockDarajaClient` for your own tests
- **Swappable models** — subclass the abstract models and add your own fields (orders, users, wallets)
- **Django signals** — hook into `payment_confirmed`, `payout_completed`, etc. without modifying library code

## Requirements

- Python 3.10, 3.11, or 3.12
- Django 4.2 or 5.0
- djangorestframework ≥ 3.14
- requests ≥ 2.31
- Celery ≥ 5.3 *(optional — set `USE_CELERY=False` for synchronous processing)*

## Installation

```bash
pip install django-mpesa

# With Celery support:
pip install django-mpesa[celery]
```

## Quick start

See the full [quickstart guide](https://django-mpesa.readthedocs.io/quickstart/) to go from install to a working STK Push in under 10 minutes.

```python
# 1. Add to INSTALLED_APPS
INSTALLED_APPS = [
    ...
    "django_mpesa",
]

# 2. Configure
MPESA = {
    "ENV": "sandbox",
    "CONSUMER_KEY": lambda: os.environ["MPESA_CONSUMER_KEY"],
    "CONSUMER_SECRET": lambda: os.environ["MPESA_CONSUMER_SECRET"],
    "SHORTCODE": "174379",
    "PASSKEY": lambda: os.environ["MPESA_PASSKEY"],
    "STK_CALLBACK_URL": "https://yourapp.com/mpesa/stk/callback/",
    "TRANSACTION_MODEL": "myapp.MpesaTransaction",
    "CALLBACK_LOG_MODEL": "myapp.MpesaCallbackLog",
}

# 3. Include URLs
urlpatterns = [
    path("mpesa/", include("django_mpesa.urls")),
]

# 4. Initiate a payment
from django_mpesa.services import STKPushService

txn = STKPushService().initiate(
    phone_number="254712345678",
    amount=100,
    account_reference="INV-001",
    transaction_desc="Payment",
)

# 5. React to the callback
from django.dispatch import receiver
from django_mpesa.signals import payment_confirmed

@receiver(payment_confirmed)
def on_payment(sender, transaction, **kwargs):
    order = transaction.order
    order.mark_paid()
```

## Documentation

Full documentation at [django-mpesa.readthedocs.io](https://django-mpesa.readthedocs.io).

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md). All PRs touching `tasks.py` must include or update the idempotency concurrency test.

## License

MIT — see [LICENSE](LICENSE).
