# 身份验证

每次运行模型或读取请求的调用都需要 API 密钥。目录（`GET /models`、`GET /categories`）、`POST /quote` 和 OpenAPI 文档是公开的。

## API 密钥

在 [https://doitong.com/developers/dashboard#keys](https://doitong.com/developers/dashboard#keys) 创建和撤销密钥。密钥的格式为 `doitong_` 后跟 64 个十六进制字符，并且只会在创建时显示一次。将其发送到 `Authorization` 标头中：

```bash
curl https://api.doitong.com/v1/account -H "Authorization: Bearer $DOITONG_API_KEY"
```

`X-API-Key: <key>` 同样有效。

> [!WARNING]
> 请将密钥保存在您的服务器上：任何拥有密钥的人都可以使用该密钥获准使用的 API 积分。如果密钥泄露，请撤销它并创建新密钥。

不带密钥的请求会收到带有代码 `missing_api_key` 的 `401`；未知、已撤销或已过期的密钥同样会收到 `401`。

## 权限范围

每个密钥都带有权限范围。模型 API 会检查以下范围：

| 操作 | 所需权限范围 |
|---|---|
| 运行模型、取消请求、删除请求的文件、更改存储设置 | `models:run`（具有旧版 `images:create` 或 `videos:create` 的密钥也有效） |
| 创建上传 URL | `models:run` 或 `media:upload` |
| 读取请求、账户 | `models:read`（可以运行模型的密钥也可以读取） |

新密钥默认获得 `models:read` 和 `models:run`。缺少正确权限范围的调用会收到带有代码 `insufficient_scope` 的 `403`。

## 积分预算

密钥可以拥有由账户所有者设置的 API 积分预算（1,000 API 积分 = $1）：总预算、每日预算（最近 24 小时），或两者兼有。在扣除运行费用之前，系统会将费用与该密钥通过此 API 已使用的金额（扣除退款后）进行比较。超过预算的运行会被拒绝，并返回 `402 budget_exceeded`，不会产生费用。

> [!IMPORTANT]
> 预算拒绝是最终结果：除非所有者提高预算，否则重试不会有帮助。

没有预算的密钥最多可以使用 API 余额。除此之外，如果 API 余额不足以支付某次运行，系统会返回带有 `top_up_url` 的 `402 insufficient_credits`。

`GET https://api.doitong.com/v1/account` 会显示 API 余额和密钥的剩余预算（均以 API 积分表示）：

```json 200 OK · 账户
{
  "object": "account",
  "credits": 125000,
  "balance": { "credits": 125000, "usd": "125.00" },
  "top_up_url": "https://doitong.com/developers/dashboard#balance",
  "key": {
    "name": "Production server",
    "prefix": "doitong_3fa9c1e...",
    "scopes": ["models:read", "models:run"],
    "budget_remaining": 50000,
    "rate_limit": 3600,
    "rate_limit_remaining": 3571
  },
  "webhook_signing_secret": "whsec_..."
}
```

当密钥没有自己的预算时，`budget_remaining` 为 `null`。

## 速率限制

除非另行设置限制，否则每个密钥每小时最多可发出 3600 个请求。每个经过身份验证的响应都会携带当前状态：

| 标头 | 含义 |
|---|---|
| `X-RateLimit-Limit` | 当前窗口内允许的请求数 |
| `X-RateLimit-Remaining` | 当前窗口内剩余的请求数 |
| `X-RateLimit-Reset` | 窗口重置时的 Unix 时间 |

超过限制时，您会收到带有 `Retry-After` 标头的 `429`（单位为秒）。使用 `?wait=` 的长轮询每次调用计为一个请求，因此等待比快速轮询更节省请求数。

每个账户还限制最多同时处理 10 个请求（`queued` 或 `running`）。再启动一个请求会返回 `429 too_many_inflight`；等一个请求完成后再重新启动。
