# 身份验证

每次运行模型或读取请求的调用都需要 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`；在某个请求完成后再重新启动。