Skip to main content
Two official client libraries wrap the API: @sempera/sdk for TypeScript and sempera-sdk for Python. Both are generated from the live OpenAPI document (https://api.sempera.org/openapi.json), so each has one method for every operation the document lists, plus a small hand-written core for authentication, errors, retries, idempotency keys, paging and webhook verification. They are not published to npm or PyPI yet. Today you install them from the Sempera source tree (04-delivery/api-sdks/ in the repository) or vendor the folder; Web SDK still applies for the browser. The SDKs call only routes that openapi.json lists.

Install

Authentication

Send your API key as a bearer token (Authentication and credentials). Pass it to the constructor, or set SEMPERA_API_KEY and omit it. Keep the key on your server.
Methods are named after the operation id in the contract: createAgent in TypeScript, create_agent in Python. Path and query parameters are named exactly as in openapi.json. A request body is passed as a plain object or dict.

Create and publish an agent

Place a prompt call

createCall / create_call places one outbound call. mode: "prompt" uses only the prompt. agent_id is still the line (number, consent, do-not-contact, calling hours, caps and billing). Send task, and optionally first_sentence, voice and language. Do not send agent_version or production with mode: "prompt". The call still requires Idempotency-Key and consent_basis. Passing your own key makes a retry safe across process restarts.

Errors

Every refusal is the one error envelope (Errors and limits). The SDK raises a typed error that carries the stable code, the optional reason and field, the request_id to quote to support and the HTTP status. Branch on code or reason, never on the message.
The SDK retries what is safe to retry, two times by default, with exponential backoff and jitter: a 429 (waiting the Retry-After it sends), a 502, a 504, a 503 with code service_unavailable, and a dropped connection. A 503 owner_setup_required is never retried because waiting does not fix it. A write that has no idempotency key is retried only after a 429, which means it was not processed. Change the count with max_retries / maxRetries on the client or on one call.

Pagination

List routes take limit and cursor and answer {"object": "list", "data": [...], "has_more": true, "next_cursor": "..."} (Errors and limits). paginate follows next_cursor until has_more is false and yields every item.
paginate follows the native envelope only. A compatibility route keeps its own envelope (Errors and limits), so paginate raises on one instead of silently yielding nothing; page those by hand with the cursor it returns.

Idempotency keys

Operations that accept an Idempotency-Key (listed in Errors and limits) get one automatically: the SDK generates a key for the call and sends the same key on every retry, so a retried POST cannot act twice. Pass your own to make a retry safe across process restarts, for instance one derived from your order id. A key lives 24 hours; the same key with a different request is a 409 idempotency_key_reused.

Webhook signature verification

Verify every delivery against the raw request body before you parse it (Webhooks). The helper checks the X-Sempera-Signature header (t=<unix seconds>,v1=<hex HMAC-SHA256 over "<t>." + body>) in constant time and rejects a timestamp more than 300 seconds from your clock. It raises WebhookSignatureError; answer 400 and process nothing. Then drop an event id you have already handled.
The webhooks guide publishes a known answer (secret, timestamp, body and signature). Both SDKs are tested against it, and you can use it to test your own handler.

Staying in step with the API

The operation layers are regenerated from the contract with one command, python3 06-tools/build-sdks.py, and a test in the Sempera repository fails when a route is added, renamed or retyped without regenerating. GET /v1/me and the API_VERSION constant tell you which contract version your copy was built from.