[ INTEGRATION SURFACE · BETA ] ━━ API, SDKs, and event payloads may change between releases. Read the versioning policy

Python SDK

cheetah-client — install, connect, sync and async usage, typed responses, and error handling.

▸ BETA
▸ APPLIES TO
cheetah service >=0.0.132

cheetah-client wraps the open REST API for Python ≥ 3.11, with synchronous and asynchronous variants of every method and Pydantic-typed responses.

Install#

Install from the cheetah-service repository, pinned to the release tag matching your cell:

pip install "cheetah-client @ git+https://github.com/CheetahEngineering/cheetah-service.git@v0.0.132#subdirectory=clients/python"

Or with uv:

uv add "cheetah-client @ git+https://github.com/CheetahEngineering/cheetah-service.git@v0.0.132#subdirectory=clients/python"

Pin the tag (@v0.0.132), not @mainmain will move under you, and the tag is what keeps SDK and service versions aligned.

Connect#

from cheetah_client import CheetahClient

with CheetahClient("http://cheetah-cell.local:8000") as client:
    print(client.health())

The constructor takes the cell's base URL and an optional timeout (seconds, default 30.0). The client is a context manager; outside a with block, call client.close() when done.

Sync and async#

Every method has an async twin with an _async suffix, and the client is also an async context manager:

import asyncio

from cheetah_client import CheetahClient


async def main() -> None:
    async with CheetahClient("http://cheetah-cell.local:8000") as client:
        page = await client.programs.list_all_runs_async(status="completed", limit=10)
        print(page.total)


asyncio.run(main())

The public surface#

How the SDK maps onto the API reference:

Method Endpoint
client.health() GET /health
client.programs.list() · .get(program_id) GET /programs · GET /programs/{program_id}
client.programs.list_all_runs(...) GET /runs — takes program_id, status, serial_number, updated_since, limit, offset
client.programs.list_runs(program_id, ...) GET /programs/{program_id}/runs
client.programs.get_run(run_id) · .get_active_run() GET /runs/{run_id} · GET /runs/active
client.programs.get_run_quality_report(run_id) GET /runs/{run_id}/quality-report
client.programs.download_cl_sweep(run_id, step_index) GET /runs/{run_id}/steps/{step_index}/cl_sweep.csv
client.sensor.get_frame(frame_id) · .get_frame_files(frame_id) GET /sensor/frames/{frame_id} · …/files
client.sensor.download_ply(frame_id, raw=False) GET …/file.ply (raw=True…/file.raw.ply) — returns bytes
client.sensor.download_png(frame_id, luminance=False) GET …/file.png (luminance=True…/file.luminance.png) — returns bytes
client.sensor.download_npy(frame_id) GET …/file.npy — returns bytes
client.webhooks.list() · .get() · .create(...) · .update(...) · .delete() /webhooks management
client.webhooks.test(webhook_id) POST /webhooks/{webhook_id}/test
client.webhooks.list_deliveries(webhook_id, ...) · .get_delivery_detail(delivery_id) · .retry_delivery(delivery_id) Delivery log and replay

The SDK exposes more than this — see scope for what that means.

Putting it together#

Recent inspection results with their QC outcomes:

from cheetah_client import CheetahClient

with CheetahClient("http://cheetah-cell.local:8000") as client:
    page = client.programs.list_all_runs(status="completed", limit=10)
    for run in page.runs:
        report = client.programs.get_run_quality_report(run.id)
        if report.quality_report:
            print(run.serial_number, run.revision, report.quality_report.status)

Responses are Pydantic models — attribute access, IDE completion, and .model_dump() when you need a plain dict. For the production polling pattern behind this loop, see incremental sync.

Errors#

All SDK exceptions derive from cheetah_client.CheetahError:

Exception Raised when
ConnectionError The cell can't be reached — network problem, not an API one
APIError Any HTTP error; carries status_code, code, params from the error envelope
NotFoundError 404s — a subclass of APIError with resource and resource_id
from cheetah_client import CheetahClient, NotFoundError

with CheetahClient("http://cheetah-cell.local:8000") as client:
    try:
        run = client.programs.get_run("0196a3f2-7c1e-7d2a-b3a4-9e8d1c2b3a4f")
    except NotFoundError as e:
        print(f"no such {e.resource}: {e.resource_id}")

Which failures are worth retrying is covered in Errors and retries.

Next#

▸ LAST VERIFIED Fri Jun 12 2026 00:00:00 GMT+0000 (Coordinated Universal Time) ▸▸ /content/developers/client-libraries/python.md
▸ DOCS UNDER CONSTRUCTION LAST UPDATED 2026-07-25 ▸ CHANGELOG