<!-- toc: 入门 -->
# Hyperouter API {#introduction}

*版本 v1 · 更新于 2026 年 10 月 25 日*

> 本文档提供 Markdown 版本，方便 AI 助手读取。可从 [/llms.txt](https://hyperouter.app/llms.txt) 开始，或获取 [/llms-full.txt](https://hyperouter.app/llms-full.txt)，一个文件包含所有页面。本页地址为 [/docs.md](https://hyperouter.app/docs.md)。

Hyperouter 是位于众多模型厂商之前的统一 HTTP API。你发送一个指定模型的请求，Hyperouter 会选出能够处理它的服务商，转发请求，并按该服务商的标价从你的余额中扣费。

`BASE https://api.hyperouter.app/v1`

所有接口都沿用 OpenAI 的请求与响应格式。只需更换 base URL 和 API 密钥，即可使用 OpenAI SDK。Hyperouter 在 OpenAI 的请求体之上增加了少量字段，本参考中均标注为“新增”。

| 接口 | 用途 | 认证 |
| --- | --- | --- |
| `GET /v1/models` | 列出你的账户可调用的模型。 | API 密钥 |
| `POST /v1/chat/completions` | 聊天补全，可选流式输出。 | API 密钥 |
| `POST /v1/images/generations` | 文生图。 | API 密钥 |
| `POST /v1/images/edits` | 编辑图片。 | API 密钥 |
| `POST /v1/videos` | 根据提示词创建视频，可附带一张图片。 | API 密钥 |
| `POST /v1/videos/edits` | 编辑或放大视频。 | API 密钥 |
| `POST /v1/videos/extensions` | 延长视频。 | API 密钥 |
| `POST /v1/videos/{id}/remix` | 用新的提示词生成视频的新版本。 | API 密钥 |
| `GET /v1/videos`, `GET /v1/videos/{id}`, `GET /v1/videos/{id}/content`, `DELETE /v1/videos/{id}` | 列出、查询、下载和删除视频。 | API 密钥 |
| `GET /v1/generations/{id}` | 查询任意请求的记录：状态、用量和扣费。 | API 密钥 |
| `GET /v1/credits` | 你的余额、未完成请求预扣的金额，以及剩余可用额度（`balance_usd`、`held_usd`、`available_usd`，均为十进制美元字符串）。 | API 密钥 |

> [登录 dash.hyperouter.app](https://dash.hyperouter.app)（支持 Google 或 GitHub）即可创建 API 密钥。`GET /v1/models` 返回请求时你可调用的模型。

## 快速开始 {#quickstart}

1. [登录](https://dash.hyperouter.app)并创建 API 密钥。密钥以 `sk-hr-v1-` 开头，仅显示一次。
2. 将密钥保存到环境变量中，例如 `HYPEROUTER_API_KEY`。
3. 充值：在控制台中提交充值申请。付款确认后，工作人员会为你的余额入账。
4. 将任意 OpenAI SDK 指向上述 base URL，并选择一个模型。

```bash
curl https://api.hyperouter.app/v1/chat/completions \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x-ai/grok-4.7",
    "messages": [{"role": "user", "content": "Hello"}]
  }'
```

```typescript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.hyperouter.app/v1",
  apiKey: process.env.HYPEROUTER_API_KEY,
});

const res = await client.chat.completions.create({
  model: "x-ai/grok-4.7",
  messages: [{ role: "user", content: "Hello" }],
});
console.log(res.choices[0].message.content);
```

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hyperouter.app/v1",
    api_key=os.environ["HYPEROUTER_API_KEY"],
)

res = client.chat.completions.create(
    model="x-ai/grok-4.7",
    messages=[{"role": "user", "content": "Hello"}],
)
print(res.choices[0].message.content)
```

## 身份验证 {#authentication}

每个请求都以 Bearer 令牌的形式携带你的 API 密钥。

```
Authorization: Bearer sk-hr-v1-...
```

密钥可以动用你的余额，请只保存在服务端，切勿放入浏览器或移动端代码。Hyperouter 只保存每个密钥的哈希值，因此丢失的密钥无法再次显示，请重新创建。

在[控制台](https://dash.hyperouter.app/keys)中，你可以为每个密钥命名、设置额度上限，或将其停用。停用的密钥立即失效。如果某个请求会使密钥超出其额度上限，将被拒绝并返回 `402 insufficient_credits`。

### 身份验证错误

| 状态码 | type | code | 触发条件 | message |
| --- | --- | --- | --- | --- |
| `401` | `authentication_error` | `invalid_api_key` | 缺少请求头、不是 `Bearer` 格式，或密钥不以 `sk-hr-v1-` 开头。 | `The API key is missing or malformed. Send Authorization: Bearer sk-hr-v1-…` |
| `401` | `authentication_error` | `invalid_api_key` | 密钥不存在或已停用。 | `The API key is not valid.` |
| `403` | `permission_error` | `account_suspended` | 账户已被暂停。每个请求都会检查。 | `This account is suspended. Open a support ticket.` |
| `429` | `rate_limit_error` | `too_many_auth_failures` | 来自你所在地址的请求在一分钟内有超过 30 个使用了缺失或无效的密钥。此后 15 分钟内，来自该地址的所有 `/v1` 请求都会被拒绝，即使密钥有效也不例外。`Retry-After` 给出剩余秒数。 | `Too many failed API key checks from this address. Try again after the time in Retry-After.` |
| `500` | `server_error` | `internal` | Hyperouter 无法校验密钥。 | `An internal error occurred. Try again.` |

```bash
curl https://api.hyperouter.app/v1/generations/0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21 \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY"
```

```json
{ "error": { "message": "The API key is not valid.", "type": "authentication_error", "code": "invalid_api_key", "param": null } }
```

## 错误 {#errors}

所有错误都使用 OpenAI 的错误对象，并配以对应的 HTTP 状态码。

```json
{
  "error": {
    "message": "n must be an integer from 1 to 128",
    "type": "invalid_request_error",
    "code": "invalid_body",
    "param": "n"
  }
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `message` | string | 说明问题的一句话。请勿解析该字段。 |
| `type` | string | 错误类别。见下方列表。 |
| `code` | string | 标识原因的稳定标识符。请以该字段进行匹配。 |
| `param` | string \| null | 出错的请求字段，或 `null`。 |

### 类型与状态码

| 状态码 | type | 含义 |
| --- | --- | --- |
| `400` | `invalid_request_error` | 请求无效。`code` 指明原因，`param` 指明字段。 |
| `401` | `authentication_error` | API 密钥缺失或无效。 |
| `402` | `insufficient_credits` | 你的余额或密钥的额度上限，不足以覆盖该请求可能产生的最高费用。 |
| `403` | `permission_error` | 账户已被暂停。 |
| `404` | `not_found` | id 不存在、id 属于其他账户，或视频已超过其 `expires_at`。 |
| `409` | `conflict` | 对象当前状态不允许该调用（`video_not_finished`），或 `Idempotency-Key` 冲突（见[重试与幂等](#idempotency)）。 |
| `422` | `invalid_request_error` | 请求有效，但其结果被拒绝（`expansion_refused`）。不计费。 |
| `429` | `rate_limit_error` | 该模型的所有服务商均已满载、你的账户超出[速率限制](#rate-limits)，或来自你所在地址的 API 密钥校验失败次数过多。请在 `Retry-After` 响应头给出的时间之后重试。 |
| `500`, `501` | `server_error` | Hyperouter 自身出错，或接口尚未实现。不计费。 |
| `503` | `upstream_error` | 服务商出错或未在时限内响应：`code` 指明具体情况（`all_venues_failed`、`upstream_error` 或 `timeout`）。响应头 `X-Upstream-Status` 为 `502`（出错）或 `504`（超时）。 |

Hyperouter 从不返回 `502` 或 `504`：这两个状态码会以我们边缘网络的裸页面形式到达你手中，不带错误响应体。在网关本应返回它们的场景下，你会收到 `503` 及下述响应体，网关状态码则放在 `X-Upstream-Status` 中。

### 可能遇到的 code

| code | 状态码 | 触发条件 |
| --- | --- | --- |
| `invalid_body` | 400 | 请求体字段或查询参数无法解析、类型错误，或超出允许的取值范围。`param` 指明字段。 |
| `unsupported_content_type` | 400 | `/v1/images/generations` 收到了 `multipart/form-data` 请求体。请发送 JSON。`param` 为 `null`。 |
| `request_too_large` | 413 | `multipart/form-data` 上传超过 50 MiB。较大的媒体请以 https URL 发送。 |
| `unknown_model` | 400 | 该接口不存在此模型，或没有服务商能在你的 `provider` 偏好下提供它。 |
| `unsupported_parameter` | 400 | 某个适用于其他模型的参数在此模型上不可用。见[模型专属参数](#parameters)。 |
| `invalid_combination` | 400 | 模型厂商不允许这些参数同时使用，例如参考媒体与关键帧一起使用。 |
| `invalid_size` | 400 | `size` 不是 `WIDTHxHEIGHT` 格式，或该模型不允许此尺寸。 |
| `too_many_images` | 400 | `n` 或输入图片数量超出上限。 |
| `invalid_image`, `invalid_video` | 400 | 图片或视频的 URL 不是指向公共主机的 https 地址：`data:` URL、`http://` URL、IP 地址或内部名称。`param` 指明字段。 |
| `image_required` | 400 | 该模型需要输入图片而你没有发送（或它只支持编辑，而你调用了 generations）。 |
| `invalid_seconds` | 400 | `seconds` 不被该模型允许，或以 URL 提供视频时缺少该字段。 |
| `unsupported_operation` | 400 | 该模型不支持此操作（编辑、延长、remix，或图片编辑）。 |
| `video_not_ready` | 400 | 源视频尚未完成。 |
| `context_length_exceeded` | 400 | 聊天提示词与 `max_tokens` 之和超出模型的上下文长度。 |
| `content_rejected` | 400 | 模型厂商的安全过滤器拒绝了输入。 |
| `vendor_rejected` | 400 | 模型认定请求无效并拒绝处理。请检查其参数和输入。 |
| `clip_too_long` | 400 | 参考视频片段加上请求的 `seconds` 超出了模型的上限（30 秒）。不计费。 |
| `prompt_rejected` | 400 | 提示词要求提示词扩写模型输出其指令。不计费。见[提示词扩写](#prompt-expansion-model)。 |
| `expansion_refused` | 422 | 提示词扩写模型的改写结果被拒绝或为空。不计费。见[提示词扩写](#prompt-expansion-model)。 |
| `invalid_api_key` | 401 | 见[身份验证](#authentication)。 |
| `insufficient_credits` | 402 | 见[计费与限制](#billing)。 |
| `account_suspended` | 403 | 账户已被暂停。 |
| `moderation_not_enabled` | 403 | 账户未启用 `moderation: "low"`。见[内容审核](#moderation)。 |
| `feature_not_enabled` | 403 | 在提供 `prompt_expand` 的模型上，账户未启用该功能。请提交支持工单申请开通。不会预扣费用，也不会发送给服务商。见[提示词扩写](#prompt-expansion)。 |
| `model_not_enabled` | 403 | 该模型需要为你的账户开通权限。请提交支持工单申请。不会预扣费用，也不会向服务商发送任何内容。 |
| `not_found` | 404 | 对象不存在。 |
| `video_not_finished` | 409 | 你删除了仍在生成中的视频。 |
| `venue_busy` | 429 | 该聊天模型的所有服务商都已超出其速率预算。 |
| `rate_limited` | 429 | 你的账户超出了每分钟请求数或并发请求数。见[速率限制](#rate-limits)。 |
| `too_many_auth_failures` | 429 | 来自你所在地址的请求在一分钟内有超过 30 个使用了无效的 API 密钥。见[速率限制](#rate-limits)。 |
| `all_venues_failed` | 503 | 没有健康的服务商，或所有服务商均失败。 |
| `upstream_error` | 503 | 图像或视频任务在模型端失败。不会向你收费。 |
| `internal`, `server_error`, `no_price` | 500 | Hyperouter 自身出错（`no_price`：该模型当前无法定价）。不计费。 |
| `not_implemented` | 501 | `This endpoint is not implemented yet.` |
| `invalid_idempotency_key` | 400 | `Idempotency-Key` 请求头超过 255 个字符，或不是可打印 ASCII。见[重试与幂等](#idempotency)。 |
| `idempotency_key_reused` | 409 | 该 `Idempotency-Key` 已被用于另一个不同的请求。 |
| `idempotency_key_in_use` | 409 | 使用该 `Idempotency-Key` 的请求仍在启动中。请使用同一个键重试。 |
| `idempotency_key_replayed` | 409 | 使用该 `Idempotency-Key` 的聊天补全已经运行过。`error.generation_id` 为其 id。 |
| `timeout` | 503 | 同步图像请求未在 90 秒内完成。任务仍在生成：`error.generation_id` 是用于轮询的 id。 |

## 重试与幂等 {#idempotency}

网络错误或超时并不能告诉你 Hyperouter 是否收到了请求。如果你再次发送，可能会启动第二个任务并重复付费。`Idempotency-Key` 可以让重复请求变得安全：Hyperouter 会识别出重复请求，不启动第二个任务，不再次预扣，并直接返回首次请求的结果。

**对每一个会产生费用的请求都发送该请求头。** 为每个新请求生成一个新的随机值，例如 UUID v4。将它与请求一起保存，并在重新发送同一请求时每次都使用相同的值。

### 发送键

以下接口接受该请求头：

| 接口 | 重复请求返回 |
| --- | --- |
| `POST /v1/images/generations`, `POST /v1/images/edits` | 首次请求的图像；若使用 `Prefer: respond-async`，则返回带有相同 `id` 的 `202` |
| `POST /v1/videos`, `/v1/videos/edits`, `/v1/videos/extensions`, `/v1/videos/{id}/remix` | 首次请求的 Video 对象（当前状态） |
| `POST /v1/chat/completions` | 带有首次请求 id 的 `409` `idempotency_key_replayed`（见[聊天补全](#idempotency-chat)） |

OpenAI SDK 不会自动发送该请求头。请将它作为额外请求头传入；SDK 在自动重试时会原样重新发送。

```bash
curl https://api.hyperouter.app/v1/images/generations \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -d '{"model": "x-ai/grok-imagine-image", "prompt": "A lighthouse at dusk", "n": 1}'
```

```python
import uuid

key = str(uuid.uuid4())  # one per request; reuse it when you retry this request
img = client.images.generate(
    model="x-ai/grok-imagine-image",
    prompt="A lighthouse at dusk",
    extra_headers={"Idempotency-Key": key},
)
```

```typescript
import { randomUUID } from "node:crypto";

const key = randomUUID(); // one per request; reuse it when you retry this request
const img = await client.images.generate(
  { model: "x-ai/grok-imagine-image", prompt: "A lighthouse at dusk" },
  { headers: { "Idempotency-Key": key } },
);
```

### 重复请求的返回结果

| 你发送的内容 | Hyperouter 的响应 |
| --- | --- |
| 新的键 | 照常运行请求。 |
| 相同的键和相同的请求，且首次请求已被接受 | 如上表所示，返回首次请求的结果。不启动第二个任务，不再次预扣，不再次扣费。 |
| 相同的键和相同的请求，但首次请求仍在受理中 | 等待首次请求，然后按上述方式响应。如果首次请求在 60 秒内仍未启动其任务：返回 `409` `idempotency_key_in_use`。请使用同一个键重试。 |
| 相同的键但请求不同 | `409` `idempotency_key_reused`。不运行任何内容。请使用新的键。 |
| 相同的键，但首次请求在任何任务启动之前就被拒绝（`400`、`402`，或未带 `x-should-retry: false` 的 `5xx`） | 将请求作为新请求运行，因此你可以修正后用同一个键重新发送。 |
| 相同的键，但距首次请求已超过 30 分钟 | 将请求作为新请求运行。 |
| 超过 255 个字符或不是可打印 ASCII 的键 | `400` `invalid_idempotency_key`。不运行任何内容。 |

### 规则

- **作用域。** 键归属于发送它的 API 密钥。两个 API 密钥可以使用相同的值，互不影响。
- **有效期。** 键在首次请求后 30 分钟内有效。请在此时间内重试。
- **相同请求。** 方法、路径和请求体都一致时，两个请求视为相同。JSON 会在解析后比较，因此字段顺序和空白不影响判断。图片或视频是请求体中的 URL，因此比较的是 URL，而不是它所指向的字节。
- **计费。** 使用同一个键发出的请求，无论重复多少次，最多只计费一次。由首次请求的结果直接应答的重复请求不产生费用。
- **保证。** 同一个键绝不会启动多于一个任务，包括两个重复请求同时到达的情况。

### 聊天补全 {#idempotency-chat}

聊天回复不会被重放。使用相同键的重复请求会返回 `409`，code 为 `idempotency_key_replayed`，`error.generation_id` 即首次请求的 id。该请求不会再次运行或计费。请通过 [GET /v1/generations/{id}](#generations) 查询首次请求，以了解其状态、用量和费用。如果首次聊天补全失败且未计费，其键会被释放，重复请求将作为新请求运行。

```json
{
  "error": {
    "message": "A request with this Idempotency-Key already ran as generation 019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17. Chat replies are not replayed: GET /v1/generations/019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17 for its record.",
    "type": "conflict",
    "code": "idempotency_key_replayed",
    "param": null,
    "generation_id": "019a1f3c-5b7e-7d21-9c4a-2e8f6b0d3a17"
  }
}
```

### OpenAI SDK 的自动重试

OpenAI SDK 默认会对 `408`、`409`、`429` 或 `5xx` 响应重试两次，除非响应带有响应头 `x-should-retry: false`。凡是重试会启动第二个任务或产生第二次扣费的响应，Hyperouter 都会附带 `x-should-retry: false`：

- 同步图像请求的 `503` `timeout`：其任务仍在继续，成功后会计费；请使用其 `generation_id` 轮询 [GET /v1/generations/{id}](#generations)；
- 任务创建之后出现的 `500`，例如已完成的图像无法读回时；
- `409` `idempotency_key_reused` 和 `idempotency_key_replayed`，重试无法改变其结果。

对于 `429`、`409` `idempotency_key_in_use`，以及任务创建之前的 `5xx`，Hyperouter 从不附带该响应头，这些情况可以放心重试。使用 `Idempotency-Key` 时，所有重试都是安全的。

<!-- toc: API 参考 -->
## 模型 {#models}

`GET /v1/models`

列出你的账户当前可调用的所有模型，包含价格及所支持的功能。没有已启用服务商的模型不会列出。部分模型需要为你的账户开通权限：开通后才会列出。该接口需要 API 密钥，并列出该密钥所属账户可调用的模型。响应可以缓存 60 秒，仅限在你的客户端缓存。

### 参数

无。

### 响应

```json
{
  "data": [{
    "id": "x-ai/grok-4.7",
    "name": "Grok 4.7",
    "kind": "chat",
    "context_length": 500000,
    "architecture": { "input_modalities": ["text", "image"], "output_modalities": ["text"] },
    "pricing": {
      "prompt": "0.000002", "completion": "0.000006", "input_cache_read": "0.0000005",
      "request": "0", "image": "0", "video_second": "0"
    },
    "top_provider": { "context_length": 500000, "max_completion_tokens": 32768 },
    "response_modes": ["sync", "stream"],
    "supported_parameters": ["max_tokens", "temperature", "top_p", "stop", "stream", "tools", "tool_choice", "response_format", "seed", "frequency_penalty", "presence_penalty"],
    "extra_parameters": {}
  }]
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `id` | string | 模型 id，格式为 `<provider>/<name>`，例如 `x-ai/grok-4.7` 或 `qwen/qwen-image-2.0`。将其作为 `model` 发送。更名后的模型仍可使用旧 id。 |
| `response_modes` | string[] | 模型的应答方式：`sync`（保持连接，返回一次完整结果）、`async`（发送 `Prefer: respond-async`，得到 `202` 后轮询）和 `stream`（`"stream": true`）。仅列出 `async` 的模型必须带上 `Prefer` 请求头，`stream` 仅在列出时可用。视频通过 Videos API 始终是异步的，无论是否带该请求头。 |
| `name` | string | 显示名称。 |
| `kind` | string | `chat`、`image` 或 `video`。 |
| `context_length` | integer | 上下文窗口，单位为 token。图像和视频模型为 `0`。 |
| `architecture` | object | `input_modalities` 和 `output_modalities`。输出为 `["text"]`、`["image"]` 或 `["video"]`。 |
| `pricing` | object of strings | 基础档位的单价（美元），以十进制字符串表示：`prompt` 和 `completion`（每 token）、`input_cache_read`（每个缓存命中 token）、`request`、`image`（每张图像）、`video_second`（每秒视频）。按分辨率定价的视频显示最低价。不适用的单位为 `"0"`。 |
| `top_provider` | object | `context_length` 和 `max_completion_tokens`。 |
| `supported_parameters` | string[] | 对聊天模型，是该模型接受的 OpenAI 参数。对图像和视频模型，是其支持的通用功能（`resolution`、`ratio`、`audio`、`seed`、`negative_prompt`、`first_frame`、`last_frame`、`reference_images`、`reference_videos`、`prompt_extend`）。 |
| `operations` | string[] | 仅限视频模型：模型支持的操作，即 `edit`、`extend` 和 `remix` 中的相应项。模型不支持任何操作时该字段不出现。 |
| `extra_parameters` | object | 模型专属的顶层字段，按名称列出。每个字段包含 `type`、`values`（允许的取值；为空表示任意值）、`price_condition`（该字段是否影响价格）和 `description`。见[模型专属参数](#parameters)。 |

```bash
curl https://api.hyperouter.app/v1/models \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY"
```

### 错误

该接口没有专属错误。

### 聊天模型

价格按每 100 万 token 计：输入 / 缓存输入 / 输出。

<!-- BEGIN GENERATED models-chat: sitemd writes the rows from models.json; edit the header row only. Run cd tools && go run ./sitemd -->
| 模型 | 上下文 | 价格 |
| --- | --- | --- |
| `x-ai/grok-4.7` | 500K | $2.00 / $0.50 / $6.00 |
| `x-ai/grok-4.6` | 500K | $2.00 / $0.50 / $6.00 |
| `x-ai/grok-4.5` | 500K | $2.00 / $0.30 / $6.00 |
| `x-ai/grok-4.3` | 1M | $1.25 / $0.20 / $2.50 |
| `x-ai/grok-build-0.1` | 256K | $1.00 / $0.20 / $2.00 |
| `deepseek/deepseek-v4.1-flash` | 1M | $0.15 / $0.003 / $0.60 |
| `deepseek/deepseek-v4.1-flash-1017` | 1M | $0.15 / $0.003 / $0.60 |
| `openai/gpt-6-astra` | 272K | $10.00 / $1.00 / $50.00 |
| `openai/gpt-6.1-sol` | 272K | $2.00 / $0.10 / $10.00 |
| `z-ai/glm-5.3` | 1M | $1.40 / $0.26 / $4.40 |
| `lumina/face-detect` | 4K | $0.0013 每次请求 |
<!-- END GENERATED models-chat -->

对 `x-ai/` 模型，提示词达到 200,000 token 及以上的请求，整体按长上下文费率计费，该费率为上表的两倍。`deepseek/` 模型在任何提示词长度下都只有一档费率，默认先推理再作答（`reasoning_effort: "none"` 可将其关闭），其推理过程计入 `max_tokens`，上限为 384,000。`z-ai/glm-5.3` 始终会推理：`reasoning_effort` 取 `low`、`high` 或 `max`，`none` 会被拒绝。`openai/` 模型同样会推理，提示词最多 272,000 token。

## 聊天补全 {#chat-completions}

`POST /v1/chat/completions`

为一段对话创建模型响应。请求体即 OpenAI 的 Chat Completions 请求。Hyperouter 新增了 `models`、`provider` 和 `moderation`。

### 参数

| 名称 | 类型 | 必填 | 允许的值 | 默认值 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `model` | string | 是 | `GET /v1/models` 中的聊天模型 id |  | 要使用的模型，例如 `x-ai/grok-4.7`。 |
| `messages` | object[] | 是 | 非空。角色为 `system`、`user`、`assistant`、`tool` |  | 迄今为止的对话。模型支持图像输入时，可传入图片（`image_url` 部分）。 |
| `models` | string[] | 否 | 最多 5 个模型 id |  | 新增。回退模型，在 `model` 的所有服务商都失败后按顺序尝试。 |
| `provider` | object | 否 | 见下文 |  | 新增。路由偏好。 |
| `moderation` | string | 否 | `auto`, `low` | `auto` | 新增。见[内容审核](#moderation)。 |
| `stream` | boolean | 否 |  | `false` | 返回服务器发送事件（SSE）。 |
| `stream_options` | object | 否 | `{"include_usage": true}` |  | 设置 `include_usage` 后，流的末尾会带有一个包含 `usage` 的数据块。 |
| `max_tokens`, `max_completion_tokens` | integer | 否 | 1 或更大 | 模型的最大输出 | 生成 token 数的上限。它同时决定了一个请求最高可能产生的费用，Hyperouter 会在调用前预扣该金额（见[计费](#billing)）。 |
| `n` | integer | 否 | 1 到 128 | `1` | 返回的候选数量。 |
| `temperature`, `top_p`, `seed`, `frequency_penalty`, `presence_penalty`, `logit_bias` | number / integer / object | 否 | 与 OpenAI 相同 |  | 采样控制，原样传给服务商。 |
| `stop` | string \| string[] | 否 |  |  | 终止生成的序列。 |
| `tools`, `tool_choice`, `parallel_tool_calls` | object[], string \| object, boolean | 否 | OpenAI 函数调用格式 |  | 函数调用。仅支持 `function` 类型的工具：其他类型会被拒绝并返回 `400 unsupported_parameter`。 |
| `response_format` | object | 否 | `{"type":"json_object"}` 或 JSON schema |  | 结构化输出。 |
| `reasoning_effort`, `logprobs`, `top_logprobs`, `user` | 与 OpenAI 相同 | 否 |  |  | 模型支持时传给服务商。 |

其他字段会被忽略。每个模型在 [GET /v1/models](#models) 中的 `supported_parameters` 精确列出了它所接受的参数。Grok 4.20 及更新的模型会忽略 `logprobs` 和 `top_logprobs`，因此不在列表中。

### provider 对象 {#routing}

默认情况下，Hyperouter 会把每个聊天请求发给该模型价格最低的健康服务商，价格相同时选最近首 token 耗时最低的。反复出错的服务商会被跳过，直到恢复。`provider` 对象沿用 OpenRouter 的请求格式。

| 名称 | 类型 | 必填 | 允许的值 | 默认值 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `sort` | string | 否 | `price`, `latency`, `throughput` | `price` | 服务商的排序方式。 |
| `order` | string[] | 否 | 服务商名称 |  | 优先按顺序尝试的服务商，例如 `["xai"]`。服务商名称可以是其公开名称（不区分大小写，如 `xAI`、`Qwen`），也可以是其模型 id 的前半部分（`x-ai`、`qwen`）。 |
| `only` | string[] | 否 | 服务商名称 |  | 仅路由到这些服务商。 |
| `ignore` | string[] | 否 | 服务商名称 |  | 绝不路由到这些服务商。 |

### 响应

OpenAI 的聊天补全响应。`id` 即请求 id：可用 [GET /v1/generations/{id}](#generations) 查询。Hyperouter 新增了 `provider`（完成该请求的服务商的公开名称，例如 `xAI`）和 `usage.cost`（费用，单位美元，JSON 数字）。

```json
{
  "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
  "object": "chat.completion",
  "model": "x-ai/grok-4.7",
  "provider": "xAI",
  "choices": [{
    "index": 0,
    "message": { "role": "assistant", "content": "Hello! How can I help?" },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 8,
    "total_tokens": 17,
    "prompt_tokens_details": { "cached_tokens": 0 },
    "cost": 0.000066
  }
}
```

提示词改写类模型只返回一个候选，`usage` 的 token 数为零，并按每个请求收取固定的 `cost`。

### 流式输出 {#streaming}

设置 `"stream": true` 后，响应是 OpenAI 数据块格式的服务器发送事件流，以 `data: [DONE]` 结束。设置 `stream_options.include_usage` 时，`[DONE]` 之前的最后一个数据块带有空的 `choices` 数组，以及包含 `cost` 的 `usage` 对象和 `provider` 字段。无论你是否请求该数据块，用量都会被收集用于计费。

在第一个 token 到达之前，流每 15 秒发送一次注释行 `: processing` 以保持连接。SSE 客户端会忽略注释。

只有在发出第一个 token 之前才会回退到其他服务商。如果服务商在流中途失败，流会以 `data: {"error": {...}}` 结束，随后是 `data: [DONE]`，并且已生成的 token 仍会计费。

服务商生成的 token 都会计费，无论你是否读取。你中止的流，或你不再等待的回复，并不会在服务商处停止，服务商会继续并按完整回答计费：Hyperouter 会把它读到末尾（最多再读 5 分钟）并按此计费。

已接受请求的服务商可能仍在运行它。如果它随后停止响应（流上 5 分钟没有 token，或超过了 `max_tokens` 的回复所需时间），或其回答在第一个 token 之前中断，该请求不会被转发给其他服务商：它会返回 `503`，code 为 `timeout` 或 `upstream_error`，并带有 `error.generation_id`，按其预扣金额计费，其记录上带有 `usage_estimated: true`。

### 示例

```bash
curl https://api.hyperouter.app/v1/chat/completions \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x-ai/grok-4.7",
    "models": ["x-ai/grok-4.6"],
    "provider": { "sort": "latency" },
    "messages": [{ "role": "user", "content": "Hello" }]
  }'
```

### 错误

| 状态码 | type | code | param | 触发条件 |
| --- | --- | --- | --- | --- |
| `400` | `invalid_request_error` | `invalid_body` | 对应字段 | 请求体不是有效的 JSON 或超过 32 MiB；缺少 `model`；`models` 超过 5 项；`n` 超出 1 到 128；`max_tokens` 不是正数；`provider.sort` 不被允许；`moderation` 不是 `auto` 或 `low`（`moderation must be auto or low.`）；`messages` 为空。所有服务商都因请求无效而拒绝时也会返回。 |
| `400` | `invalid_request_error` | `unknown_model` | `model` 或 `models` | 该模型不是聊天模型，或没有已启用的服务商。 |
| `400` | `invalid_request_error` | `unsupported_parameter` | `tools`、`response_format`、`messages` 或 `max_tokens` | 模型不支持工具、响应格式或图片；某个工具不是 `function` 类型；或该模型的所有服务商都无法限定其输出长度。 |
| `400` | `invalid_request_error` | `context_length_exceeded` | `messages` | 提示词与 `max_tokens` 之和超出模型的上下文长度。 |
| `402` | `insufficient_credits` | `insufficient_credits` | `max_tokens` | 余额或密钥额度上限不足以覆盖该请求可能产生的最高费用。message 会说明你能负担多少 token。 |
| `429` | `rate_limit_error` | `venue_busy` |  | 该模型的所有服务商都已超出其速率预算。 |
| `429` | `rate_limit_error` | `rate_limited` |  | 你的账户超出了每分钟请求数或并发请求数（见[速率限制](#rate-limits)）。不会预扣费用，也不会转发请求。 |
| `409` | `conflict` | `idempotency_key_replayed`, `idempotency_key_reused`, `idempotency_key_in_use` |  | 见[重试与幂等](#idempotency)。 |
| `503` | `upstream_error` | `all_venues_failed` |  | 没有健康的服务商，或所有服务商均失败。不计费。 |
| `503` | `upstream_error` | `upstream_error` |  | 服务商已接受请求，但其回答在第一个 token 之前中断。按预扣金额计费（见[流式输出](#streaming)）。 |
| `503` | `upstream_error` | `timeout` |  | 服务商已接受请求，但未在时限内完成。按预扣金额计费（见[流式输出](#streaming)）。 |
| `401`, `403`, `500` |  |  |  | 见[身份验证](#authentication)。 |

## 图像 {#images}

`POST /v1/images/generations`

`POST /v1/images/edits`

两者都沿用 OpenAI 的 Images API，请求体为 JSON。`/v1/images/edits` 接受 OpenAI 的 JSON 形式：图片是 `images`，即 1 到 5 个 https URL。OpenAI SDK 的 `images.edit` 会以 `multipart/form-data` 发送图片文件，这同样可行：Hyperouter 的边缘节点会将每个文件（PNG、JPEG 或 WebP，每个 20 MiB，每次请求 50 MiB）保存 3 天，对应一个服务商可以获取、无法猜测的 `https://api.hyperouter.app/u/...` URL，然后按 JSON 运行该请求。视频文件会被拒绝（`400 invalid_video`）：请以 https URL 发送视频。两者都支持下列通用功能，以及作为顶层字段传入的任意[模型专属参数](#parameters)。

### 参数

| 名称 | 类型 | 必填 | 允许的值 | 默认值 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `model` | string | 是 | 图像模型 id |  | 要使用的模型。 |
| `prompt` | string | Generations：是。Edits：视模型而定 | 非空白文本 |  | 要生成的内容。 |
| `images` | object[] | Edits：是 | 1 到 5 个对象 `{"image_url": "https://..."}`，数量不超过模型可接受的上限。每个 URL 都是指向公共主机的 https 地址，不能是 `data:` URL、IP 地址或内部名称。不接受 `file_id`。 |  | 要编辑的图片。每个 URL 都会原样传给服务商，因此服务商必须能够获取它；服务商无法获取或读取的 URL 会使任务以 `vendor_rejected` 失败，且不收取任何费用。如果模型要求按固定顺序传入图片，会在模型参考的说明中注明。 |
| `n` | integer | 否 | 1 到 10，且不超过模型的上限 | `1` | 图像数量。 |
| `size` | string | 否 | `WIDTHxHEIGHT`，例如 `1024x1024`；模型可能只允许部分尺寸 | `1024x1024` | 输出尺寸。 |
| `quality` | string | 否 | 视模型而定 |  | 传给模型。 |
| `response_format` | string | 否 | `url` | `url` | 图像的返回方式：始终为 URL。`b64_json` 会以 `400 unsupported_parameter` 拒绝。 |
| `seed` | integer | 否 | 模型列出 `seed` 时可用 |  | 用于得到可复现输出的种子。 |
| `negative_prompt` | string | 否 | 模型列出该字段时可用 |  | 需要避免的内容。 |
| `prompt_extend` | boolean | 否 | 模型列出该字段时可用 | 除非你开启，否则为关闭 | 让模型扩写提示词。 |
| `prompt_expand` | boolean | 否 | 模型列出该字段时可用 | `false` | 扩展字段。Hyperouter 会在模型生成前为它改写提示词。参见[提示词扩写](#prompt-expansion)。 |
| `prompt_expand_model` | string | 否 | 你的账户可调用的聊天模型 slug | `x-ai/grok-4.6` | 扩展字段。配合 `prompt_expand` 使用：负责改写的模型。没有 `prompt_expand: true` 时为 `400 invalid_body`。参见[提示词扩写](#prompt-expansion)。 |
| `locale` | string | 否 | BCP 47 语言标签，例如 `zh-CN` | 英语 | 扩展字段。配合 `prompt_expand` 使用：视频台词所用的语言（前提是模型会说该语言）。 |
| `ratio` | string | 否 | 模型列出该字段时可用 |  | 宽高比。 |
| `resolution` | string | 否 | `480p`, `720p`, `1080p`, `2K`, `4K`，视模型而定 |  | 输出分辨率。 |
| `models` | string[] | 否 | 图像模型 id |  | 新增。回退模型。 |
| `provider` | object | 否 | `only`, `ignore`, `order`（服务商名称数组） |  | 新增。路由偏好。 |
| `moderation` | string | 否 | `auto`, `low` | `auto` | 新增。见[内容审核](#moderation)。 |
| 模型专属字段 | 按声明 | 按声明 | 按声明 |  | 见[模型专属参数](#parameters)。 |

模型未列出的通用功能，例如在不支持 `seed` 的模型上使用 `seed`，会被拒绝并返回 `400 unsupported_parameter`。这类参数绝不会被悄悄丢弃，因为那会改变输出和价格。

### 响应

```json
{
  "created": 1730000000,
  "data": [{ "url": "https://..." }],
  "usage": { "cost": 0.02 },
  "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21"
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `created` | integer | 请求的 Unix 时间。 |
| `data[].url` | string | 使用 `response_format: "url"` 时：签名链接，有效期 24 小时。`GET /v1/generations/{id}` 会签发新的链接。 |
| `usage.cost` | number | 费用，单位美元，JSON 数字。 |
| `id` | string | 请求 id。可配合 [GET /v1/generations/{id}](#generations) 使用。 |
| `expanded_prompt` | string \| null | 扩展字段。配合 `prompt_expand` 使用：实际用于生成的提示词。未扩写时为 `null`。 |

Hyperouter 会将每个结果保存 30 天，因此链接从不指向模型厂商。30 天后记录仍会保留，但其 `outputs` 为空。

### 等待结果

- 对 `response_modes` 包含 `sync` 的模型，请求最多会等待图像 90 秒，并返回真实状态：带图像的 `200`，或错误。参数校验、余额和容量方面的错误会先出现，并带有各自的状态码。
- 90 秒后图像仍未就绪时，会返回 `503`，code 为 `timeout`，并带有响应头 `x-should-retry: false`，这样 OpenAI SDK 不会重试并启动第二张图像。任务会继续运行，错误中以 `generation_id` 携带其 id：请轮询 [GET /v1/generations/{id}](#generations) 获取结果。只有成功时才会计费。如需自行安全地重试，请发送 [Idempotency-Key](#idempotency)：使用相同键的重试会等待同一个任务。
- `response_modes` 仅为 `async` 的模型需要 `Prefer: respond-async`。缺少时，响应为 `400`，code 为 `async_required`。
- 对任何列出 `async` 的模型，如要避免长时间占用连接，请发送 `Prefer: respond-async`（RFC 7240）。该请求头可以重复出现，也可以携带其他偏好，例如 `Prefer: wait=10, respond-async`。你会立即收到 `202`，响应头为 `Preference-Applied: respond-async`：

  ```json
  { "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21", "status": "queued" }
  ```

  请轮询 [GET /v1/generations/{id}](#generations)，或接收 `image.completed` 或 `image.failed` [Webhook](#webhooks)。图像的 Webhook 仅对带有该请求头发送的任务触发。

### 示例

```bash
curl https://api.hyperouter.app/v1/images/generations \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "x-ai/grok-imagine-image", "prompt": "A lighthouse at dusk", "n": 1}'
```

```bash
curl https://api.hyperouter.app/v1/images/edits \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "x-ai/grok-imagine-image", "prompt": "make it night",
       "images": [{"image_url": "https://example.com/photo.png"}]}'
```

### 错误

| 状态码 | code | param | 触发条件 |
| --- | --- | --- | --- |
| `400` | `unsupported_content_type` |  | 请求体是 `multipart/form-data`：`Send a JSON body; pictures and videos are https URLs.` |
| `400` | `invalid_body` | 对应字段 | 请求体不是有效的 JSON；`images` 不是带有 `image_url` 的对象数组；generations 缺少 `prompt`；`n` 小于 1；`response_format` 不是 `url`（`response_format must be url.`；`b64_json` 返回 `unsupported_parameter`）；`resolution` 不被允许；带类型的字段类型错误；`moderation` 不是 `auto` 或 `low`。 |
| `400` | `unknown_model` | `model` | 该模型在图像接口中不存在，或没有服务商符合你的 `provider` 偏好。 |
| `400` | `invalid_size` | `size` | `size` 的格式不像 `1024x1024`，或模型不允许该尺寸。 |
| `400` | `too_many_images` | `n` 或 `images` | `n` 超过 10 或超过模型的上限；图片超过 5 张；图片数超出模型可接受的数量。 |
| `400` | `image_required` | `images` | 编辑请求的图片少于模型所需，或你对只支持编辑的模型调用了 generations（请使用 `/v1/images/edits`）。 |
| `400` | `unsupported_operation` | `images` | 该模型不支持编辑图片。 |
| `400` | `unsupported_parameter` | 对应字段 | 模型不支持该字段；`images[i].file_id`。 |
| `400` | `invalid_combination` | 对应字段 | 模型厂商不允许这些字段同时使用。 |
| `400` | `async_required` |  | 该模型仅支持异步应答：请发送 `Prefer: respond-async`。 |
| `400` | `unsupported_parameter` | `stream` | 对 `response_modes` 不含 `stream` 的模型设置了 `"stream": true`。 |
| `400` | `invalid_image` | `images[i].image_url` | URL 不是指向公共主机的 https 地址：对于 `data:` 或 `http://` URL，消息为 `images[i].image_url must be an https URL.` |
| `400` | `content_rejected` |  | 模型厂商的安全过滤器拒绝了输入：`The request was rejected by a content safety filter.` |
| `400` | `vendor_rejected` |  | `The request was refused by the model. Check its parameters and inputs.` |
| `400` | `invalid_idempotency_key` |  | 见[重试与幂等](#idempotency)。 |
| `402` | `insufficient_credits` |  | 余额或密钥额度上限不足以覆盖该请求可能产生的最高费用。 |
| `409` | `idempotency_key_reused`, `idempotency_key_in_use` |  | 见[重试与幂等](#idempotency)。 |
| `429` | `rate_limit_error` |  | 所有服务商均已满载（无 `code`），或你的账户超出了每分钟请求数或并发请求数（`code: rate_limited`，见[速率限制](#rate-limits)）。 |
| `503` | `upstream_error` |  | `The model failed to produce a result. You were not charged.` |
| `503` | `provider_busy` |  | 服务商约两分钟内一直满载，未接收任务。请稍后重试。未扣费。 |
| `500` | `server_error`, `no_price` |  | Hyperouter 自身出错，或该模型当前无法定价。图像生成后出现的 `500` 会带有 `x-should-retry: false`。 |
| `503` | `timeout` |  | 图像未在 90 秒内完成。任务仍在生成：`error.generation_id` 是用于轮询的 id。带有 `x-should-retry: false`。 |

失败任务的 message 末尾会在 `Provider:` 之后附上服务商给出的原因（如有），以便区分提示词被拒、服务商繁忙和服务故障。其中的 URL 会替换为 `<url>`。

### 图像模型

<!-- BEGIN GENERATED models-image: sitemd writes the ids and prices from models.json; write each model's Does cell. Run cd tools && go run ./sitemd -->
| 模型 | 功能 | 价格 |
| --- | --- | --- |
| `x-ai/grok-imagine-image` | 生成和编辑。最多 10 张图像，最多 5 张输入图片。 | $0.02 每张 |
| `x-ai/grok-imagine-image-2.0` | 生成和编辑，同上。 | $0.04 起 每张 |
| `qwen/qwen-image-2.0` | 生成和编辑（1 到 3 张输入图片）。`n` 为 1 到 6。 | $0.035 每张 |
| `bytedance/seedream-5.0-flash` | 生成和编辑（1 到 10 张输入图片）。每次请求生成一张 2K 图片，无水印。 | $0.018 每张 |
| `bytedance/seedream-5.0-lite` | 生成和编辑，同上。 | $0.035 每张 |
<!-- END GENERATED models-image -->

部分模型需要为你的账户开通权限。控制台中的[模型参考](https://dash.hyperouter.app/docs/models)列出了你的账户可调用的所有模型，以及其参数、价格和说明。

## 视频 {#videos}

视频沿用 OpenAI 的 Videos API。视频是一个任务。创建、编辑、延长或 remix 调用会立即返回 `200`，并带有状态为 `queued` 的 Video 对象。你需要轮询 `GET /v1/videos/{id}` 直到状态变为 `completed`，或接收 [Webhook](#webhooks)。`Prefer` 在此不起作用：视频始终是异步的。

| 接口 | 功能 |
| --- | --- |
| `POST /v1/videos` | 根据提示词创建视频，可附带 `input_reference`。 |
| `POST /v1/videos/edits` | 编辑或放大已完成的视频。仅限在 `operations` 中列出 `edit` 的模型。 |
| `POST /v1/videos/extensions` | 延长已完成的视频。仅限列出 `extend` 的模型。 |
| `POST /v1/videos/{id}/remix` | 对已完成的视频使用新提示词，模型不变。仅限列出 `remix` 的模型。 |
| `GET /v1/videos` | 列出你的视频。 |
| `GET /v1/videos/{id}` | Video 对象。 |
| `GET /v1/videos/{id}/content` | MP4 文件或缩略图。 |
| `DELETE /v1/videos/{id}` | 删除视频。 |

### 创建视频

`POST /v1/videos`

所有视频接口的请求体都是 JSON；OpenAI SDK 的 `videos.create` 附带 `input_reference` 图片文件的形式同样被接受，文件的处理方式与[图像编辑](#images)相同。每张图片和每个视频都是指向公共主机的 https URL，并原样传给服务商：服务商必须能够获取它，服务商无法获取或读取的 URL 会使视频以 `vendor_rejected` 失败，且不收取任何费用。`data:` URL、`http://` URL、IP 地址或内部名称会被拒绝，返回 `400 invalid_image` 或 `400 invalid_video`。`multipart/form-data` 请求体会被拒绝，返回 `400 unsupported_content_type`。

| 名称 | 类型 | 必填 | 允许的值 | 默认值 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `model` | string | 是 | 视频模型 id |  | 要使用的模型。 |
| `prompt` | string | 是 | 非空白文本 |  | 要生成的内容。 |
| `seconds` | string \| integer | 否 | 视模型而定 | 模型的第一个允许值，否则为 4 秒（若模型最大值更小，则取模型最大值） | 视频时长。`"8"` 与 `8` 相同。 |
| `size` | string | 否 | `WIDTHxHEIGHT` |  | 除非你发送 `resolution`，否则由高度决定分辨率：不超过 480 为 `480p`，不超过 720 为 `720p`，不超过 1080 为 `1080p`，不超过 1440 为 `2K`，更高为 `4K`。模型必须允许该分辨率。 |
| `input_reference` | object | 模型需要图片时 | `{"image_url": "https://..."}`，一个 https URL |  | 视频的第一张图片。不接受 `file_id`。 |
| `resolution` | string | 否 | `480p`, `720p`, `1080p`, `2K`, `4K`，视模型而定 | 模型的第一个分辨率 | 输出分辨率。会影响价格。 |
| `ratio` | string | 否 | 模型列出该字段时可用 |  | 宽高比。 |
| `audio` | boolean | 否 | 模型能生成声音时可用 | `false` | 生成声音。 |
| `seed` | integer | 否 | 模型列出该字段时可用 |  | 用于得到可复现输出的种子。 |
| `negative_prompt` | string | 否 | 模型列出该字段时可用 |  | 需要避免的内容。 |
| `prompt_extend` | boolean | 否 | 模型列出该字段时可用 | 除非你开启，否则为关闭 | 让模型扩写提示词。 |
| `prompt_expand`, `locale` | boolean, string | 否 | 同[图像](#images) | `false` | 扩展字段。参见[提示词扩写](#prompt-expansion)。 |
| `prompt_expand_model` | string | 否 | 同[图像](#images) | `x-ai/grok-4.6` | 扩展字段。配合 `prompt_expand` 使用：负责改写的模型。参见[提示词扩写](#prompt-expansion)。 |
| `first_frame`, `last_frame` | string | 否 | 图片的 https URL |  | 关键帧。 |
| `reference_images`, `reference_videos` | string[] | 否 | https URL |  | 参考媒体。依模型厂商的设定，它们不能与关键帧同时使用。 |
| `models`, `provider` | string[], object | 否 | 同[图像](#images) |  | 新增。回退模型和路由偏好。 |
| `moderation` | string | 否 | `auto`, `low` | `auto` | 新增。见[内容审核](#moderation)。 |
| 模型专属字段 | 按声明 | 按声明 | 按声明 |  | 见[模型专属参数](#parameters)。 |

### 编辑、延长与 remix

| 接口 | 请求体（JSON） |
| --- | --- |
| `POST /v1/videos/edits` | `model`、`video`（必填）、`prompt`、`resolution` 以及通用功能。`video` 为 `{"id": "<your video id>"}`（你的某个已完成视频）或 `{"url": "https://..."}`。传 id 时，`model` 默认为源视频的模型。 |
| `POST /v1/videos/extensions` | `model`、`video`（必填）、`prompt`、`seconds`。新增的秒数遵循与创建相同的规则。 |
| `POST /v1/videos/{id}/remix` | `prompt`（必填）。模型为源视频的模型。 |

源视频必须已经完成。以 URL 提供的视频是一个 https URL，与图片一样原样传给服务商。如果以 URL 提供视频，对没有固定最大时长的模型，需要提供 `seconds`。

### 列出、查询、下载、删除

| 接口 | 参数 | 响应 |
| --- | --- | --- |
| `GET /v1/videos` | 查询参数：`after`（视频 id）、`limit`（1 到 100，默认 20）、`order`（默认 `desc`，或 `asc`） | `{"object":"list","data":[Video],"first_id","last_id","has_more"}`。已超过 `expires_at` 的视频不会列出。 |
| `GET /v1/videos/{id}` |  | Video 对象。 |
| `GET /v1/videos/{id}/content` | 查询参数：`variant`（默认 `video`，或 `thumbnail`） | `302 Found`，指向字节内容（`video/mp4`，或缩略图的类型）的签名链接，有效期 15 分钟。HTTP 客户端和 OpenAI SDK 会跟随它。完成前或没有缩略图时返回 `404 not_found`。 |
| `DELETE /v1/videos/{id}` |  | `{"id","object":"video.deleted","deleted":true}`。任务运行期间返回 `409 video_not_finished`。已删除的视频返回 `404`。 |

### Video 对象

```json
{
  "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
  "object": "video",
  "model": "x-ai/grok-imagine-video",
  "status": "completed",
  "progress": 100,
  "prompt": null,
  "seconds": "8",
  "size": "",
  "created_at": 1730000000,
  "completed_at": 1730000137,
  "expires_at": 1732592000,
  "error": null,
  "remixed_from_video_id": null,
  "usage": { "cost": 0.4, "seconds": 8 }
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `status` | string | `queued`、`in_progress`、`completed` 或 `failed`。 |
| `progress` | integer | 0 到 100。 |
| `prompt` | string \| null | 提示词仅在任务运行期间返回。任务完成后的对象返回 `null`。 |
| `seconds` | string | 视频时长，以字符串表示，与 OpenAI 一致。 |
| `size` | string | 你发送的 `size`（如有）。 |
| `expires_at` | integer | Unix 时间：`created_at` 加 30 天。到期后，`GET /v1/videos/{id}` 和 `/content` 返回 `404 not_found`，该视频也不再出现在列表中。请在此之前下载你想保留的内容。 |
| `error` | object \| null | 任务失败时为 `{"code", "message"}`，例如 `content_rejected`。 |
| `remixed_from_video_id` | string \| null | 编辑、延长或 remix 的源视频。 |
| `usage` | object \| null | 任务结算后设置：`cost`（美元，JSON 数字）和 `seconds`（整数）。 |
| `expanded_prompt` | string \| null | 扩展字段。配合 `prompt_expand` 使用：任务提交后实际用于生成的提示词。保留 30 天，之后为 `null`。 |

视频按你请求的秒数计费。该金额会预先预扣，任务失败时全额释放。

### 示例：x-ai/grok-imagine-video

模型 `x-ai/grok-imagine-video` 根据提示词生成视频，可选择一张图片作为起始画面。`seconds` 为 1 到 15。价格：每秒 $0.050。

```bash
curl https://api.hyperouter.app/v1/videos \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "x-ai/grok-imagine-video",
    "prompt": "She turns to the camera and smiles",
    "input_reference": { "image_url": "https://example.com/portrait.png" },
    "seconds": 8
  }'
```

```json
{
  "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
  "object": "video",
  "model": "x-ai/grok-imagine-video",
  "status": "queued",
  "progress": 0,
  "prompt": "She turns to the camera and smiles",
  "seconds": "8",
  "size": "",
  "created_at": 1730000000,
  "completed_at": null,
  "expires_at": 1732592000,
  "error": null,
  "remixed_from_video_id": null,
  "usage": null
}
```

该任务收费 8 × $0.050 = $0.40，因此结算后的对象显示 `"usage": {"cost": 0.4, "seconds": 8}`。

### 错误

| 状态码 | code | param | 触发条件 |
| --- | --- | --- | --- |
| `400` | `unsupported_content_type` |  | 请求体是 `multipart/form-data`：`Send a JSON body; pictures and videos are https URLs.` |
| `400` | `invalid_body` | 对应字段 | 请求体不是有效的 JSON；`prompt` 为空白；`video` 不是带有 `id` 或 `url` 的对象；`input_reference` 不是带有 `image_url` 的对象；`limit`、`after` 或 `variant` 无效；带类型的字段类型错误；`resolution` 不被允许；`moderation` 不是 `auto` 或 `low`。 |
| `400` | `unknown_model` | `model` | 该模型在视频接口中不存在。 |
| `400` | `invalid_seconds` | `seconds` | 模型不允许该 `seconds`（message 会列出允许的值），或以 URL 提供视频时需要该字段。 |
| `400` | `invalid_size` | `size` | `size` 的格式不像 `1280x720`。 |
| `400` | `unsupported_parameter` | 对应字段 | 模型不支持该字段；该分辨率不可用（`resolution` 或 `size`）；对不带声音的模型设置了 `audio`；`input_reference.file_id`。 |
| `400` | `unsupported_operation` | `model` | 模型未列出该操作（编辑、延长或 remix）。 |
| `400` | `invalid_combination` | 对应字段 | 参考媒体与关键帧同时使用，依模型厂商的设定不被允许。 |
| `400` | `image_required` | `input_reference` | `This model needs an input_reference picture.` |
| `400` | `video_not_ready` | `video` | 源视频尚未完成。 |
| `400` | `invalid_image`, `invalid_video` | 对应字段 | 图片 URL（`invalid_image`）或视频 URL（`invalid_video`：`reference_videos[i]`、`video.url`）不是指向公共主机的 https 地址，例如 `data:` 或 `http://` URL：`<field> must be an https URL.` `param` 为对应字段，例如 `input_reference.image_url`、`first_frame` 或 `reference_images[1]`。URL 会原样传给服务商：服务商无法获取或读取的 URL 会使视频以 `vendor_rejected` 失败，且不收取任何费用。 |
| `400` | `clip_too_long` |  | 参考视频片段加上请求的 `seconds` 超出了模型的上限：`The reference clip plus the requested seconds run past the model's limit of 30 s. Send a shorter clip or fewer seconds. You were not charged.` 它显示在 Video 对象的 `error.code` 中。 |
| `400` | `content_rejected`, `vendor_rejected` |  | 任务在模型厂商端失败。它显示在 Video 对象的 `error.code` 中。 |
| `402` | `insufficient_credits` |  | 余额或密钥额度上限不足以覆盖预扣金额。 |
| `404` | `not_found` |  | 视频不存在、不属于你、已被删除或已超过 `expires_at`；或内容尚未就绪。 |
| `409` | `video_not_finished` |  | 你删除了仍在生成中的视频。 |
| `409` | `idempotency_key_reused`, `idempotency_key_in_use` |  | 见[重试与幂等](#idempotency)。 |
| `429`, `503`, `500` |  |  | 与图像相同。视频创建之后出现的 `500` 会带有 `x-should-retry: false`。 |

### 视频模型

<!-- BEGIN GENERATED models-video: sitemd writes the ids and prices from models.json; write each model's Notes cell. Run cd tools && go run ./sitemd -->
| 模型 | 每秒视频价格 | 说明 |
| --- | --- | --- |
| `x-ai/grok-imagine-video` | $0.050 起 | 文本、图片或视频输入。最长 15 秒。支持 `edit`。 |
| `x-ai/grok-imagine-video-1.5` | $0.080 起 | 文本、图片或参考媒体输入。最长 15 秒。 |
| `x-ai/grok-imagine-video-1.5-lite` | $0.020 起 | 同上，体积更小、价格更低。 |
| `bytedance/seedance-2.0` | $0.0431892 起 | 文本、首尾帧或参考图片输入，可选音频。4 到 15 秒。480p、720p、1080p 或 4K；所列为 480p 的价格。 |
| `bytedance/seedance-2.0-fast` | $0.0331452 起 | 文本、首尾帧或参考图片输入，可选音频。4 到 15 秒。480p 或 720p；所列为 480p 的价格。 |
| `bytedance/seedance-2.0-mini` | $0.0210924 起 | 文本、首尾帧或参考图片输入，可选音频。4 到 15 秒。480p 或 720p；所列为 480p 的价格。 |
| `bytedance/seedance-2.5` | $0.0642816 起 | 文本、首尾帧或参考图片输入，可选音频。4 到 15 秒。480p、720p 或 1080p；所列为 480p 的价格。 |
| `lumina/berry-1.0` | $0.050 起 | 文本、图片或参考媒体输入，可选音频。最长 30 秒。480p、720p 或 1080p；所列为 480p 的价格。 |
| `minimax/minimax-h3` | $0.080 起 | 文本、首尾帧或参考图片输入，无音频。4 到 15 秒，768p 或 2K。 |
| `alibaba/wan3.0` | $0.050 起 | 文本、图片或参考媒体输入，可选音频。最长 30 秒。480p、720p 或 1080p；所列为 480p 的价格。 |
<!-- END GENERATED models-video -->

控制台中的[模型参考](https://dash.hyperouter.app/docs/models)列出了你的账户可调用的所有视频模型。

## 生成记录 {#generations}

`GET /v1/generations/{id}`

返回你的某个请求的记录，任何类型均可：包括状态、用量、扣费、耗时，对于图像和视频还包括输出的签名链接。可用它来轮询以 `Prefer: respond-async` 发送的图像请求，并核对支出。记录中从不包含提示词和补全文本。Hyperouter 仅为满足法律义务将其加密保存 180 天，任何 API 或控制台页面都不会返回它们（[隐私政策](privacy.md#p3)）。

### 参数

| 名称 | 位置 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- | --- |
| `id` | path | string (UUID) | 是 | 聊天补全、图像响应或 Video 对象的 `id`。 |

### 响应

```json
{
  "data": {
    "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
    "kind": "chat",
    "model": "x-ai/grok-4.7",
    "provider_name": "xAI",
    "status": "done",
    "created_at": "2026-10-24T08:12:00Z",
    "finished_at": "2026-10-24T08:12:02Z",
    "usage": {
      "input_tokens": 120, "output_tokens": 300, "cache_read_tokens": 0,
      "image": 0, "video_seconds": 0, "cost": 0.00204
    },
    "usage_estimated": false,
    "ttft_ms": 320,
    "latency_ms": 2100,
    "error": null,
    "outputs": []
  }
}
```

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `kind` | string | `chat`、`image` 或 `video`。 |
| `provider_name` | string \| null | 处理已完成聊天请求的服务商。图像和视频为 `null`。 |
| `status` | string | `queued`、`submitting`、`running`、`done` 或 `failed`。 |
| `created_at`, `finished_at` | string \| null | RFC 3339 UTC 时间。请求结束前 `finished_at` 为 `null`。 |
| `usage` | object | `input_tokens`、`output_tokens`、`cache_read_tokens`、`image`、`video_seconds` 和 `cost`。`cost` 为费用，单位美元，JSON 数字。请求完成前各项计数为 `0`。 |
| `usage_estimated` | boolean | 服务商未返回 token 数而由 Hyperouter 自行统计时为 `true`。 |
| `ttft_ms`, `latency_ms` | integer \| null | 首 token 耗时和总耗时，单位为毫秒。 |
| `error` | object \| null | 请求失败时为 `{"code", "message"}`。 |
| `outputs` | object[] | 对图像和视频：`[{"url", "expires_at"}]`，签名链接，有效期 24 小时。请求后 30 天内可用；之后 `outputs` 为空，记录仍保留。聊天始终为空。 |
| `expanded_prompt` | string \| null | 对使用 `prompt_expand` 发送的图像和视频：实际用于生成的提示词。请求后保留 30 天，之后为 `null`。 |

```bash
curl https://api.hyperouter.app/v1/generations/0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21 \
  -H "Authorization: Bearer $HYPEROUTER_API_KEY"
```

### 错误

| 状态码 | type | code | param | 触发条件 |
| --- | --- | --- | --- | --- |
| `404` | `not_found` | `not_found` | `id` | `No generation with that id.` id 不是 UUID、不存在、属于其他账户，或已被删除。 |
| `500` | `server_error` | `server_error` |  | Hyperouter 无法读取或签发该记录。 |
| `401`, `403` |  |  | 见[身份验证](#authentication)。 |

<!-- toc: 概念 -->
## 模型专属参数 {#parameters}

部分模型拥有其他模型没有的字段，称为*额外参数*。你可以像其他字段一样，将它们作为请求体的顶层字段发送。所有 OpenAI SDK 都可以发送它们（Python 中用 `extra_body`，JavaScript 中用额外属性）。

`GET /v1/models` 在 `extra_parameters` 中列出每个模型的额外参数。每一项包含：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `type` | string | `string`、`integer`、`number`、`boolean`、`array`、`object` 之一。 |
| `values` | array | 允许的取值。为空表示该类型的任意值。 |
| `price_condition` | boolean | 该字段会改变价格时为 `true`。 |
| `description` | string | 该字段的作用。 |

控制台中的[模型参考](https://dash.hyperouter.app/docs/models)介绍了你的账户可调用的每个模型的额外参数。

### 规则

- 已知参数但该模型不具备时会被拒绝：返回 `400 invalid_request_error`，code 为 `unsupported_parameter`，`param` 设为字段名（例如 `loras`），message 为 `This model does not support "loras".`。只要目录中有某个模型声明了该参数，它就是已知参数。同一规则也适用于通用功能（`resolution`、`ratio`、`audio`、`seed`、`negative_prompt`、`first_frame`、`last_frame`、`reference_images`、`reference_videos`、`prompt_extend`）。不会悄悄丢弃任何参数，因为那会改变输出和价格。
- 类型错误的值会被拒绝并返回 `400 invalid_body`，`param` 设为该名称，message 形如 `loras must be of type array.`。
- 超出 `values` 的值会被拒绝并返回 `400 invalid_body`，message 为 `<name> must be one of [...]`。
- 没有任何模型声明的字段会被忽略，与 OpenAI 的 API 忽略未知字段的做法一致。
- 每个模型都按自己的 schema 校验参数：允许的取值、最小值和最大值、必填字段以及列表长度。超出范围的值返回 `400 invalid_body`，`param` 指明字段，例如 `seconds must be one of 5, 8.`
- 模型厂商不允许的组合，例如参考媒体与关键帧同时使用，会返回 `400 invalid_combination` 并附上原因。这些检查在任何扣费之前执行。
- 会改变价格的字段，例如 `resolution` 和 `audio`，已计入预先预扣的金额，因此预扣金额是精确的。

### 通用功能

这些字段在所有具备它们的模型上名称相同。模型在 `supported_parameters` 中列出其接受的字段。

| 字段 | 含义 |
| --- | --- |
| `resolution` | `480p`、`720p`、`1080p`、`2K` 或 `4K`，视模型而定。 |
| `ratio`, `seed`, `negative_prompt`, `prompt_extend`, `audio` | 见字段名。除非你开启，否则 `audio` 和 `prompt_extend` 为关闭。 |
| `first_frame`, `last_frame` | 视频的关键帧。 |
| `reference_images`, `reference_videos` | 视频和图像编辑的参考媒体。 |

### 提示词扩写 {#prompt-expansion}

设置 `"prompt_expand": true` 后，Hyperouter 会在模型生成前为它改写你的提示词：图像得到更完整的描述，视频得到逐秒的脚本。该功能默认关闭，提示词按原样发送。只有 `supported_parameters` 中列出 `prompt_expand` 的模型才接受它，而且只能用于创建图像或视频；用在其他模型上，或用于视频的编辑、延长、重混时，会以 `400 unsupported_parameter` 拒绝；它也不能与 `prompt_extend: true` 同时使用（`400 invalid_body`）。

提示词扩写需由 Hyperouter 为账户开通后才能使用，请提交支持工单申请。开通前，`GET /v1/models` 不会为任何模型列出 `prompt_expand`；在提供该功能的模型上发送 `prompt_expand: true` 会返回 `403 permission_error`，code 为 `feature_not_enabled`，`param` 为 `prompt_expand`，不会预扣费用，也不会发送给服务商。

- **实际生成的内容。** 图像响应、视频对象和 `GET /v1/generations/{id}` 都带有 `expanded_prompt`，即模型实际收到的提示词。它在请求后保留 30 天，之后返回 `null`。`prompt` 仍是你自己的原文。
- **改写模型。** `prompt_expand_model` 指定负责改写的聊天模型，默认 `x-ai/grok-4.6`。它只在 `prompt_expand: true` 时有效（否则 `400 invalid_body`）。不存在或不是聊天模型的模型返回 `400 unknown_model`，你的账户无法调用的模型返回 `403 model_not_enabled`，两者都发生在冻结任何费用之前。能读取图像的模型会看到请求中的图片；不能读取图像的模型只根据文本改写。
- **价格。** 改写在同一个请求上计费，按它实际用掉的 token、以改写模型（`prompt_expand_model`，缺省为 `x-ai/grok-4.6`）的 token 价格计算；它可能产生的最高费用会和生成费用一起预先冻结。各模型的详情见模型参考。
- **不执行的情况。** 改写失败、超时或无法使用时，按你发送的原始提示词生成，返回 `expanded_prompt: null`，不收费。
- **语言。** 视频台词遵循 `locale`（未设置时为英语），前提是模型会说该语言。

#### 以聊天模型调用改写 {#prompt-expansion-model}

开通了提示词扩写的账户还会获得一个聊天模型，它返回改写结果而不进行生成；你的[模型参考](#models)中列出了它的名称。在 `POST /v1/chat/completions` 上调用它，且只发送一条 `user` 消息：其中的文本是提示词，其 `image_url` 部分（https URL，最多 5 个）是图片；`data:` 或 `http://` URL 返回 `400 invalid_image`，`param` 为 `messages`。`target_model` 为必填项，须是列出 `prompt_expand` 的模型。`seconds`、`locale` 和 `negative_prompt` 为可选项。带图片的视频目标会以该图片作为首帧来编写。它不支持流式输出（`stream: true` 返回 `400 unsupported_parameter`），任何其他消息（包括 system 消息）都返回 `400 invalid_body`。

这个聊天模型始终使用 `x-ai/grok-4.6`，不接受 `prompt_expand_model`。`choices[0].message.content` 是一个 JSON 字符串：`{"prompt": "...", "negative_prompt": "..."}`，视频目标另含 `"beats"`（每秒一行）。按 `x-ai/grok-4.6` 的 token 价格计费，费用见 `usage`。要求模型输出其指令的提示词返回 `400 prompt_rejected`；改写结果被拒绝或为空时返回 `422 expansion_refused`，改写失败时返回 `503 upstream_error`。以上情况均不收费。

## 内容审核 {#moderation}

`moderation` 字段沿用 OpenAI 的定义。它适用于 `/v1/chat/completions`、`/v1/images/generations`、`/v1/images/edits` 以及 `/v1/videos` 及其编辑、延长和 remix 调用。

| 值 | 含义 |
| --- | --- |
| `auto`（默认） | 使用模型厂商自带的审核。Hyperouter 不额外发送任何内容。 |
| `low` | 对服务商提供关闭其审核选项的模型，Hyperouter 会发送该选项。对其他模型，`low` 会被忽略且不报错，与 OpenAI 的做法一致。每个模型是否提供该选项，见你的[模型参考](https://dash.hyperouter.app/docs/models)中该模型的条目。请在请求体中发送 `moderation`：服务商自己的审核请求头或字段在这些接口上不会被转发。 |

其他任何值都会被拒绝：`400 invalid_request_error`，code 为 `invalid_body`，`param` 为 `moderation`，message 为 `moderation must be auto or low.`

`low` 需要 Hyperouter 为账户启用后才可使用；请提交支持工单申请。在此之前，带有 `low` 的请求会返回 `403 permission_error`，code 为 `moderation_not_enabled`，`param` 为 `moderation`，且不会发送给服务商。

```json
{
  "model": "qwen/qwen-image-2.0",
  "prompt": "...",
  "moderation": "low"
}
```

响应不会说明是否使用了该关闭选项。[服务条款](terms.md)中的政策仍然适用。被模型厂商的过滤器拒绝的请求会以 `400 content_rejected` 失败，且不收费。

## Webhook {#webhooks}

你无需轮询，可以让自己的某个端点在任务结束时接收请求。请在[控制台](https://dash.hyperouter.app/webhooks)中添加端点。其格式沿用 OpenAI 的 Webhook，并采用 Standard Webhooks 方案签名，因此 OpenAI SDK 可以直接校验。

| 事件 | 发送时机 |
| --- | --- |
| `video.completed`, `video.failed` | 视频任务结束。 |
| `image.completed`, `image.failed` | 你以 `Prefer: respond-async` 发送的图像任务结束。 |
| `raw.completed`, `raw.failed` | 原始调用的任务结束（开通了原始调用的账户）：已扣费，或预扣已释放。直接返回结果的原始调用不发送事件。 |

载荷只携带 id，从不包含结果、提示词或费用。请使用你的 API 密钥获取对象：`data.id` 就是 [GET /v1/videos/{id}](#videos) 和 [GET /v1/generations/{id}](#generations) 所接受的 id。对于原始任务，它是创建请求返回的 `X-Generation-Id`。

```json
{
  "id": "evt_0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21",
  "object": "event",
  "type": "video.completed",
  "created_at": 1761300000,
  "data": { "id": "0194f2c4-7a1e-7b3c-9d02-5f6a1c0e8b21" }
}
```

### 请求头与校验

每次投递都是一个 `POST` 请求，带有 `content-type: application/json` 以及以下请求头：

- `webhook-id`：事件 id。每次重试都相同，可用它去重。
- `webhook-timestamp`：Unix 秒。
- `webhook-signature`：`v1,` 加上 `id.timestamp.body` 的 base64 HMAC-SHA256，以该端点的密钥作为 key。

签名密钥以 `whsec_` 开头。它在你创建端点和轮换密钥时仅显示一次。请在解析之前，对原始请求体进行校验：

```js
// Node, with the OpenAI SDK
const event = client.webhooks.unwrap(rawBody, req.headers, process.env.HYPEROUTER_WEBHOOK_SECRET);
if (event.type === "video.completed") {
  const video = await client.videos.retrieve(event.data.id);
}
```

签名校验失败时 `unwrap` 会抛出异常；请对这类请求返回错误状态码。后续调用使用与本 API 其余部分相同的 base URL。

### 端点、重试与限制

- 端点必须是 `https`，端口为 443（或不写端口），且使用主机名而非 IP 地址。该主机必须解析到公共地址；Hyperouter 在连接时会再次检查。不会跟随重定向。
- 一个账户最多有 10 个端点。每个端点可选择自己需要的事件类型。
- 10 秒内返回 `2xx` 即视为成功。其他情况会在约 5 秒、1 分钟、5 分钟、30 分钟、2 小时、5 小时、10 小时和 10 小时后重试，之后该次投递被标记为失败。
- 如果某个端点的所有投递连续 3 天失败，该端点会被停用，控制台会说明原因。修复接收端后请重新启用。
- 控制台会列出每个端点的投递记录，包含状态、尝试次数、最近一次 HTTP 状态码和最近一次错误。它提供“重新发送”（事件 id 不变）和“发送测试事件”，后者会投递一个 `webhook.test` 事件，其 `data.id` 为该端点的 id。

## MCP 服务器 {#mcp}

`POST https://api.hyperouter.app/mcp`

AI 助手可以通过模型上下文协议（MCP）操作你的 Hyperouter 账户。该服务器管理控制台功能：API 密钥、活动记录、额度、工单、Webhook 和模型列表。它不运行模型。模型调用仍通过 API 密钥发往 `/v1`。

该服务器使用 Streamable HTTP 和 JSON-RPC 2.0。支持 MCP 版本 `2025-11-25` 和 `2025-06-18`。它是无状态的：没有会话，`GET /mcp` 返回 `405`。

### 访问令牌

MCP 客户端使用控制台访问令牌进行认证，而不是 API 密钥。

- 在[控制台](https://dash.hyperouter.app/tokens)中创建令牌。为它设置名称、作用域，还可以选择设置过期时间。
- 令牌以 `hr_dt_` 开头，仅显示一次。Hyperouter 只保存其哈希值。
- 一个账户用户最多可持有 25 个未过期且未吊销的令牌。在控制台中吊销令牌即可立即使其失效。
- 令牌不能用于 `/v1`，API 密钥也不能用于 `/mcp`。
- 令牌以创建它的用户的身份行事，拥有该用户的权限。每条消息都会检查权限，因此角色变更在下一次调用时生效。

| 作用域 | 令牌可调用的工具 |
| --- | --- |
| `read` | 只读取数据的工具。 |
| `write` | 该用户有权使用的所有工具。 |

请以 Bearer 令牌的形式发送令牌：

```
Authorization: Bearer hr_dt_...
```

### 协议

| 方法 | 响应 |
| --- | --- |
| `initialize` | 协议版本（若受支持则为客户端的版本，否则为 `2025-11-25`）、`tools` 能力和服务器信息。 |
| `ping` | 空结果。 |
| `tools/list` | 令牌所属用户及作用域允许使用的工具。 |
| `tools/call` | 单个工具的执行结果。 |

通知，或对服务器的响应，会返回无响应体的 `202`。JSON-RPC 批量请求会被拒绝并返回错误 `-32600`。单条消息不得超过 1 MiB。未知的 `MCP-Protocol-Version` 请求头会返回 `400`。浏览器请求必须来自 `https://dash.hyperouter.app`；不发送 `Origin` 请求头的客户端不受影响。

```bash
curl https://api.hyperouter.app/mcp \
  -H "Authorization: Bearer $HYPEROUTER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
```

### 工具

`tools/list` 返回当前的工具集。每个工具对应一个控制台路由，并带有描述其参数的 JSON Schema。这些工具涵盖：

- 账户与密钥：`get_me`、`list_api_keys`、`create_api_key`、`update_api_key`。
- 活动与额度：`list_activity`、`get_activity`、`get_activity_summary`、`get_credits`、`get_topup_fee`。
- 工单：`list_tickets`、`create_ticket`、`get_ticket`、`reply_to_ticket`、`close_ticket`。
- Webhook：`list_webhooks`、`create_webhook`、`update_webhook`、`rotate_webhook_secret`、`delete_webhook`、`list_webhook_deliveries`、`resend_webhook_delivery`、`send_test_webhook`。
- 模型：`list_models`。
- 带有 `admin_` 前缀的工作人员工具，仅对拥有工作人员权限的用户显示。

工具以一个文本内容项作答，其内容是该路由的 JSON 响应体。路由失败时，结果带有 `isError: true`，文本为 `<message> (<code>, HTTP <status>)`。未知的工具，或你的令牌看不到的工具，会返回 JSON-RPC 错误 `-32602`。

### 审批

敏感的写操作（例如为账户入账）不会立即执行。工具不会执行它，而是返回 `status` 为 `approval_required` 的结果，以及控制台上的 `approval_url`。用户打开该链接，通过二次验证并批准该操作。审批在 24 小时后过期。用户也可以拒绝。

<!-- toc: 账户 -->
## 计费与限制 {#billing}

- 请求由预付的美元余额支付，按实际处理该请求的服务商的标价计费，不加价。
- **先预扣，再结算。** 请求运行之前，Hyperouter 会预扣其最高可能产生的费用：聊天为你的输入加 `max_tokens`，图像为请求的数量，视频为请求的秒数。请求结束后，按实际用量扣费，其余预扣金额释放。余额不会变为负数。
- 失败的请求，或失败的图像或视频任务，不收费。失败的回退尝试也不收费。
- 每个响应都以 `usage.cost` 给出其费用，即以美元计的 JSON 数字：聊天、图像、已结算的视频，以及 `GET /v1/generations/{id}` 中均是如此。控制台会显示每个请求，以及按日、按模型和按密钥统计的支出。
- 金额是精确的：货币以十亿分之一美元为单位计数，绝不通过浮点数取整。`GET /v1/models` 中的价格是十进制字符串。
- 目前充值为人工处理。请在[控制台](https://dash.hyperouter.app/credits)中提交充值申请，附上金额、付款凭证编号和付款截图。工作人员核对付款后为你的余额入账，并在同一工单中回复。
- **充值手续费。** 每笔充值收取所付金额 5.5% 的手续费，最低 $0.80，在充值入账时扣除：付款 $100 入账 $94.50，付款 $10 入账 $9.20。当前生效的手续费会在你申请充值之前显示在[额度](https://dash.hyperouter.app/credits)页面上，你的历史记录中的每笔充值也会显示所付金额和手续费。请求本身不收取手续费。

### 速率限制 {#rate-limits}

每个账户都有每分钟请求数和同时进行中的请求数两项限制。两者都将账户下的所有 API 密钥合并计算，并适用于每一个启动工作的请求：聊天补全、图像和视频的创建，以及原始创建请求。读取结果（`GET /v1/generations/{id}`、`GET /v1/videos…`、原始任务轮询）不计入；原始轮询按服务商单独计数，上限与每分钟请求数相同。

你的等级取决于你累计的充值总额（不含充值手续费）：

| 等级 | 累计充值 | 每分钟请求数 | 并发请求数 |
| --- | --- | --- | --- |
| 1 | 低于 $10 | 60 | 10 |
| 2 | $10 或以上 | 300 | 30 |
| 3 | $100 或以上 | 1,200 | 100 |
| 4 | $1,000 或以上 | 6,000 | 300 |

你当前的限制显示在[额度](https://dash.hyperouter.app/credits)页面上。以上为默认值；工作人员可以针对整个平台或单个账户调整，调整在一分钟内生效。

超出任一限制时，请求会在预扣或转发任何内容之前被拒绝，返回 `429`，`type: rate_limit_error`，`code: rate_limited`，以及以秒为单位的 `Retry-After` 响应头。message 会指明你触及的限制。即使请求被拒绝，也会计入当前这一分钟。进行中的请求（包括流式请求）在结束之前一直计数。

为防止密钥被猜测，Hyperouter 按客户端地址统计 API 密钥校验失败次数。一分钟内超过 30 次，该地址的所有 `/v1` 路由将被屏蔽 15 分钟：返回 `429`、`rate_limit_error`、`too_many_auth_failures`，并带有 `Retry-After`。使用有效密钥也无法解除屏蔽。

## 支持 {#support}

如有计费、充值和 API 方面的问题，请在[控制台](https://dash.hyperouter.app/tickets)中提交工单，工作人员会在同一对话中回复。你也可以发邮件至 [account@hyperouter.app](mailto:account@hyperouter.app)。反馈具体请求时，请附上响应中的 `id`。
