Metadata-Version: 2.4
Name: felloh
Version: 0.1.0
Summary: Official Python SDK for the Felloh payment API
Project-URL: Homepage, https://github.com/felloh-org/python-sdk
Project-URL: Documentation, https://felloh.com/docs
Author-email: Felloh <engineering@felloh.com>
License-Expression: MIT
License-File: LICENSE
Keywords: api,felloh,payments,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
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: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: httpx>=0.25.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# Felloh Python SDK

Official Python SDK for the [Felloh](https://felloh.com) payment API.

## Installation

```sh
pip install felloh
```

## Quick Start

```python
import asyncio
from felloh import FellohClient
from felloh.types import FellohConfig

client = FellohClient(FellohConfig(
    public_key="your_public_key",
    private_key="your_private_key",
))

async def main():
    # List bookings
    bookings = await client.bookings.list({"organisation": "org-id"})
    print(bookings["data"])

    # Create a booking
    booking = await client.bookings.create({
        "organisation": "org-id",
        "booking_reference": "REF-001",
        "customer_name": "Jane Smith",
        "email": "jane@example.com",
    })
    print(booking["data"]["id"])

    await client.close()

asyncio.run(main())
```

## Context Manager

```python
async with FellohClient(FellohConfig(
    public_key="your_public_key",
    private_key="your_private_key",
)) as client:
    bookings = await client.bookings.list({"organisation": "org-id"})
```

## Pagination

Iterate through all results automatically:

```python
from felloh import to_array

# Async iteration
async for booking in client.bookings.list_all({"organisation": "org-id"}):
    print(booking["id"])

# Or collect all into a list
all_bookings = await to_array(client.bookings.list_all({"organisation": "org-id"}))
```

## Resources

| Resource | Methods |
|---|---|
| `organisations` | `list` |
| `bookings` | `list`, `list_all`, `get`, `create`, `update`, `delete`, `update_reference` |
| `booking_components` | `create`, `delete` |
| `transactions` | `list`, `list_all`, `get`, `refund`, `complete`, `reverse`, `reassign` |
| `customers` | `list`, `list_all`, `create` |
| `payment_links` | `list`, `list_all`, `get`, `create`, `delete`, `assign` |
| `ecommerce` | `list`, `list_all`, `get`, `create`, `delete`, `assign` |
| `refunds` | `list`, `list_all`, `authorise`, `decline` |
| `charges` | `list`, `list_all` |
| `chargebacks` | `list`, `list_all` |
| `credit_notes` | `list`, `list_all`, `get`, `create`, `assign` |
| `suppliers` | `list`, `list_all`, `create` |
| `beneficiaries` | `list`, `list_all`, `create`, `activate` |
| `disbursements` | `list`, `list_all`, `get` |
| `ledger` | `list`, `list_all` |
| `batches` | `list`, `list_all`, `get` |
| `api_keys` | `list`, `create`, `delete` |
| `audit` | `list`, `list_all` |
| `aisp` | `accounts`, `transactions`, `statistics` |
| `scheduled_payments` | `list`, `list_all`, `available_tokens`, `create_payment`, `approval_link`, `delete` |
| `enums` | `list` |

## Error Handling

```python
from felloh import (
    FellohError,
    FellohAuthenticationError,
    FellohNotFoundError,
    FellohValidationError,
    FellohRateLimitError,
    FellohServerError,
    FellohNetworkError,
)

try:
    await client.bookings.get("nonexistent-id")
except FellohNotFoundError as e:
    print(f"Not found: {e}")
except FellohAuthenticationError:
    print("Invalid credentials")
except FellohError as e:
    print(f"API error {e.status_code}: {e}")
```

## Webhook Verification

```python
from felloh import verify_webhook_signature, assert_webhook_signature

# Returns True/False
is_valid = verify_webhook_signature(
    payload=request_body,
    signature=request.headers["X-Signature"],
    secret="your_webhook_secret",
)

# Or raise FellohWebhookSignatureError
assert_webhook_signature(
    payload=request_body,
    signature=request.headers["X-Signature"],
    secret="your_webhook_secret",
)
```

## Configuration

```python
FellohConfig(
    public_key="pk_...",
    private_key="sk_...",
    base_url="https://api.felloh.com",       # default
    timeout=30.0,                              # seconds, default
    max_retries=2,                             # default
    token_refresh_buffer=60,                   # seconds before expiry, default
    logger=lambda entry: print(entry),         # optional request logger
)
```

## Development

```sh
pip install -e ".[dev]"
pytest                              # unit + resource tests
pytest -m integration               # integration tests (requires env vars)
```

Integration tests require:
- `FELLOH_PUBLIC_KEY`
- `FELLOH_PRIVATE_KEY`
- `FELLOH_ORGANISATION_ID`

## License

MIT
