VerdifaxClient

The synchronous Python client. Wraps an httpx.Client with a connection pool, applies client-side validation before every call, and translates HTTP errors into a clean exception hierarchy.

Import

from verdifax import VerdifaxClient

Constructor

VerdifaxClient(
    base_url: str | None = None,
    api_key: str | None = None,
    timeout: float = 30.0,
    transport: httpx.BaseTransport | None = None,
)
ArgumentDefaultNotes
base_url$VERDIFAX_API_URL or https://api.verdifax.comTrailing slashes are stripped
api_key$VERDIFAX_API_KEYSent as X-Verdifax-Key header
timeout30.0 secondsApplied to every request
transportNoneInject a custom transport for tests (e.g. httpx.MockTransport)

Methods

client.health() -> dict
client.attest(payload, program_id, route_id, registry_record_hash,
              attested_context=None, reproducibility_context=None,
              ai_output_text=None) -> AttestationReceipt
client.verify_run(run_id) -> VerifyResponse
client.verify(...)  # raises UnsupportedOperationError since 0.6.0, see client.verify_run()
client.execute(payload, program_id, route_id, registry_record_hash) -> ExecutionManifest
client.close() -> None

verify_run() asks the server to re-derive a recorded run's manifest hash and compare it with the recorded seal; see client.verify_run().

execute() is a lower-level alternative to attest() that returns just the ExecutionManifest without the receipt envelope.

Context manager

with VerdifaxClient(api_key="vfx_...") as client:
    receipt = client.attest(...)
# connection pool closed automatically

Environment variables

VariableEffect
VERDIFAX_API_URLDefault base URL
VERDIFAX_API_KEYDefault API key

Explicit constructor arguments override env vars.

Connection reuse

For high-throughput servers, instantiate one VerdifaxClient at startup and reuse. Don't construct a new client per request, that re-creates the connection pool and triggers extra TCP handshakes.

Return types and exception handling

client.attest() returns an AttestationReceipt on success. When the orchestrator refuses or halts a run (a policy deny, a per-run budget halt, a cumulative budget halt, or any other stage failure), it answers HTTP 422 with an error_stage field, and the SDK raises StageError. Any other non-success response raises APIError, and a network failure raises ConnectionError:

from verdifax import VerdifaxClient, StageError, APIError

client = VerdifaxClient()
try:
    receipt = client.attest(payload="...", program_id="...", ...)
    print(receipt.manifest_hash)  # OK run
except StageError as e:
    print(f"Stage {e.stage} refused or halted the run: {e.message}")
    print(e.response_body)  # the orchestrator's full response, including any sealed receipt
except APIError as e:
    print(f"HTTP {e.status_code}: {e.message}")

StageError is a subclass of APIError, so catch it first. Both carry status_code, message, and response_body; StageError adds stage, the name of the pipeline stage that refused the run.

client.execute() takes the same arguments as attest() and returns only the ExecutionManifest from the receipt.

Continue