Metadata-Version: 2.5
Name: suqo
Version: 0.2.0
Summary: Python SDK for the Suqo API
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.9
Requires-Dist: requests>=2.28
Description-Content-Type: text/markdown

# suqo-python

[![PyPI](https://img.shields.io/pypi/v/suqo)](https://pypi.org/project/suqo/)
[![License](https://img.shields.io/pypi/l/suqo)](LICENSE)

Python SDK for the Suqo API.

```bash
pip install suqo
```

Python 3.9+. Only dependency is `requests`.

## Quick start

```python
from suqo import SuqoClient

client = SuqoClient(
    api_key="su_key_...",       # or set SUQO_API_KEY
    base_url="https://...",     # or set SUQO_BASE_URL
)

for subscription in client.subscriptions.iter():
    print(subscription["subscription_id"], subscription["status"])
```

Responses are plain dicts matching the API payloads.

## Methods

| Call | Does |
|---|---|
| `products.list()` / `.iter()` | Your catalogue, with plans and billing periods nested |
| `subscriptions.list()` / `.iter()` | All subscriptions; `list()` also returns status totals |
| `subscriptions.get(id)` | One subscription |
| `subscriptions.create(...)` | New subscription, returns a `checkout_url` |
| `subscriptions.cancel(id)` | Cancel at end of the current period |
| `subscriptions.resume(id)` | Undo a pending cancellation |
| `subscriptions.update_billing_cycle(id, date)` | Move the next billing date |
| `customers.list()` / `.iter()` / `.get(id)` | Your buyers |

## Creating a subscription

`pbp_id` identifies a billing period — find one under `product["plan"][n]["billing_periods"]`.

```python
created = client.subscriptions.create(
    pbp_id="pbp_3n9k2x",
    return_url="https://yourapp.com/thanks",
    client={
        "phone": "9841000100",
        "full_name": "Ram Shrestha",
        "email": "ram@client.com",
    },
)

created["checkout_url"]   # send the buyer here to pay
```

`client` also takes an optional `address`, plus optional `billing` and
`shipping` blocks:

```python
"billing": {
    "billing_business_name": "ABC Pvt Ltd.",
    "billing_email": "ram@client.com",
    "billing_address": "Kathmandu, Nepal",
    "billing_pan_vat": "301234567",     # optional
},
"shipping": {
    "phone": "9841000100",
    "full_name": "Ram Shrestha",
    "email": "ram@client.com",
    "address": "Kathmandu, Nepal",      # optional
},
```

## Pagination

`.iter()` walks every page for you, fetching lazily:

```python
for customer in client.customers.iter():
    ...
```

`.list()` returns one page with the raw envelope (`count`, `next`, `previous`,
`results`). Both accept `page` and `page_size` (max 100). There are no
server-side filters — filter in Python.

## Errors

```python
from suqo import ValidationError

try:
    client.subscriptions.create(pbp_id="bad", return_url="...", client={...})
except ValidationError as exc:
    exc.errors        # {"pbp_id": ["does not exist or is not visible."]}
    exc.status_code   # 400
```

`ValidationError` (400), `AuthenticationError` (401), `PermissionDeniedError`
(403), `NotFoundError` (404), `RateLimitError` (429) and `ServerError` (5xx) all
subclass `SuqoAPIError`, which carries `status_code`, `payload` and `response`.

GETs retry 429s and 5xxs three times with backoff. POSTs never retry — a
replayed create would make a second subscription.

## Configuration

```python
SuqoClient(
    api_key=None,     # required; falls back to SUQO_API_KEY
    base_url=None,    # required; falls back to SUQO_BASE_URL
    timeout=30,
    max_retries=3,    # GET only; 0 disables
    session=None,     # inject your own requests.Session
)
```

`api_key` and `base_url` are both required — there is no default host, so which
environment you talk to is always an explicit choice. Missing either raises
`ValueError` at construction.

Also works as a context manager, closing the session on exit.

