Metadata-Version: 2.4
Name: lmbtech
Version: 1.1.0
Summary: Python SDK for the LMBTech payment gateway. Supports MTN MoMo, Airtel Money, and card payments in Rwanda.
Author-email: IRANKUNDA Elyssa <elyssa001ely@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/ielyssa/lmbtech-payment-gateway
Project-URL: Repository, https://github.com/ielyssa/lmbtech-payment-gateway
Project-URL: Bug Tracker, https://github.com/ielyssa/lmbtech-payment-gateway/issues
Project-URL: Documentation, https://github.com/ielyssa/lmbtech-payment-gateway#readme
Keywords: lmbtech,payment,momo,mtn,airtel,rwanda,mobile money,pesapal,gateway
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business :: Financial
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28.0
Provides-Extra: django
Requires-Dist: django>=4.2; extra == "django"
Provides-Extra: async
Requires-Dist: httpx>=0.27; extra == "async"
Provides-Extra: models
Requires-Dist: pydantic>=2.5; extra == "models"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-django; extra == "dev"
Requires-Dist: hypothesis; extra == "dev"
Requires-Dist: responses; extra == "dev"
Requires-Dist: freezegun; extra == "dev"
Requires-Dist: coverage[toml]; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: mypy; extra == "dev"
Requires-Dist: pip-audit; extra == "dev"
Requires-Dist: bandit; extra == "dev"
Dynamic: license-file

# lmbtech

**Python SDK for the [LMBTech](https://pay.lmbtech.rw) payment gateway —
MTN MoMo · Airtel Money · Card payments (PesaPal) in Rwanda.**

Built and maintained by [ATAS — Alliance for Transformative AI Systems](https://github.com/ielyssa).

📚 **Full documentation: [DOCS.md](DOCS.md)** · Upgrading from 1.0.x:
[MIGRATION.md](MIGRATION.md) · Going live: [DEPLOYMENT.md](DEPLOYMENT.md)

---

## Why this SDK?

LMBTech's official documentation is minimal and inconsistent. This SDK
abstracts everything discovered through live testing, and adds the safety
properties a payment library must have:

| | |
|---|---|
| 💰 MTN + Airtel MoMo (USSD), Card via PesaPal | one client, unified status checks |
| 🛡️ Exactly-once fulfillment | duplicate workers can't double-deliver hooks |
| 🔒 No webhooks to forge | polling is the single source of truth |
| 🧮 Exact money math | whole-RWF Decimals; ~5% fee handled two ways |
| 🩹 Ambiguity-safe charges | `collect_verified()` heals network errors by polling |
| 🕵️ PII-redacted logs | phones masked, emails pseudonymized, injection-safe |
| ⚙️ Batteries included | Django mixin + Celery tasks + transactional outbox + daily reconciliation sweep |
| 🔁 Future-proof | async client, strict pydantic models, multi-provider protocol |

Undocumented gateway behavior handled for you: collect timeouts that still
initiate, 12–15-minute cancellation lag, permanent reference-ID consumption,
the never-called-but-required `callback_url`, the 100 RWF minimum.

---

## Installation

```bash
pip install lmbtech                # core SDK
pip install "lmbtech[django]"     # + Django integration
pip install "lmbtech[async]"      # + httpx async client
pip install "lmbtech[models]"     # + strict pydantic models
```

Requires Python 3.9+, `requests>=2.28`.

---

## Quick start

```python
from lmbtech import LMBTechClient, generate_reference_id

client = LMBTechClient(app_key="app_...", secret_key="scrt_...")

result = client.momo.collect_verified(
    phone="0788123456",
    amount=1000,                                  # customer sees 1050 RWF
    reference_id=generate_reference_id("ORD"),
    email="customer@example.com",
    name="Jane Uwimana",
    callback_url="https://yourapp.rw/payments/",   # required, never called
    service_paid="Subscription",
)

if result.success:
    print("USSD prompt sent —", result.reference_id)
```

Confirm before fulfilling — polling is the only truth:

```python
status = client.momo.status(result.reference_id)
if status.is_paid:
    fulfill_order(status.reference_id)
```

Card payments return a PesaPal redirect instead of a USSD prompt — send it
to React **only when `result.is_trusted`**, then poll status exactly the
same way. Full walkthrough: [DOCS.md §5–6](DOCS.md#5-mobile-money-guide).

---

## Django in four steps

```python
# 1. model
class Payment(LMBTechPaymentMixin):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

# 2. AppConfig.ready()
LMBTechConfig.setup(
    payment_model="myapp.Payment",
    on_payment_success=fulfill_order,
    on_payment_failed=reject_order,
    on_payment_expired=cleanup_checkout,
    use_outbox=True,                       # retryable hook delivery
    outbox_model="myapp.HookOutboxRow",
    log_events=True,
    event_model="myapp.PaymentEvent",
)

# 3+4. copy-paste Celery tasks & beat schedule → DOCS.md §8
```

Includes a reconciliation sweep that catches customers who approve *after*
the 20-minute window (`manage.py lmbtech_reconcile`).

---

## Lifecycle at a glance

```
pending ── approve(~30s) ──► success ✅        pending ── reject ──► failed ❌
   │ 5 min                                        │ 20 min total
   ▼                                              ▼
timeout ── cancel confirmed (~12-15 min) ► failed     expired 🌙
              └── late approval ► success ✅          └─ reconcile sweep reopens
```

---

## Security

Environment-only secrets · PII-redacted, injection-safe logging · fail-closed
response parsing · atomic guarded transitions · card-redirect host allowlist
· exact-decimal money · PCI SAQ-A posture preserved (card data never touches
your servers).

Details and disclosure policy: [SECURITY.md](SECURITY.md).

---

## Development

```powershell
python -m venv .venv
.venv\Scripts\pip install -e ".[django,async,models,dev]"
pre-commit install
pytest --ignore=tests/live     # 358-test offline suite, 100% coverage
```

CI gates every push with ruff, mypy, bandit, pip-audit, gitleaks and the test
suite (Python 3.9–3.13). Releases publish to PyPI via Trusted Publishing on
`v*` tags — no API tokens exist anywhere.

---

## License

MIT — see [LICENSE](LICENSE).
**Author:** IRANKUNDA Elyssa / [ATAS](https://github.com/ielyssa) ·
Repository: https://github.com/ielyssa/lmbtech-payment-gateway
