# SDK（TypeScript / Python）

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

> simail API 的官方 TypeScript 与 Python 客户端：安装、配置、幂等发送和错误处理。

两个 SDK 都是盖在 [REST API](/zh/api/) 上的薄客户端，没有额外运行时依赖。它们从你的代码读 key（从 `SIMAIL_API_KEY` 加载），替你设置头，并把 problem+json 错误变成带 agent 所需字段的异常。资源方法由 `GET https://api.simail.ai/v0/openapi.json` 的 OpenAPI 文档生成，所以始终和 API 参考一致；每个客户端也提供通用的 `request()`，可以打任意端点。

## TypeScript

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

可在 Node 22 及以后、Cloudflare Workers 和其他带标准 `fetch` 的运行时使用。没有运行时依赖。在服务器上用，不要放进浏览器：它需要你的 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;
}
```

| 选项 | 默认 |
|---|---|
| `apiKey` | 无（没有 key 时只有 `beta()` 能用） |
| `baseUrl` | `https://api.simail.ai` |
| `fetch` | 全局 `fetch`（代理或测试时传入你自己的） |
| `userAgent` | `simail-sdk-ts/<version>` |

## Python

```sh
pip install simail
```

Python 3.10 或更高，只用标准库。

```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")`；请求 30 秒后超时。

## 错误

两个 SDK 对任何非 2xx 响应都抛 `SimailApiError`：

| 字段 | 来自 |
|---|---|
| `status` | HTTP 状态 |
| `code` | problem+json 的 `code`（见[错误码](/zh/errors/)） |
| `retryable` | problem+json 的 `retryable` |
| `requestId` / `request_id` | `request_id`，也在 `x-request-id` 头里 |
| `body` | 整个 problem+json 对象，有的话包括 `human_message`、`reasons` 或 `reason` |

SDK 不会自己重试，所以发送不会在你背后再发一次。只有 `retryable` 为真时才重试，等过 `Retry-After`，并用**同一把**幂等键。见[幂等](/zh/idempotency/)。

## 密钥

不要把 key 写死，也不要通过提示词传递。从环境变量或密钥管理器加载，并给每个 agent 自己的、作用域落在邮箱上的 key（[认证](/zh/authentication/)）。
