Metadata-Version: 2.5
Name: simpleapps-com-augur-api
Version: 2026.9.7
Summary: Python client for Augur API microservices
Project-URL: Homepage, https://github.com/simpleapps-com/augur-api
Project-URL: Documentation, https://augur-api.info
Project-URL: Repository, https://github.com/simpleapps-com/augur-api
Author-email: SimpleApps <info@simpleapps.com>
License-Expression: MIT
License-File: LICENSE
Keywords: api,augur,client,microservices
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
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.27
Requires-Dist: pydantic>=2.0
Provides-Extra: dev
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# simpleapps-com-augur-api

Python client library for Augur microservices.

## Installation

```bash
pip install simpleapps-com-augur-api
```

## Quick Start

```python
from augur_api import AugurAPI

api = AugurAPI(
    token="your-bearer-token",
    site_id="your-site-id",
)

# Access any service via api.{service_name}
items = api.items.inv_mast.list(limit=10)
customers = api.customers.customer.list(limit=10)
orders = api.orders.oe_hdr.lookup()
```

## Service Access Pattern

All services are accessed through the unified `AugurAPI` client:

```python
api.items        # Items service
api.customers    # Customers service
api.orders       # Orders service
api.pricing      # Pricing service
api.commerce     # Commerce service
# ... one property per service (see https://items.augur-api.com/llms.txt)
```

## Documentation

| Resource | URL |
|----------|-----|
| **Full API Reference** | https://augur-api.info |
| **Endpoint Hints** | `https://{service}.augur-api.com/llms.txt` |
| **Parameters** | `https://{service}.augur-api.com/endpoints.jsonl` |
| **OpenAPI Spec** | `https://{service}.augur-api.com/openapi.json` |

### Example: Items Service

- https://items.augur-api.com/llms.txt
- https://items.augur-api.com/endpoints.jsonl
- https://items.augur-api.com/openapi.json

Each `llms.txt` lists all other available services for discovery.

## Authentication

All endpoints require:
- `site_id` - Site identifier
- `token` - Bearer authentication token

```python
api = AugurAPI(
    site_id="your-site-id",
    token="your-bearer-token",
)
```

## Configuration

```python
from augur_api import AugurAPI, AugurAPIConfig

# With custom configuration
config = AugurAPIConfig(
    token="your-bearer-token",
    site_id="your-site-id",
    timeout=30.0,
    retries=3,
    retry_delay=1.0,
)
api = AugurAPI.from_config(config)

# From context (for framework integration)
api = AugurAPI.from_context(context)
```

## Edge Caching

Enable Cloudflare edge caching on any GET request using the `edge_cache` parameter:

```python
# Sub-hour caching
items = api.items.inv_mast.list(limit=10, edge_cache="30s")  # 30 seconds
items = api.items.inv_mast.list(limit=10, edge_cache="1m")   # 1 minute
items = api.items.inv_mast.list(limit=10, edge_cache="5m")   # 5 minutes

# Hourly caching (1, 2, 3, 4, 5, or 8 hours)
items = api.items.inv_mast.list(limit=10, edge_cache=1)      # 1 hour
items = api.items.inv_mast.list(limit=10, edge_cache=8)      # 8 hours
```

| Value | Duration |
|-------|----------|
| `"30s"` | 30 seconds |
| `"1m"` | 1 minute |
| `"5m"` | 5 minutes |
| `1` - `5`, `8` | 1-5 or 8 hours |

The client automatically transforms `edge_cache` to Cloudflare's `cacheSiteId{N}` format.

## Error Handling

```python
from augur_api import (
    AugurAPI,
    AugurError,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)

api = AugurAPI(token="...", site_id="...")

try:
    response = api.items.inv_mast.get(12345)
except ValidationError as e:
    print(f"Bad request: {e.message}")
except AuthenticationError as e:
    print(f"Auth failed: {e.message}")
except NotFoundError as e:
    print(f"Item not found: {e.message}")
except RateLimitError as e:
    print(f"Rate limited: {e.message}")
except AugurError as e:
    print(f"API error: {e.code} - {e.message}")
```

The status decides the class: 400 → `ValidationError`, 401 → `AuthenticationError`, 404 → `NotFoundError`, 429 → `RateLimitError`, anything else (including 403 and network failures) → `AugurError`. `e.endpoint` is the path template (`/inv-mast/{invMastUid}`), and messages never contain parameter values.

## Endpoint Registry and `call()`

`AugurAPI.endpoints()` lists every endpoint (id, method, path template, params). `call()` invokes one by id or alias id, with no typed method:

```python
result = api.call(
    "items.invMast.doc.get",
    path_params={"invMastUid": 12345},
    query={"edgeCache": 1},
)

result.http_status    # 200
result.envelope       # Envelope (count, data, message, ..., total_results) or None
result.body           # parsed JSON, or the raw text when the body isn't JSON
```

- Arguments are checked before any request: path params must match exactly, query keys must be declared, and a body is allowed only on POST/PUT. Violations raise `InvalidArgumentError`.
- A 2xx always returns; there is no schema validation. Use the typed methods when you want validated, typed responses.
- Non-2xx responses raise the same errors as the typed methods.

## Path Values

Path values are sent unencoded, because the API does not decode path segments (`/bins/D%2FS` looks up the literal `D%2FS`). A string path value MUST use only letters, digits and `- . _ ~ ! $ & ' ( ) * + , ; = : @`. Anything else, such as `/`, `?`, `#`, `%`, spaces or non-ASCII, raises `InvalidArgumentError` before any request. Pass the raw value, never a pre-encoded one. Use the query parameter instead where there is one:

```python
api.call("items.locations.bins.list", path_params={"locationId": 100}, query={"bin": "D/S"})
```

## For AI Agents

See [SKILL.md](./SKILL.md) for guidance on using this package with AI assistance.

## License

MIT
