Metadata-Version: 2.4
Name: payaza
Version: 1.0.0
Summary: Unofficial Python SDK for the Payaza Africa API
Author-email: Shagbaor Agber <dxtlive@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/0xAfterSnow/payaza-python
Project-URL: Documentation, https://docs.payaza.africa
Project-URL: Bug Tracker, https://github.com/0xAfterSnow/payaza-python/issues
Keywords: payaza,payments,africa,fintech,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: responses>=0.25; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Dynamic: license-file

# Payaza Python SDK

> Unofficial Python SDK for the [Payaza Africa](https://payaza.africa) API.

[![Python](https://img.shields.io/badge/python-3.8%2B-blue)](https://www.python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## Installation

```bash
pip install payaza
```

For local development:

```bash
git clone https://github.com/0xAfterSnow/payaza-python
cd payaza-python
pip install -e ".[dev]"
```

---

## Quick start

```python
from payaza import Payaza

# Live
client = Payaza(api_key="your-live-key")

# Test / sandbox — uses X-TenantID: test on APIs that require it
client = Payaza(api_key="your-test-key", sandbox=True)
```

Payaza uses a **single** base URL (`https://api.payaza.africa`) with a fixed `/live/` path prefix for both environments. Test vs live is controlled by your API key and, where required, `X-TenantID`.

### Authentication headers

| Header | When |
|--------|------|
| `Authorization: Payaza <base64-key>` | Always |
| `X-TenantID: test \| live` | Only APIs that require it (transfers, account enquiry, bank codes, sub-accounts, MoMo collections, …) |
| `X-ProductID: app` | **Only** MoMo / XOF / ZAR / SLE collections |

The SDK does **not** attach tenant/product headers globally. Resource methods that need them call `client.tenant_headers()` or `client.product_headers()` internally.

See the official [authentication guide](https://docs.payaza.africa/guides/authentication#required-headers-by-api).

### Webhooks

Payaza signs each webhook body with HMAC-SHA512 and sends the Base64 digest in `x-payaza-signature`. Hash the raw request body with your webhook secret (not Base64-encoded):

```python
from payaza import verify_signature

def handle(raw_body: bytes, signature: str, secret: str) -> None:
    if not verify_signature(raw_body, signature, secret):
        raise PermissionError("invalid webhook signature")
```

### Signed transfers

Accounts activated by Payaza for signed payouts send `X-Payaza-Signature` on Initiate A Transfer. Pass the same style of secret:

```python
client = Payaza(api_key="your-live-key", payout_secret_key="your-payout-secret")
```

You can also pass `secret_key=` on a single `client.payouts.initiate_payout(...)` call. The SDK hashes the exact JSON body it sends.

---

## Implemented resources

| Resource | Methods |
|----------|---------|
| `client.collections` | Card charge (optional NGN PIN), 3DS check, card status/refund status, tokenization, token charge/list/delete, Apple/Google Pay initiate |
| `client.virtual_accounts` | Create dynamic/static VA, get status, fund test VA (sandbox), collection status by txn/merchant ref |
| `client.payouts` | Initiate transfer (single or multi-beneficiary) |
| `client.accounts` | View main accounts (balance / `payazaAccountReference`), account name enquiry |
| `client.transactions` | Transfer transaction status |
| `client.misc` | Bank codes by currency |
| `client.momo_collections` | MoMo/XOF/ZAR/SLE process collection, status, XOF OTP, sandbox fund |
| `client.refunds` | Initiate refund, refund history, chargeback requests/accept-reject/history |
| `client.auth_capture` | Authorize, capture, void, get/list authorizations |
| `client.sub_accounts` | Create sub-account, view sub-account details |
| `client.split_settlements` | Create, list, update, delete split settlement accounts |
| `client.eur_accounts` | Acceptable IDs, request user/corporate EUR subaccount, list/get requests, list EUR subaccounts |
| `client.branches` | List merchant branches |
| `client.subscriptions` | Plans, create/list/get subscription, pause/resume/cancel/change-plan, charge-now/custom, charges/events/upcoming, invoices |

### Examples

```python
# Main accounts — balances + payazaAccountReference for payouts
accounts = client.accounts.view_main_accounts()
ngn = next(a for a in accounts["data"] if a["currency"] == "NGN")
account_reference = ngn["payazaAccountReference"]

# Bank codes (requires X-TenantID)
banks = client.misc.get_bank_codes("NGN")

# Name enquiry before payout
details = client.accounts.fetch_account_details(
    currency="NGN",
    bank_code="000013",
    account_number="0123456789",
)

# Initiate transfer — sender is nested into each beneficiary
response = client.payouts.initiate_payout(
    transaction_type="nuban",
    payout_amount=1000,
    transaction_pin=1234,
    account_reference=account_reference,
    currency="NGN",
    country="NGA",
    payout_beneficiaries=[{
        "credit_amount": 1000,
        "account_number": "0123456789",
        "account_name": "John Doe",
        "bank_code": "000013",
        "narration": "Test payout",
        "transaction_reference": "TXN-001",
    }],
    sender={
        "sender_name": "Jane Doe",
        "sender_phone_number": "08012345678",
        "sender_address": "Lagos, Nigeria",
    },
)
```

Runnable scripts live under [`examples/`](examples/).

---

## Development

```bash
pip install -e ".[dev]"
pytest --cov=payaza
```

---

## Contributing

PRs are welcome! Please open an issue first to discuss what you'd like to change.

---

## ⚠️ Disclaimer

This is an **unofficial** SDK and is not affiliated with or endorsed by Payaza Africa Limited.
Endpoint paths and request/response shapes are based on the public documentation at
[docs.payaza.africa](https://docs.payaza.africa) — always cross-check against the latest
official docs and update accordingly.

---

## License

MIT © Shagbaor Agber
