Metadata-Version: 2.4
Name: zayono
Version: 1.1.0
Summary: Official Python SDK for the Zayono unified Mobile Money payment gateway.
Project-URL: Homepage, https://zayono.com
Project-URL: Documentation, https://docs.zayono.com/sdks/python
Project-URL: Repository, https://github.com/RomualdAKM/sdks-zayono/tree/main/zayono-python
Project-URL: Issues, https://github.com/RomualdAKM/sdks-zayono/issues
Author-email: Zayono <developers@zayono.com>
License: MIT
License-File: LICENSE
Keywords: africa,asyncio,httpx,mobile-money,payment-gateway,payments,sdk,zayono
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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 :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1,>=0.25
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: mypy>=1.7; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.4; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=7.4; extra == 'test'
Requires-Dist: respx>=0.20; extra == 'test'
Description-Content-Type: text/markdown

# Zayono Python SDK

[![PyPI version](https://img.shields.io/pypi/v/zayono.svg)](https://pypi.org/project/zayono/)
[![Python versions](https://img.shields.io/pypi/pyversions/zayono.svg)](https://pypi.org/project/zayono/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE)

Official Python SDK for the [Zayono](https://zayono.com) unified Mobile Money
payment gateway for Africa.

- **Sync + async** out of the box: `Zayono` and `AsyncZayono`.
- **Type-safe**: ships `py.typed`; complete type hints picked up by mypy/pyright/Pylance.
- **Resilient**: automatic retries (429/5xx/connect) with jittered exponential backoff,
  honours `Retry-After`.
- **Idempotent by default**: every mutating request carries an auto-generated
  `X-Idempotency-Key` (UUIDv4); override with `idempotency_key=`.
- **Framework-agnostic**: integrates with Django, Flask, FastAPI, Starlette, etc.

## Installation

```bash
pip install zayono
```

Requires Python 3.9+.

## Quick start (sync)

```python
import os
from zayono import Zayono

client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])

payment = client.payments.create(
    amount=5000,
    currency="XOF",
    description="Premium t-shirt",
    customer={
        "email": "customer@example.com",
        "first_name": "Jean",
        "last_name": "Dupont",
    },
    return_url="https://example.com/success",
    metadata={"order_id": "ORD-12345"},
)

print(payment["checkout_url"])
```

## Quick start (async)

```python
import asyncio
from zayono import AsyncZayono

async def main():
    async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
        payment = await client.payments.create(
            amount=5000,
            currency="XOF",
            description="Premium t-shirt",
            return_url="https://example.com/success",
            customer={
                "email": "c@example.com",
                "first_name": "Jean",
                "last_name": "Dupont",
            },
        )
        print(payment["checkout_url"])

asyncio.run(main())
```

## Examples

### 1. Initiate a payment with a specific operator (no hosted page)

```python
from zayono import Zayono

client = Zayono(api_key="zyn_test_xxxxx")

payment = client.payments.create(
    amount=15000,
    currency="XOF",
    operator="mtn_bj",
    description="Plan Pro mensuel",
    return_url="https://example.com/success",
    customer={
        "email": "c@example.com",
        "first_name": "Jean",
        "last_name": "Dupont",
        "phone": "+22961000000",
    },
)
# Payment is dispatched immediately. Poll its status via retrieve()
```

### 2. Initiate a payout (disbursement), async

```python
import asyncio
from zayono import AsyncZayono

async def disburse():
    async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
        payout = await client.payouts.create(
            amount=20000,
            currency="XOF",
            operator="moov_bj",
            recipient={
                "phone": "+22961000000",
                "first_name": "Kossi",
                "last_name": "Mensah",
            },
            description="Payout for order ORD-12345",
        )
        print(payout["id"], payout["status"])

asyncio.run(disburse())
```

### 3. Stream every successful payment (auto-paginated)

```python
from zayono import Zayono

client = Zayono(api_key="zyn_test_xxxxx")

for payment in client.payments.list(status="success", per_page=100):
    print(payment["id"], payment["amount"], payment["currency"])
```

Async equivalent:

```python
async for payment in async_client.payments.list(status="success"):
    print(payment["id"])
```

### 4. Verify a webhook signature (FastAPI)

```python
from fastapi import FastAPI, Request, HTTPException
from zayono import Zayono
import os

app = FastAPI()
client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])

@app.post("/webhooks/zayono")
async def webhook(request: Request):
    body = await request.body()                    # raw bytes, required
    signature = request.headers.get("x-zayono-signature", "")
    secret = os.environ["ZAYONO_WEBHOOK_SECRET"]

    if not client.webhooks.verify(body, signature, secret):
        raise HTTPException(401, "Invalid signature")

    event = await request.json()
    # ... handle event["type"], event["data"]
    return {"received": True}
```

> **Refunds**: the public API-key surface does not yet expose
> `POST /v1/payments/{id}/refunds`. For now, trigger refunds from the
> Zayono merchant dashboard. A `refunds` resource will be added to this
> SDK once the endpoint ships on the v1 surface.

## Error handling

```python
from zayono.exceptions import (
    ValidationError, AuthenticationError, RateLimitError,
    NotFoundError, ServerError, NetworkError,
)

try:
    payment = client.payments.create(amount=-1, currency="XOF")
except ValidationError as e:
    # 422: e.errors is dict[str, list[str]]
    for field, messages in e.errors.items():
        print(f"{field}: {', '.join(messages)}")
except AuthenticationError:
    # 401 / 403
    ...
except RateLimitError as e:
    # 429: e.retry_after is in seconds, may be None
    ...
except NotFoundError:
    # 404
    ...
except ServerError:
    # 5xx after retries exhausted
    ...
except NetworkError:
    # Transport-level failure (timeout, connect refused, DNS)
    ...
```

## Configuration

```python
client = Zayono(
    api_key="zyn_test_xxxxx",
    base_url="https://backend.zayono.com/api/v1",  # default
    timeout=30.0,                                  # seconds, default 30
    max_retries=3,                                 # default 3
    application_id=None,                           # only needed for dashboard endpoints
)
```

## Development

```bash
git clone https://github.com/RomualdAKM/sdks-zayono
cd sdks-zayono/zayono-python
pip install -e ".[test]"
pytest                      # run the test suite
python -m build             # produce wheel + sdist into dist/
```

## License

MIT. See [LICENSE](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE).
