# SDKs (TypeScript / Python)

Source: https://docs.simail.ai/sdk/

> The official TypeScript and Python clients for the simail API — installation, configuration, idempotent sends and error handling.

Both SDKs are thin, dependency-free clients over the [REST API](/api/). They read the key from your
code (load it from `SIMAIL_API_KEY`), set the headers for you and turn problem+json errors into
exceptions with the fields an agent needs. Resource methods are generated from the OpenAPI document
at `GET https://api.simail.ai/v0/openapi.json`, so they always match the API reference; every client
also exposes a generic `request()` for any endpoint.

## TypeScript

```sh
npm install @simail/sdk
```

Works in Node 22 and later, Cloudflare Workers and other runtimes with a standard `fetch`. No runtime dependencies. Use it on a server, never in a browser: it needs your API key.

```ts
import { Simail, SimailApiError } from "@simail/sdk";

const simail = new Simail({ apiKey: process.env.SIMAIL_API_KEY });

// Call this first: during the private beta, sign-up is closed.
const beta = await simail.beta();

// Any endpoint through request(method, path, body?, { idempotencyKey? })
const inbox = await simail.request("POST", "/v0/inboxes", { username: "shop-helper", client_id: "shop-helper" }, { idempotencyKey: "create-shop-helper" });

try {
  await simail.request(
    "POST",
    "/v0/inboxes/shop-helper@simail.email/messages/msg_…/reply",
    { text: "Thanks! Your order shipped today." },
    { idempotencyKey: "reply-msg_…-1" },
  );
} catch (e) {
  if (e instanceof SimailApiError && !e.retryable) {
    // e.status, e.code ("thread_locked", "send_blocked", …), e.requestId, e.body (full problem+json)
  }
  throw e;
}
```

| Option | Default |
|---|---|
| `apiKey` | none (only `beta()` works without a key) |
| `baseUrl` | `https://api.simail.ai` |
| `fetch` | the global `fetch` (pass your own for proxies or tests) |
| `userAgent` | `simail-sdk-ts/<version>` |

## Python

```sh
pip install simail
```

Python 3.10 or later, standard library only.

```python
import os
from simail import Simail, SimailApiError

simail = Simail(api_key=os.environ["SIMAIL_API_KEY"])
simail.beta()

try:
    simail.request(
        "POST",
        "/v0/inboxes/shop-helper@simail.email/messages/msg_…/reply",
        {"text": "Thanks! Your order shipped today."},
        idempotency_key="reply-msg_…-1",
    )
except SimailApiError as e:
    if not e.retryable:
        print(e.status, e.code, e.request_id)  # e.body has the full problem+json
    raise
```

`Simail(api_key=None, base_url="https://api.simail.ai")`; requests time out after 30 seconds.

## Errors

Both SDKs raise `SimailApiError` for any non-2xx response:

| Field | From |
|---|---|
| `status` | HTTP status |
| `code` | problem+json `code` (see [Errors](/errors/)) |
| `retryable` | problem+json `retryable` |
| `requestId` / `request_id` | `request_id`, also in the `x-request-id` header |
| `body` | the whole problem+json object, including `human_message`, `reasons` or `reason` when present |

The SDKs do not retry on their own, so a send is never repeated behind your back. Retry only when
`retryable` is true, after `Retry-After`, with the **same** idempotency key. See
[Idempotency](/idempotency/).

## Keys

Never hard-code a key and never pass one through a prompt. Load it from the environment or your
secret manager, and give each agent its own inbox-scoped key ([Authentication](/authentication/)).
