Metadata-Version: 2.4
Name: malipopay
Version: 1.1.0
Summary: Official Python SDK for the Malipopay payment platform (Tanzania)
Project-URL: Homepage, https://malipopay.co.tz
Project-URL: Documentation, https://docs.malipopay.co.tz
Project-URL: Repository, https://github.com/lockwood-technology/malipopay-python
Project-URL: Issues, https://github.com/lockwood-technology/malipopay-python/issues
Author-email: Lockwood Technology Ltd <dev@lockwoodtechnology.co.tz>
License-Expression: MIT
License-File: LICENSE
Keywords: fintech,malipopay,mobile-money,mpesa,payments,tanzania
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
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: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Description-Content-Type: text/markdown

# Malipopay Python SDK

Official Python SDK for the [Malipopay](https://malipopay.co.tz) payment platform. Accept payments via Mobile Money (M-Pesa, Airtel Money, Mixx/YAS, Halopesa, T-Pesa), Bank Transfer (CRDB, NMB), USSD, and Card (Visa, Mastercard) in Tanzania.

## Installation

```bash
pip install malipopay
```

## Quick Start

```python
from malipopay import Malipopay

client = Malipopay("your-api-key")

# Collect payment via mobile money
payment = client.payments.collect({
    "description": "Order #1234",
    "amount": 10000,
    "phoneNumber": "255712345678",
})

print(payment["reference"])  # "PAY-abc123"
```

### Async Usage

```python
import asyncio
from malipopay import AsyncMalipopay

async def main():
    async with AsyncMalipopay("your-api-key") as client:
        payment = await client.payments.collect({
            "description": "Order #1234",
            "amount": 10000,
            "phoneNumber": "255712345678",
        })
        print(payment["reference"])

asyncio.run(main())
```

## Configuration

```python
client = Malipopay(
    "your-api-key",
    environment="uat",           # "production" (default) or "uat"
    timeout=30.0,                # Request timeout in seconds (default: 30)
    retries=2,                   # Auto-retry on 5xx/429 (default: 2)
    webhook_secret="whsec_...",  # For webhook signature verification
)
```

## Usage

### Payments

```python
# Collect payment
payment = client.payments.collect({
    "description": "Order #1234",
    "amount": 10000,
    "phoneNumber": "255712345678",
})

# Disburse funds
payout = client.payments.disburse({
    "description": "Salary payment",
    "amount": 50000,
    "phoneNumber": "255712345678",
})

# Verify payment status
status = client.payments.verify("PAY-abc123")

# Search payments
results = client.payments.search({
    "status": "COMPLETED",
    "from": "2026-01-01",
    "to": "2026-03-31",
})

# Create payment link
link = client.payments.create_link({
    "amount": 25000,
    "phoneNumber": "255712345678",
})
```

### Customers

```python
# Create customer
customer = client.customers.create({
    "phoneNumber": "255712345678",
    "firstname": "John",
    "lastname": "Doe",
    "email": "john@example.com",
})

# Search customers
customers = client.customers.search({"query": "John"})

# Verify customer
verified = client.customers.verify("255712345678")
```

### Invoices

```python
# Create invoice
invoice = client.invoices.create({
    "customer": "customer-id",
    "items": [
        {"description": "Web Development", "quantity": 1, "unitPrice": 500000},
    ],
    "dueDate": "2026-05-01",
    "currency": "TZS",
    "taxRate": 18,
})

# Record payment against invoice
client.invoices.record_payment({
    "invoiceId": "invoice-id",
    "amount": 500000,
    "reference": "PAY-abc123",
})
```

### Products

```python
product = client.products.create({
    "name": "Monthly Subscription",
    "price": 25000,
    "currency": "TZS",
    "category": "subscription",
})
```

### Transactions

```python
transactions = client.transactions.list()
tx = client.transactions.get("tx-id")
search = client.transactions.search({"status": "COMPLETED"})
```

### Account

```python
balance = client.account.transactions()
reconciliation = client.account.reconciliation()
```

### SMS

```python
# Send single SMS
client.sms.send({
    "sender": "MALIPOPAY",
    "phoneNumber": "255712345678",
    "message": "Your payment was received!",
})

# Send bulk SMS
client.sms.send_bulk({
    "sender": "MALIPOPAY",
    "phoneNumber": ["255712345678", "255713456789"],
    "message": "Special offer!",
})
```

### Reference Data

```python
banks = client.references.banks()
currencies = client.references.currencies()
countries = client.references.countries()
```

## Webhook Handling

```python
from malipopay import Malipopay

client = Malipopay("your-api-key", webhook_secret="whsec_your_secret")

# Verify and parse webhook
event = client.webhooks.construct_event(
    payload=raw_body,                                  # request body as string or bytes
    signature=request.headers["x-malipopay-signature"],  # signature header
)

if event["type"] == "payment.completed":
    print("Payment completed:", event["data"])
elif event["type"] == "payment.failed":
    print("Payment failed:", event["data"])
```

### Flask Example

```python
from flask import Flask, request
from malipopay import Malipopay, MalipopayError

app = Flask(__name__)
client = Malipopay("your-api-key", webhook_secret="whsec_your_secret")

@app.route("/webhooks", methods=["POST"])
def handle_webhook():
    try:
        event = client.webhooks.construct_event(
            payload=request.get_data(as_text=True),
            signature=request.headers.get("x-malipopay-signature", ""),
        )
        print(f"Event: {event['type']}")
        return {"received": True}
    except MalipopayError as e:
        return {"error": str(e)}, 400
```

## Error Handling

```python
from malipopay import Malipopay, AuthenticationError, ValidationError

try:
    client.payments.collect({...})
except AuthenticationError:
    print("Invalid API key")
except ValidationError as e:
    print(f"Validation failed: {e.message}")
```

Error types: `AuthenticationError` (401), `PermissionError` (403), `NotFoundError` (404), `ValidationError` (422), `RateLimitError` (429), `ApiError` (5xx), `ConnectionError` (network).

## Requirements

- Python 3.8+
- Malipopay API key ([get one here](https://app.malipopay.co.tz))

## License

MIT


---

## See Also

| SDK | Install |
|-----|---------|
| [Node.js](https://github.com/Malipopay/malipopay-node) | `npm install malipopay` |
| [Python](https://github.com/Malipopay/malipopay-python) | `pip install malipopay` |
| [PHP](https://github.com/Malipopay/malipopay-php) | `composer require malipopay/malipopay-php` |
| [Java](https://github.com/Malipopay/malipopay-java) | Maven / Gradle |
| [.NET](https://github.com/Malipopay/malipopay-dotnet) | `dotnet add package Malipopay` |
| [Ruby](https://github.com/Malipopay/malipopay-ruby) | `gem install malipopay` |

[API Reference](https://developers.malipopay.co.tz) | [OpenAPI Spec](https://github.com/Malipopay/malipopay-openapi) | [Test Scenarios](https://github.com/Malipopay/malipopay-sdk-tests)

