Metadata-Version: 2.4
Name: augstash
Version: 0.2.0
Summary: Python client for the Augstash messaging API
License-Expression: Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: urllib3<3,>=2.1
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: pydantic<3,>=2
Requires-Dist: typing-extensions>=4.7
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# augstash (Python)

Python client for the Augstash API. Not published yet - see [`../README.md`](../README.md).

```bash
python -m pip install -e .[dev]
python ../tools/refresh.py --base-url http://localhost:8086 python   # generate the client
python -m pytest tests
```

## Using it

```python
import os
from augstash import AugstashClient, AugstashError
from augstash.generated.api import SmsApi, WalletApi
from augstash.generated.models import SendSmsRequest

client = AugstashClient(
    base_url=os.environ["AUGSTASH_BASE_URL"],   # required - there is no default host
    api_key=os.environ["AUGSTASH_API_KEY"],     # ask_live_<keyId>.<secret>
)

wallet = client.api(WalletApi).balance()

try:
    client.api(SmsApi).send_sms(SendSmsRequest(to="+919000000000", body="hello"))
except AugstashError as error:
    if error.code == "WALLET_INSUFFICIENT_FUNDS":   # branch on code, never on message
        print(error.detail, error.trace_id)
```

`client.api(X)` takes any of the 154 generated API classes and hands back a cached, configured
instance. There is no hand-written list of accessors: one would drift the moment an endpoint is
added.

### Paging

```python
from augstash import paginate_cursor, paginate_pages
from augstash.generated.api import ContactApi

contacts = client.api(ContactApi)
for contact in paginate_pages(lambda page: contacts.list_contacts(page=page, limit=100)):
    ...
```

Use `paginate_cursor` for message, conversation and event history - those endpoints are
cursor-paged because an offset page over a table that grows at the top repeats and skips rows
mid-scroll.

### Webhooks

```python
from augstash import verify_webhook_signature, SIGNATURE_HEADER

@app.post("/hooks/augstash")
def receive():
    # request.get_data(), not request.get_json(): the signature covers the bytes as sent, and a
    # parsed-then-reserialized body no longer matches.
    if not verify_webhook_signature(secret, request.get_data(), request.headers.get(SIGNATURE_HEADER)):
        return "", 401
    return "", 204
```

## Options

| Argument | Default | |
|---|---|---|
| `base_url` | - | required |
| `api_key` / `bearer_token` | - | one is required; a bearer token reaches endpoints a key cannot |
| `timeout` | 30.0 | seconds, per attempt |
| `retry` | `RetryPolicy(3, 0.5, 8.0)` | `RetryPolicy(max_attempts=1)` disables |
| `idempotency` | `True` | off also stops mutating calls being retried |
| `headers` | - | extra headers on every request |

The client is a context manager (`with AugstashClient(...) as client:`) and holds a connection
pool; call `close()` when you are done with it.

## Layout

`augstash/generated/` is machine-written and gitignored; `augstash/*.py` beside it is the
hand-written core and is protected from the generator by `.openapi-generator-ignore`.
