Metadata-Version: 2.4
Name: trackee
Version: 0.1.0
Summary: The official Python SDK for the Trackee API
Project-URL: Homepage, https://trackee.dev
Project-URL: Documentation, https://docs.trackee.dev
Project-URL: Repository, https://github.com/Trackee-API/trackee-python
Project-URL: Issues, https://github.com/Trackee-API/trackee-python/issues
Author: Trackee
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: api,sdk,seo,trackee
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
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<1,>=0.27
Requires-Dist: pydantic[email]<3,>=2
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: hatchling>=1.27; extra == 'dev'
Requires-Dist: mypy>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=6; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.22; extra == 'dev'
Requires-Dist: ruff>=0.9; extra == 'dev'
Requires-Dist: twine>=6; extra == 'dev'
Description-Content-Type: text/markdown

# Trackee Python SDK

Python SDK for the [Trackee API](https://trackee.dev), following the PostPeer Python SDK architecture: OpenAPI-generated Pydantic models, typed sync and async resources, and an HTTPX transport.

Requires Python 3.10 or newer. Install from PyPI:

```bash
pip install trackee
```

For local development:

```bash
uv sync --extra dev
```

```python
from trackee import Trackee

# Reads TRACKEE_API_KEY, or pass api_key="your-key".
with Trackee() as client:
    brands = client.brands.list()
    print(brands)
```

## Async usage

```python
import asyncio
from trackee import AsyncTrackee


async def main():
    async with AsyncTrackee() as client:
        result = await client.brands.list()
        print(result)


asyncio.run(main())
```

## Resources

All 50 operations in the checked-in Trackee contract are available. Resource names match the Node SDK using Python snake_case:

- `health.check()`, `health.verify_access_key()`, `usage.get()`
- `brands.create()`, `list()`, `get()`, `update()`, `delete()`, `timeline()`, `overview()`
- `brands.prompts.get()` / `set()`, `brands.competitors.get()` / `set()`, `brands.keywords.get()` / `set()`
- `trackers.create()`, `list()`, `get()`, `update()`, `delete()`, `run()`
- `scans.create()`, `list()`, `get()`
- `notifications.create()`, `list()`, `get()`, `update()`, `delete()`, `rotate_secret()`, `test()`
- `rank.get()`, `keywords.get()`, `keyword_ideas.get()`, `ai_keyword_volume.get()`
- `visibility.get()`, `prompts.run()`, `models.list()`, `snapshots.query()`
- `alerts.get()`, `recommendations.get()`, `backlinks.get()`, `domain_overview.get()`
- `ranked_keywords.get()`, `audit.get()`, `mentions.get()`, `mentions.history()`
- `citations.get()`, `competitors.get()`

```python
with Trackee() as client:
    result = client.rank.get(keyword="analytics", domain="example.com")
    tracker = client.trackers.create(brand_id="brand-id", interval_minutes=1440)
```

Arguments use snake_case and serialize to the API's field names. Responses are validated Pydantic v2 models. Generated request, response, and enum types are available from `trackee.types`.

For nullable notification fields, omitting an argument leaves it unchanged; explicitly passing `None` sends JSON null. For example, `client.notifications.update(id="notification-id", brand_id=None)` clears its brand scope. `UNSET` is exported for callers that need to represent omission explicitly.

## Configuration and errors

```python
from trackee import Trackee, NotFoundError, RequestOptions

with Trackee(
    api_key="your-key",
    base_url="https://api.trackee.dev",
    timeout=60.0,
    max_retries=2,
    default_headers={"X-Application": "my-app"},
) as client:
    try:
        brand = client.brands.get(id="brand-id", _request_options=RequestOptions(timeout=10.0))
    except NotFoundError as error:
        print(error.status, error.message, error.request_id)
```

Each instance is isolated. You may inject an `httpx.Client` or `httpx.AsyncClient` with `http_client`; the caller retains ownership and must close it.

Typed errors cover API status failures, connection failures, timeouts, and invalid success responses. GET, PUT, DELETE, HEAD, and OPTIONS retry connection failures, 408, 409, 429, and 5xx responses, honoring `Retry-After`. POST and PATCH require an explicit `RequestOptions(retry_non_idempotent=True)` opt-in because replaying a request can repeat work or charges.

## Development

The initial `openapi.json` comes from the Trackee app's local API export. Fetching a newer contract and generating SDK code are separate steps:

```bash
pnpm install --frozen-lockfile
pnpm spec:fetch ../../trackee/apps/web/openapi.json
# Or: pnpm spec:fetch (fetches https://api.trackee.dev/openapi.json)
pnpm generate
uv run ruff format .
uv run ruff check .
uv run mypy
uv run pytest
uv build
uv run twine check dist/*
```

Hey API 0.0.24 generates models; `scripts/generate_resources.py` generates the typed sync/async resource trees. The resource mapping fails on missing, duplicate, or stale operations. Fastify's nullable schema type arrays are normalized on a copy for generation; the original API contract remains intact.

Keep `openapi.json` and both generated directories together when committing. Never edit generated files manually. CI checks generation drift, lint, types, tests, and installable distributions. Version `0.1.0` is the initial SDK; no release or publication is performed by setup.
