Skip to main content

campai-client

A Python SDK for campai.com, generated from campai's OpenAPI spec, with pydantic v2 models, sync + async clients, and a durable patch layer for spec-vs-reality fixes.

Status: early / alpha. See docs/DESIGN.md for the full architecture and docs/adr/ for key decisions.

Install

pip install campai-client

Requires Python ≥ 3.13. Runtime deps: httpx, pydantic>=2, pydantic-settings.

Quickstart

from campai_client import CampaiClient
from campai_client import models

client = CampaiClient(
    api_key="...",  # or env CAMPAI_API_KEY
    organization_id="...",  # or env CAMPAI_ORGANIZATION_ID
    mandate_id="...",  # optional default; overridable per call
    # base_url defaults to https://cloud.campai.com/api
)

# Ergonomic namespaces mirror campai's tag hierarchy. List bodies (pagination +
# filters) are typed via the generated request model:
page = client.crm.applications.forms.list(
    body=models.CrmApplicationsFormsListFormsRequest(limit=50)
)
print(page.count, len(page.items))

form = client.crm.applications.forms.get(application_form_id="...")

# Walk every page transparently:
for form in client.crm.applications.forms.iterate():
    ...

client.close()

Async mirror:

from campai_client import AsyncCampaiClient

async with AsyncCampaiClient(api_key="...", organization_id="...") as client:
    form = await client.crm.applications.forms.get(application_form_id="...")
    async for f in client.crm.applications.forms.aiterate():
        ...

Configuration is resolved from constructor args or CAMPAI_* env vars (CAMPAI_API_KEY, CAMPAI_ORGANIZATION_ID, CAMPAI_MANDATE_ID, CAMPAI_BASE_URL).

Errors

HTTP status + campai's error envelope map to a typed hierarchy: CampaiAPIError (BadRequestError/AuthenticationError/PermissionError/NotFoundError/ServerError), plus CampaiValidationError (response didn't match the models) and CampaiConfigError.

How it's built (three layers)

  1. Spec pipeline (spec/, scripts/): download → normalize/overlay → committed spec.
  2. Generated layer (src/campai_client/_generated/, never hand-edited): 2 200+ pydantic v2 models via openapi-generator (models-only), plus the operations manifest (operations.py) built from the spec.
  3. Facade + patch layer (src/campai_client/, durable): clients, resource namespaces, the patch pipeline, pagination, errors.

See docs/adr/0002 for how the runtime call path and resource tree are driven by the manifest.

The agent maintenance loop

When campai's spec changes, regenerate and let the tests triage the drift:

pixi run regen          # fetch + normalize + generate + manifest + format
pixi run test           # replay (VCR) tests

Triage failures:

  • CampaiValidationError / import error → schema drift. Fix spec/overlay.yaml (schema-level, JSON-Pointer keyed), then pixi run regen.
  • Behavioural mismatch (id-only response, aliasing, follow-up needed) → add or adjust a patch in src/campai_client/patches/ plus a test. Patches without tests are not allowed.
  • New/removed operations → the manifest + resource namespaces regenerate automatically; add smoke tests for important new resources.

Cassettes are re-recorded (CAMPAI_RECORD=1 pixi run test-record) only when the real API behaviour changed.

Development

pixi manages the dev environment (the shipped package uses standard pyproject.toml deps).

pixi run check       # lint + typecheck + test  (CI aggregate)
pixi run lint        # ruff check
pixi run format      # ruff format
pixi run typecheck   # ty check
pixi run test        # pytest (VCR replay)
pixi run regen       # full regeneration (openapi-generator via pixi's JVM)

lefthook runs format/lint/typecheck on staged files and guards against hand-edits to _generated/**.

Regeneration (pixi run regen/generate) runs the openapi-generator JAR with a JVM supplied by pixi (openjdk) — no Docker required (it runs fine inside containers). The JAR is pinned by version + SHA-256 and cached under .cache/. Using or testing the shipped client needs neither Java nor the JAR.

Integration tests (real campai org)

Most tests use a mock transport. The integration tests (tests/resources/test_live.py) hit the real API and are recorded with VCR, then replayed from committed cassettes (no credentials on replay). Provide credentials via env vars to record:

CAMPAI_RECORD=1 CAMPAI_API_KEY=... CAMPAI_ORGANIZATION_ID=... \
  CAMPAI_MANDATE_ID=... pixi run test-record

Credentials are scrubbed from cassettes. See tests/README.md for the full flow and scrubbing tradeoffs.

License

Apache-2.0.

Release files for campai-client 2026.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for campai-client 2026.9.0
File Size Uploaded
campai_client-2026.9.0.tar.gz 922.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for campai-client 2026.9.0
File Interpreter ABI Platform
campai_client-2026.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.9 MB

Release files / campai_client-2026.9.0.tar.gz

Download URL campai_client-2026.9.0.tar.gz
Size 922.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b50d125fbe54485203a65269b35143ed5e3b4d99549aa512394b5d79a45cb55c
BLAKE2b-256 checksum
How to use checksums
6c5ee2a2966ae1528dc3b9bfdd02cb8e4b630f3ab341b537b021d500991194c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / campai_client-2026.9.0-py3-none-any.whl

Download URL campai_client-2026.9.0-py3-none-any.whl
Size 4.0 MB
Tags Python 3
SHA-256 checksum
How to use checksums
5d80f283ff86ade72ae305d442adde34fbe3eca36021f2f115e86a53d4360637
BLAKE2b-256 checksum
How to use checksums
e8e1aa1542c0dca4382182ef655bd5bc0122b742212ef28b6012ee11988a758f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2026.9.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page