Metadata-Version: 2.5
Name: adveron
Version: 0.2.0
Summary: Python client for the Adveron public API — generated from the OpenAPI spec
Project-URL: Homepage, https://adveron.com
Project-URL: Documentation, https://api.adveron.com/v1/docs
License-Expression: MIT
License-File: LICENSE
Keywords: adveron,api,brand-intelligence,openapi,sdk
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.11
Requires-Dist: attrs>=22.2.0
Requires-Dist: httpx<0.29.0,>=0.23.1
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# adveron

Python client for the Adveron public API — the tenant `/v1` surface, generated from the API's own OpenAPI document. Requires Python 3.11+; the transport is [httpx](https://www.python-httpx.org/).

The client is **generated, not hand-written**. Every operation, every request shape, and every response model comes from the same registered operations the server dispatches, so the client cannot describe a surface the API does not serve. Beside the generated tree sits a small hand-written layer: a constructor, an error helper, and a cursor loop.

## Install

```bash
pip install adveron
```

## Authentication

Every call authenticates with a workspace API key as a bearer token. `from_env()` reads it from the environment and hands back a client every operation accepts:

```python
from adveron import from_env

client = from_env()            # ADVERON_API_KEY, and ADVERON_API_URL if set
```

| Variable | Default | |
|---|---|---|
| `ADVERON_API_KEY` | — | required |
| `ADVERON_API_URL` | `https://api.adveron.com` | optional |

Either can be overridden per client, which is what a process serving several workspaces needs:

```python
client = from_env(api_key=key, base_url="https://api.adveron.com", timeout=60.0)
```

Extra keyword arguments configure the transport. `timeout`, `follow_redirects`, `headers`, `cookies`, `verify` and `raise_on_unexpected_status` are the client's own settings; anything else (`transport`, `proxies`, `limits`, …) reaches `httpx.Client` unchanged.

The key is passed through exactly as given — it is never parsed, pattern-checked or normalised — and it leaves only as an `Authorization: Bearer` header, never as a query parameter. Under Managed Agents the environment variable holds an opaque placeholder that the sandbox substitutes for the real credential at egress, so a client that insisted on a key-shaped key would reject every sandboxed run.

## Calling an operation

Operations are grouped by tag under `adveron.generated.api`, one module per operation, named for the operation: `brand.mentions.list` is `brand_mentions_list`. Each module offers `sync`, `sync_detailed`, `asyncio` and `asyncio_detailed`.

```python
from adveron import from_env
from adveron.generated.api.brands import brand_search, brand_get

client = from_env()

found = brand_search.sync(client=client, q="nike", limit=5)
brand = brand_get.sync(found.data.items[0].id, client=client)
```

`sync` returns the parsed body: `{data, meta}` on success, where `meta` always carries the `request_id` that also rides the `X-Request-Id` response header. `sync_detailed` returns a `Response` carrying the status and headers as well.

## Errors

Operations do not raise on an HTTP status. They return the house error envelope, `{"error": {code, message, request_id, details?}}`; `is_adveron_error` tells the two apart:

```python
from adveron import from_env, is_adveron_error
from adveron.generated.api.brands import brand_get

result = brand_get.sync(brand_id, client=client)
if is_adveron_error(result):
    # result.error.code is one of the stable machine codes — e.g.
    # "resource_not_activated", "insufficient_credits", "rate_limited"
    print(result.error.code, result.error.request_id)
```

`AdveronErrorCode` is the enum of known codes. Branch with a default arm rather than assuming it is closed: the server can ship a new code before the client is regenerated, and `is_adveron_error` deliberately accepts one.

Quote `request_id` in a support request: it joins our logs, traces, and the credit ledger.

## Paging

List operations take `limit` and `cursor` and answer `meta.next_cursor`. `iter_pages` follows it to the end, and `iter_items` flattens the rows:

```python
from adveron import from_env, iter_items
from adveron.generated.api.audiences import audience_posts

client = from_env()
posts = list(iter_items(audience_posts.sync, "AUD123", client=client, limit=100))
```

Both take the operation's `sync` function, its path parameters positionally, and its query parameters as keywords — the same call you would write by hand. `max_pages=` caps a run; an error envelope on any page raises `AdveronError` rather than ending the loop quietly, so a 403 can never read as an audience nobody posts in.

Operations that return everything at once (`audience_influencers`, `category_list`) carry no cursor and read as a single page, so paging code does not need to know which kind it holds.

## One example per group

**Brands** — search first; every other brand operation takes an id, not a name.

```python
from datetime import date

from adveron.generated.api.brands import brand_search, brand_mentions_list

found = brand_search.sync(client=client, q="nike", limit=5)
mentions = brand_mentions_list.sync(found.data.items[0].id, client=client,
                                    q="running", start_date=date(2026, 5, 1))
```

Date parameters are typed `datetime.date | datetime.datetime`, not `str` — the spec declares them as date-or-date-time and the generated client serialises them.

**Categories**

```python
from adveron.generated.api.categories import category_list

categories = category_list.sync(client=client)
# categories.data.items[0].subcategories — the launched children under each category
```

**Audiences**

```python
from adveron.generated.api.audiences import audience_get

audience = audience_get.sync("AUD123", client=client)
```

**Balance & usage**

```python
from adveron.generated.api.billing import balance_get, usage_summary

balance = balance_get.sync(client=client)
usage = usage_summary.sync(client=client, group_by="WORKSPACE")
```

## Metering headers

Successful responses carry `X-Credits-Charged` / `X-Credits-Reason` and the organization's purchased throughput as `RateLimit-*`. Reads answer `Cache-Control: no-store`. Read them from `sync_detailed(...).headers`. Pass `idempotency_key=` to make a call safe to retry — recommended on metered `GET`s, where an auto-retried read would otherwise double-charge.

## Reference

The full operation reference, with request and response shapes for every `/v1` endpoint, is the API's own interactive documentation at `https://api.adveron.com/v1/docs`. The SHA-256 of the exact spec revision this client was generated from ships inside the package as `adveron/openapi.sha256`.
