> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kallabot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SDKs

> Official TypeScript and Python libraries: typed, safe to retry, auto-paging, with webhook verification and a browser call client.

> [!NOTE]
>
> The SDKs aren't published yet. The install commands below will work once `@kallabot/sdk` is on npm and `kallabot` is on PyPI. Until then, call the API directly; every example in these docs also has a curl tab.

> [card] TypeScript / JavaScript
>
> `npm i @kallabot/sdk`
>
> Node 18+, Deno, Bun, Cloudflare Workers, Vercel Edge, and browsers (for voice calls). No runtime dependencies.

> [card] Python
>
> `pip install kallabot`
>
> Python 3.9+. Sync `Kallabot` and async `AsyncKallabot` clients with the same methods.

Both are generated from the same OpenAPI spec as the [API reference](https://docs.kallabot.com/api-reference/introduction.md), so every operation, field and scope is there, with editor completion.

## Quickstart

```typescript Node SDK theme={"dark"}
import Kallabot from "@kallabot/sdk";

const kallabot = new Kallabot(); // reads KALLABOT_API_KEY
const call = await kallabot.calls.create({
  agent_id: "8f0e4c1a-3b7d-4e2f-9a61-2c5d8b7e1f30",
  to: "+971501234567",
  variables: { first_name: "Sara" },
});
console.log(call.id, call.lifecycle); // "call_5f0a…", "queued"
```

```python Python SDK theme={"dark"}
from kallabot import Kallabot

client = Kallabot()  # reads KALLABOT_API_KEY
call = client.calls.create(
    agent_id="8f0e4c1a-3b7d-4e2f-9a61-2c5d8b7e1f30",
    to="+971501234567",
    variables={"first_name": "Sara"},
)
print(call.id, call.lifecycle)  # call_5f0a…  queued
```

Methods are named after their resource: `calls.create()`, `agents.list()`, `agents.publish()`, `agents.versions.list()`, `knowledge.sources.create()`, `webhooks.create()`, `webCalls.create()` (`web_calls.create()` in Python). TypeScript reads with `get()`, Python with `retrieve()`. Both kinds of [API key](https://docs.kallabot.com/developers/authentication.md#two-kinds-of-key) work the same way.

## What the SDKs do for you

> [accordion] Automatic idempotency keys
>
> Every create and action gets a fresh `Idempotency-Key`, **reused on every retry**, so a retried `calls.create` can never ring someone twice. Pass your own to dedupe across your own retries:
>
> ```typescript theme={"dark"}
> await kallabot.calls.create({ agent_id, to }, { idempotencyKey: `reminder-${appointment.id}` });
> ```
>
> ```python theme={"dark"}
> client.calls.create(agent_id=agent_id, to=to, idempotency_key=f"reminder-{appointment.id}")
> ```

> [accordion] Retries with backoff
>
> Network errors, timeouts, `408`, retryable `5xx` (only where a repeat can't run twice), `429` and `409 idempotency_in_progress` are retried with exponential backoff and jitter. A `429` waits exactly `Retry-After`. Set `maxRetries` / `max_retries` (default 2). Errors that need a change to the request are never retried.

> [accordion] Typed errors
>
> Every API error is an exception carrying the stable `code`, `status`, `detail`, field problems and `requestId` / `request_id`.
>
> ```typescript theme={"dark"}
> import { PaymentRequiredError, ValidationError, KallabotError } from "@kallabot/sdk";
> try {
>   await kallabot.calls.create({ agent_id, to });
> } catch (err) {
>   if (err instanceof PaymentRequiredError) notifyOwner("Out of minutes");
>   else if (err instanceof ValidationError) err.fieldProblems.forEach((p) => show(p.path, p.message));
>   else if (err instanceof KallabotError) console.error(err.code, err.requestId);
>   else throw err;
> }
> ```
>
> ```python theme={"dark"}
> import kallabot
> try:
>     client.calls.create(agent_id=agent_id, to=to)
> except kallabot.APIStatusError as err:
>     if err.code == "insufficient_credit":
>         notify_owner("Out of minutes")
>     else:
>         raise
> ```

> [accordion] Auto-pagination
>
> Iterate a list and the SDK fetches further pages as you go:
>
> ```typescript theme={"dark"}
> for await (const agent of kallabot.agents.list({ status: "active" })) console.log(agent.name);
> ```
>
> ```python theme={"dark"}
> for call in client.calls.list(direction="outbound"):
>     print(call.id, call.outcome)
> ```

> [accordion] Revisions
>
> Pass the `revision` you read so a stale write is refused: `{ ifMatch: agent.revision }` in TypeScript, `if_match=agent.revision` in Python.

> [accordion] Webhook verification
>
> `verify` checks the Standard Webhooks signature and timestamp and returns a typed event.
>
> ```typescript theme={"dark"}
> import { Webhooks } from "@kallabot/sdk";
> const event = await Webhooks.verify(rawBody, request.headers, process.env.KALLABOT_WEBHOOK_SECRET!);
> ```
>
> ```python theme={"dark"}
> event = kallabot.webhooks.verify(raw_body, headers, secret="whsec_…")
> ```
>
> See [Webhooks](https://docs.kallabot.com/developers/webhooks.md#with-the-kallabot-sdk).

> [accordion] Request IDs and rate limits
>
> Every result knows its response: `agent.lastResponse.requestId` and `.rateLimit` in TypeScript; `agent.request_id` and `agent.rate_limit` in Python.

> [accordion] File uploads
>
> `knowledge.sources.create` sends files as multipart: `toFile(buffer, "menu.pdf")` in TypeScript, a `Path`, an open file or bytes in Python. See [Knowledge](https://docs.kallabot.com/developers/knowledge.md).

## Browser voice calls

`@kallabot/sdk/web` connects a web page to an agent over WebRTC. It never sees an API key: your server creates the session and hands the browser a single-use grant.

```typescript theme={"dark"}
import { KallabotWebCall } from "@kallabot/sdk/web";

const { id, grant, ice_servers } = await fetch("/api/voice", { method: "POST" }).then((r) => r.json());
const call = await KallabotWebCall.start({ callId: id, grant, iceServers: ice_servers });
call.on("transcript", (line) => render(line));
await call.hangUp();
```

See [Web calls](https://docs.kallabot.com/developers/web-calls.md) for the server side.

> [!WARNING]
>
> The main client refuses to start in a web page, whichever key you pass, because anyone could read the key there. In the browser, use only `@kallabot/sdk/web`.

## Pin the API version

Set `Kallabot-Version` once as a default header, so a future API version never changes behaviour under you:

```typescript theme={"dark"}
const kallabot = new Kallabot({ defaultHeaders: { "Kallabot-Version": "2026-11-07" } });
```

```python theme={"dark"}
client = Kallabot(default_headers={"Kallabot-Version": "2026-11-07"})
```

Each request also identifies the SDK release (`X-Kallabot-SDK`). If a release is ever retired, the API answers `426 sdk_version_unsupported` and the SDK tells you how to upgrade. See [Versioning](https://docs.kallabot.com/developers/versioning.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.