Python SDK
The zentiq package calls every operation of the API from your server. It runs on Python 3.9 or later with the standard library only, and ships typed dictionaries for every object in the OpenAPI document.
pip install "zentiq>=1,<2"Coming to PyPI
zentiq 1.0.0 is being released with the 2026-10-01 contract. The command above installs 1.0.0 or a later 1.x only, so it works as soon as 1.0.0 is out.The client#
import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"]) # a server secret
me = zentiq.get_me()
print(me["organization"]["displayName"], me["apiKey"]["effectiveScopes"])Zentiq(api_key=None, base_url="https://app.zentiqai.com/v1", api_version="2026-10-01", max_retries=2, timeout=90.0, transport=None): without api_key it reads ZENTIQ_API_KEY; transport lets you bring your own HTTP stack.
Operations#
Every operation is a method named after its operation id in snake_case. Path parameters come first, then the body as a dict (or, for a GET, the query as keyword arguments):
persona = zentiq.create_persona({"name": "Ava", "systemPrompt": "You are Ava, Acme's product specialist."})
zentiq.update_persona(persona["id"], {"greeting": None}) # None sends null: it clears the greeting
page = zentiq.list_personas(limit=20) # {"data": [...], "nextCursor": ...}
for p in zentiq.paginate("list_personas", limit=100):
print(p["id"], p["name"])Answers are plain dictionaries with the API's own field names (systemPrompt, nextCursor), typed with TypedDicts (from zentiq.types import Persona). Every method also takes idempotency_key, api_version and timeout. zentiq.request("createPersona", body=…) calls any operation by its id.
Errors#
The same kinds as the Node SDK, as exceptions: ZentiqError and InvalidRequestError, ConsentError, AuthenticationError, InsufficientMinutesError, PermissionDeniedError, UpgradeRequiredError, FeatureNotInPlanError, NotFoundError, ConflictError, VersionConflictError, DuoNotLiveError, IdempotencyError, GoLiveRefusedError, RateLimitError, ServerError and APIConnectionError (named so they never shadow Python's own PermissionError and ConnectionError). Each has status, code, message, param, details, request_id and, where it applies, retry_after.
from zentiq import UpgradeRequiredError, ZentiqError
try:
zentiq.create_voice({"audioBase64": "data:audio/wav;base64,...", "consent": {"attested": True, "subject": "myself"}})
except UpgradeRequiredError as e:
print(e.feature, e.plan, e.message)
except ZentiqError as e:
print(e.status, e.code, e.request_id)Waiting and webhooks#
from zentiq import verify_webhook
doc = zentiq.create_document(pack["id"], {"url": "https://www.example.com/help"})
zentiq.wait_until_ready("get_document", doc["id"]) # ready, or raises on failed
# In your webhook handler: the raw body, exactly as it arrived
event = verify_webhook(raw_body, request.headers, os.environ["ZENTIQ_WEBHOOK_SECRET"])
if event["type"] == "lead.captured":
print(event["data"]["inboxItemId"])