# Python client

> packages/api/python holds a small Python client for /api/v1, generated from the OpenAPI spec. Standard library only (no requests), Python 3.9 or newer.

URL: https://timetracking.tech/developers/api/python
Last updated: 2026-11-02

`packages/api/python` holds a small Python client for `/api/v1`, generated from the OpenAPI spec. Standard library
only (no `requests`), Python 3.9 or newer.

```python
from timetracking_api import ApiError, Client

api = Client("tt_live_…")                      # API key, or a user access token (+ org_id="…")
people = api.list_persons(query={"limit": 100})  # {"items": [...], "next_cursor": ...}
unit = api.create_unit(body={"kind": "branch", "name": "Heerlen"})

try:
    api.get_person("00000000-0000-0000-0000-000000000000")
except ApiError as e:
    print(e.status, e.code, e.reason)

print(api.rate_limit)  # last X-RateLimit-* values: limit, remaining, reset (epoch seconds)
```

What the client does for you:

- One method per operation: the `operationId` in snake_case (`listPersons` → `list_persons`). Path parameters are
  positional arguments, `body=` is the JSON body, `query=` the query string. Methods return the unwrapped `data`.
- Writes (POST, PUT, PATCH, DELETE) get an `Idempotency-Key` (or pass `idempotency_key=`), reused on every retry,
  so a retried write is never applied twice.
- `429`: waits `Retry-After` (or until `X-RateLimit-Reset`) and retries, up to `max_retries` (default 3). A wait
  longer than `max_retry_delay` (default 60 s) raises `ApiError` instead.
- `502`/`503`/`504` and network errors are retried with backoff for calls that are safe to repeat (GET, or a write
  with an Idempotency-Key).
- Response types: `timetracking_api.schemas` has one `TypedDict` per schema of the spec.

Rate limits: 120 requests per minute per API key, 300 per minute per login for user access tokens
(see [rate limits](https://timetracking.tech/developers/api/rate-limits)).

Regenerate after an API change (from the repository root):

```
pnpm --filter @tt/api generate          # openapi.json + TypeScript types
pnpm --filter @tt/api generate:python   # python/timetracking_api/schemas.py + operations.py
```

`pnpm --filter @tt/api test` checks that both are up to date and runs the Python smoke test when `python3` is
installed.
