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

# suqo-python

Python SDK for the Suqo external API (`/api/v1/`).

```bash
pip install -e .
```

## Usage

```python
from suqo import SuqoClient

client = SuqoClient(api_key="su_key_...")        # or set SUQO_API_KEY
```

Point it at another environment with `base_url=`:

```python
client = SuqoClient(base_url="https://staging.suqo.ai")
```

### Subscriptions

```python
page = client.subscriptions.list(page_size=50)
page["active_subscriptions"]                      # status totals ride along

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

client.subscriptions.get(subscription_id)

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",
        "address": "Kathmandu, Nepal",
        "billing": {                              # optional
            "billing_business_name": "ABC Pvt Ltd.",
            "billing_email": "ram@client.com",
            "billing_address": "Kathmandu, Nepal",
            "billing_pan_vat": "301234567",
        },
        "shipping": {                             # optional
            "phone": "9841000100",
            "full_name": "Ram Shrestha",
            "email": "ram@client.com",
            "address": "Kathmandu, Nepal",
        },
    },
)
created["checkout_url"]                           # send the buyer here to pay

client.subscriptions.cancel(subscription_id)      # at end of current period
client.subscriptions.resume(subscription_id)
client.subscriptions.update_billing_cycle(subscription_id, "2026-09-01")
```

### Customers and products

```python
client.customers.list()
client.customers.get(customer_id)
client.products.list()                            # plans + billing periods nested
```

### Auto-pagination

Every resource has `.iter()`, a generator that walks all pages for you:

```python
for customer in client.customers.iter():
    print(customer["full_name"], customer["buyer_phone"])

for subscription in client.subscriptions.iter():
    ...

for product in client.products.iter():
    ...
```

Pages are fetched lazily — page 2 only goes out once page 1 is consumed, so
`break` costs you nothing. Materialise them all with `list(...)`:

```python
customers = list(client.customers.iter())
```

`.list()` is the single-page alternative, returning the raw envelope
(`count`, `next`, `previous`, `results`) when you need those fields:

```python
page = client.customers.list(page=2, page_size=100)   # page_size max is 100
```

`page_size` works on `.iter()` too, and cuts the number of round trips:

```python
client.customers.iter(page_size=100)   # 100 per request instead of 20
```

The API exposes no server-side filters on these endpoints — filter in Python:

```python
active = [s for s in client.subscriptions.iter() if s["status"] == "active"]
```

### Errors

```python
from suqo import ValidationError, AuthenticationError, NotFoundError

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
```

All errors subclass `SuqoError`. API failures subclass `SuqoAPIError` and carry
`status_code`, `payload` and the raw `response`.

### Notes

- GETs retry transient failures (429, 5xx) three times with backoff. POSTs never
  retry — a replayed create would make a second subscription.
- Responses are plain dicts, matching the API payloads.
- `SuqoClient` works as a context manager to close the underlying session.

## Tests

```bash
python test_suqo.py
```
