<!-- toc: はじめに -->
# Hyperouter API {#introduction}

*バージョン v1 · 2026 年 10 月 25 日更新*

> このドキュメントは、AI アシスタント向けに Markdown でも提供しています。[/llms.txt](https://hyperouter.app/llms.txt) から始めるか、すべてのページを 1 つにまとめた [/llms-full.txt](https://hyperouter.app/llms-full.txt) を取得してください。このページの URL は [/docs.md](https://hyperouter.app/docs.md) です。

Hyperouter は、多数のモデルベンダーの手前に置かれた 1 つの HTTP API です。モデルを指定したリクエストを送ると、Hyperouter がそのモデルを提供できるプロバイダーを選び、リクエストを転送して、そのプロバイダーの定価で残高から課金します。

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

すべてのエンドポイントは、OpenAI のリクエストとレスポンスの形式に従っています。ベース URL と API キーを変更すれば、OpenAI SDK がそのまま動作します。Hyperouter は OpenAI のボディにいくつかのフィールドを追加しており、このリファレンスでは追加分であることを明記しています。

| Endpoint | 用途 | 認証 |
| --- | --- | --- |
| `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`。10 進数の USD 文字列）を返します。 | API キー |

> API キーを作成するには、Google または GitHub で [dash.hyperouter.app にサインイン](https://dash.hyperouter.app)してください。`GET /v1/models` は、リクエスト時点で呼び出せるモデルを返します。

## クイックスタート {#quickstart}

1. [サインイン](https://dash.hyperouter.app)して API キーを作成します。キーは `sk-hr-v1-` で始まり、一度だけ表示されます。
2. 環境変数（たとえば `HYPEROUTER_API_KEY`）に保存します。
3. クレジットを追加します。ダッシュボードでチャージの依頼を作成してください。お支払いの確認後、スタッフが残高に反映します。
4. 任意の OpenAI SDK の接続先を上記のベース 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}

すべてのリクエストで、API キーをベアラートークンとして送信します。

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

キーは残高へのアクセス権を持ちます。サーバー側で管理し、ブラウザーやモバイルのコードには決して含めないでください。Hyperouter が保存するのは各キーのハッシュのみのため、紛失したキーを再表示することはできません。新しいキーを作成してください。

[ダッシュボード](https://dash.hyperouter.app/keys)では、キーに名前を付けたり、クレジット上限を設定したり、無効にしたりできます。無効にしたキーは直ちに使えなくなります。キーの上限を超えることになるリクエストは、`402 insufficient_credits` で拒否されます。

### 認証エラー

| Status | 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` | お客様のアドレスから 1 分間に 30 件を超えるリクエストが、キーなし、または無効なキーを使用しました。そのアドレスからのすべての `/v1` リクエストは、有効なキーを含めて 15 分間拒否されます。`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"
  }
}
```

| Field | Type | 説明 |
| --- | --- | --- |
| `message` | string | 何が問題かを説明する文です。解析しないでください。 |
| `type` | string | エラーの種類です。下の一覧を参照してください。 |
| `code` | string | 原因を示す安定した識別子です。このフィールドで判定してください。 |
| `param` | string \| null | 問題のあるリクエストのフィールド、または `null` です。 |

### type とステータス

| Status | 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 | Status | 発生条件 |
| --- | --- | --- |
| `unsupported_content_type` | 400 | `/v1/images/generations` が `multipart/form-data` のボディを受け取りました。JSON を送信してください。`param` は `null` です。 |
| `request_too_large` | 413 | `multipart/form-data` のアップロードが 50 MiB を超えています。大きなメディアは https URL で送信してください。 |
| `invalid_body` | 400 | ボディのフィールド、またはクエリパラメーターが解析できない、型が誤っている、または許可された値の範囲外です。`param` が該当の項目を示します。 |
| `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 で指定した動画に対して `seconds` がありません。 |
| `unsupported_operation` | 400 | モデルがその操作（編集、延長、リミックス、または画像編集）に対応していません。 |
| `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 | アカウントが 1 分あたりのリクエスト数、または同時リクエスト数の上限を超えています。[レート制限](#rate-limits)を参照してください。 |
| `too_many_auth_failures` | 429 | お客様のアドレスから 1 分間に 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 がリクエストを受信したかどうかはわかりません。再送すると、2 つ目のジョブが開始され、二重に支払うことになりかねません。`Idempotency-Key` を使うと、再送を安全に行えます。Hyperouter は再送を識別し、2 つ目のジョブを開始せず、2 回目のクレジット確保も行わずに、最初のリクエストの結果で応答します。

**お金のかかるリクエストには、毎回キーを送信してください。**新しいリクエストごとに、UUID v4 などのランダムな値を新たに生成します。その値をリクエストとともに保持し、同じリクエストを再送するときは毎回同じ値を送信します。

### キーの送信

このヘッダーは、次のエンドポイントで受け付けられます。

| Endpoint | 再送で返されるもの |
| --- | --- |
| `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 の応答 |
| --- | --- |
| 新しいキー | 通常どおりリクエストを実行します。 |
| 同じキーと同じリクエスト（最初のリクエストが受理された後） | 上の表のとおり、最初のリクエストの結果を返します。2 つ目のジョブも、2 回目のクレジット確保も、2 回目の課金もありません。 |
| 同じキーと同じリクエスト（最初のリクエストがまだ受理処理中） | 最初のリクエストを待ち、上記のとおり応答します。最初のリクエストが 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 キーに属します。2 つの API キーが同じ値を使っても、互いに影響しません。
- **有効期間。**キーは、最初のリクエストから 30 分間有効です。その間に再試行してください。
- **同一のリクエスト。**メソッド、パス、ボディが一致する場合、2 つのリクエストは同一とみなされます。JSON は解析後に比較されるため、フィールドの順序や空白は影響しません。画像や動画はボディ内の URL なので、比較されるのは URL であり、その先のバイト列は比較されません。
- **課金。**キーを付けたリクエストは、再送の回数にかかわらず、最大で 1 回だけ課金されます。最初のリクエストの結果で応答した再送は、無料です。
- **保証。**1 つのキーで開始されるジョブは 1 つまでです。2 つの再送が同時に届いた場合も同様です。

### チャット補完 {#idempotency-chat}

チャットの応答は再現されません。同じキーでの再送には、コード `idempotency_key_replayed` の `409` が返り、`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` の応答を、既定で 2 回再試行します。ただし、応答にレスポンスヘッダー `x-should-retry: false` が付いている場合は再試行しません。Hyperouter は、再試行すると 2 つ目のジョブや 2 回目の課金が発生するすべての応答に `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` には、このヘッダーを付けません。これらは再試行しても安全です。`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": {}
  }]
}
```

| Field | Type | 説明 |
| --- | --- | --- |
| `id` | string | モデル ID（`<provider>/<name>`）。たとえば `x-ai/grok-4.7` や `qwen/qwen-image-2.0` です。`model` として送信します。名前が変更されたモデルも、旧 ID で引き続き応答します。 |
| `response_modes` | string[] | モデルの応答方法です。`sync`（1 回の保持された応答）、`async`（`Prefer: respond-async` を送信して `202` を受け取り、ポーリングする）、`stream`（`"stream": true`）があります。`async` のみを列挙するモデルには `Prefer` ヘッダーが必要で、`stream` は列挙されている場合にのみ使えます。動画は、ヘッダーの有無にかかわらず、Videos API では常に非同期です。 |
| `name` | string | 表示名。 |
| `kind` | string | `chat`、`image`、または `video`。 |
| `context_length` | integer | トークン数で表したコンテキストウィンドウ。画像・動画モデルでは `0`。 |
| `architecture` | object | `input_modalities` と `output_modalities`。出力は `["text"]`、`["image"]`、または `["video"]` です。 |
| `pricing` | object of strings | 基本ティアでの、単位あたりの USD 価格（10 進数の文字列）。`prompt` と `completion`（トークンあたり）、`input_cache_read`（キャッシュされたトークンあたり）、`request`、`image`（画像 1 枚あたり）、`video_second`（動画 1 秒あたり）です。解像度で価格が決まる動画には、最も低い価格が表示されます。該当しない単位は `"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 万トークンあたりの価格：入力 / キャッシュされた入力 / 出力。

<!-- BEGIN GENERATED models-chat: sitemd writes the rows from models.json; edit the header row only. Run cd tools && go run ./sitemd -->
| Model | Context | 価格 |
| --- | --- | --- |
| `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 | 1 リクエストあたり $0.0013 |
<!-- END GENERATED models-chat -->

`x-ai/` のモデルでは、プロンプトが 200,000 トークン以上のリクエストは、全体が長コンテキスト料金で課金されます。この料金は上記の 2 倍です。`deepseek/` のモデルは、プロンプトの長さにかかわらず料金が一定で、既定では回答の前に推論を行い（`reasoning_effort: "none"` で無効にできます）、その推論分も `max_tokens` に数えられ、上限は 384,000 です。`z-ai/glm-5.3` は常に推論します。`reasoning_effort` は `low`、`high`、`max` のいずれかで、`none` は拒否されます。`openai/` のモデルも推論を行い、プロンプトは最大 272,000 トークンです。

## チャット補完 {#chat-completions}

`POST /v1/chat/completions`

会話に対するモデルの応答を作成します。ボディは OpenAI の Chat Completions リクエストです。Hyperouter は `models`、`provider`、`moderation` を追加しています。

### パラメーター

| 名前 | Type | 必須 | 許可される値 | 既定値 | 説明 |
| --- | --- | --- | --- | --- | --- |
| `model` | string | はい | `GET /v1/models` のチャットモデル ID |  | 使用するモデル。たとえば `x-ai/grok-4.7`。 |
| `messages` | object[] | はい | 空でないこと。ロールは `system`、`user`、`assistant`、`tool` |  | これまでの会話。モデルが画像に対応している場合は、画像（`image_url` パート）も受け付けます。 |
| `models` | string[] | いいえ | モデル ID は最大 5 件 |  | 追加項目。`model` のすべてのプロバイダーが失敗した後に、順に試すフォールバックモデル。 |
| `provider` | object | いいえ | 下記を参照 |  | 追加項目。ルーティングの希望。 |
| `moderation` | string | いいえ | `auto`、`low` | `auto` | 追加項目。[モデレーション](#moderation)を参照してください。 |
| `stream` | boolean | いいえ |  | `false` | サーバー送信イベントを返します。 |
| `stream_options` | object | いいえ | `{"include_usage": true}` |  | `include_usage` を指定すると、ストリームは `usage` を含むチャンクで終わります。 |
| `max_tokens`、`max_completion_tokens` | integer | いいえ | 1 以上 | モデルの最大出力 | 生成するトークン数の上限。リクエストにかかりうる最大額も決まり、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 スキーマ |  | 構造化出力。 |
| `reasoning_effort`、`logprobs`、`top_logprobs`、`user` | OpenAI と同じ | いいえ |  |  | モデルが対応している場合、プロバイダーにそのまま渡されます。 |

その他のフィールドは無視されます。各モデルが受け付ける内容は、[GET /v1/models](#models) の各モデルの `supported_parameters` に正確に列挙されています。Grok 4.20 以降は `logprobs` と `top_logprobs` を無視するため、列挙されません。

### provider オブジェクト {#routing}

既定では、Hyperouter は各チャットリクエストを、そのモデルの価格が最も低い正常なプロバイダーに送信し、同価格の場合は直近の最初のトークンまでの時間が最も短いプロバイダーを選びます。エラーを繰り返すプロバイダーは、回復するまでスキップされます。`provider` オブジェクトは、OpenRouter のリクエスト形式に従っています。

| 名前 | Type | 必須 | 許可される値 | 既定値 | 説明 |
| --- | --- | --- | --- | --- | --- |
| `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`（課金額。USD、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
  }
}
```

プロンプト書き換えモデルは、選択肢を 1 つ、トークン数 0 の `usage`、およびリクエストごとの固定の `cost` で応答します。

### ストリーミング {#streaming}

`"stream": true` を指定すると、レスポンスは OpenAI のチャンク形式のサーバー送信イベントのストリームになり、`data: [DONE]` で終わります。`stream_options.include_usage` を設定すると、`[DONE]` の直前の最後のチャンクに、空の `choices` 配列と、`cost` を含む `usage` オブジェクト、および `provider` フィールドが含まれます。このチャンクを要求するかどうかにかかわらず、課金のために利用量は常に収集されます。

最初のトークンが届くまでの間、ストリームは接続を維持するために、コメント行 `: processing` を 15 秒ごとに送信します。SSE クライアントはコメントを無視します。

別のプロバイダーへのフォールバックは、最初のトークンが送信される前にのみ行われます。ストリームの途中でプロバイダーが失敗した場合、ストリームは `data: {"error": {...}}` に続けて `data: [DONE]` で終了し、すでに生成されたトークンが課金されます。

課金されるのは、読み取ったかどうかにかかわらず、プロバイダーが生成したトークンです。中断したストリームや、待つのをやめた応答は、プロバイダー側では停止されず、プロバイダーは回答の全体を生成して課金します。Hyperouter はその終わりまで（最大でさらに 5 分間）読み取り、その分を課金します。

リクエストを受け付けたプロバイダーは、それを実行中である可能性があります。その後プロバイダーが応答しなくなった場合（ストリームで 5 分間トークンがない、または `max_tokens` 分の応答にかかる時間を超えた場合）、または最初のトークンの前に応答が途切れた場合、リクエストは別のプロバイダーには送信されません。コード `timeout` または `upstream_error` と `error.generation_id` を伴う `503` が返り、確保した額が課金され、その記録には `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" }]
  }'
```

### エラー

| Status | type | code | param | 発生条件 |
| --- | --- | --- | --- | --- |
| `400` | `invalid_request_error` | `invalid_body` | 該当のフィールド | ボディが有効な JSON でない、または 32 MiB を超えている。`model` がない。`models` が 6 件以上ある。`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` | 残高またはキーの上限が、リクエストにかかりうる最大額をまかなえません。メッセージに、まかなえるトークン数が示されます。 |
| `429` | `rate_limit_error` | `venue_busy` |  | モデルのすべてのプロバイダーが、レートの上限に達しています。 |
| `429` | `rate_limit_error` | `rate_limited` |  | アカウントが 1 分あたりのリクエスト数、または同時リクエスト数の上限を超えています（[レート制限](#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` |  | プロバイダーがリクエストを受け付けた後、最初のトークンの前に応答が途切れました。確保した額が課金されます（[ストリーミング](#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。1 つあたり 20 MiB、1 リクエストあたり 50 MiB）を 3 日間保存し、プロバイダーが取得する推測不能な `https://api.hyperouter.app/u/...` URL にしたうえで、リクエストを JSON として実行します。動画ファイルは拒否されます（`400 invalid_video`）。動画は https URL で送信してください。どちらも、下記の共通機能と、[モデル固有のパラメーター](#parameters)をトップレベルのフィールドとして受け付けます。

### パラメーター

| 名前 | Type | 必須 | 許可される値 | 既定値 | 説明 |
| --- | --- | --- | --- | --- | --- |
| `model` | string | はい | 画像モデル ID |  | 使用するモデル。 |
| `prompt` | string | Generations：はい。Edits：モデルの要件による | 空白でないテキスト |  | 作成する内容。 |
| `images` | object[] | Edits：はい | `{"image_url": "https://..."}` のオブジェクト 1 〜 5 個。モデルが受け付ける数まで。各 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"
}
```

| Field | Type | 説明 |
| --- | --- | --- |
| `created` | integer | リクエストの Unix 時刻。 |
| `data[].url` | string | `response_format: "url"` の場合：24 時間有効な署名付きリンク。`GET /v1/generations/{id}` を呼ぶと、新しい署名付きリンクが発行されます。 |
| `usage.cost` | number | 課金額。USD、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 秒たっても画像が完成していない場合は、コード `timeout` とレスポンスヘッダー `x-should-retry: false` を伴う `503` が返ります。これにより、OpenAI SDK が再試行して 2 枚目の画像を開始することはありません。ジョブは継続し、エラーには `generation_id` としてその ID が含まれます。結果は [GET /v1/generations/{id}](#generations) をポーリングして取得してください。成功した場合にのみ課金されます。ご自身で安全に再試行するには、[Idempotency-Key](#idempotency) を送信してください。同じキーでの再試行は、同じジョブを待ちます。
- `response_modes` が `async` のみのモデルには、`Prefer: respond-async` が必要です。これがない場合は、コード `async_required` の `400` が返ります。
- `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"}]}'
```

### エラー

| Status | 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 を超えている、またはモデルの上限を超えている。画像が 6 枚以上ある。モデルが受け付ける数より画像が多い。 |
| `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` なし）、またはアカウントが 1 分あたりのリクエスト数もしくは同時リクエスト数の上限を超えています（`code: rate_limited`。[レート制限](#rate-limits)を参照）。 |
| `503` | `upstream_error` |  | `The model failed to produce a result. You were not charged.` |
| `503` | `provider_busy` |  | プロバイダーが約 2 分間満杯のままで、ジョブを受け付けませんでした。後で再試行してください。課金されていません。 |
| `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 -->
| Model | 内容 | 価格 |
| --- | --- | --- |
| `x-ai/grok-imagine-image` | 生成と編集。最大 10 枚の画像を生成、最大 5 枚の画像を入力。 | 1 枚あたり $0.02 |
| `x-ai/grok-imagine-image-2.0` | 生成と編集（上記と同じ）。 | 1 枚あたり $0.04 から |
| `qwen/qwen-image-2.0` | 生成と編集（入力画像 1 〜 3 枚）。`n` は 1 〜 6。 | 1 枚あたり $0.035 |
| `bytedance/seedream-5.0-flash` | 生成と編集（入力画像 1 〜 10 枚）。1 リクエストにつき 2K 画像 1 枚、透かしなし。 | 1 枚あたり $0.018 |
| `bytedance/seedream-5.0-lite` | 生成と編集（上記と同じ）。 | 1 枚あたり $0.035 |
<!-- END GENERATED models-image -->

一部のモデルは、アカウントへのアクセス許可が必要です。ダッシュボードの[モデルリファレンス](https://dash.hyperouter.app/docs/models)には、アカウントが呼び出せるすべてのモデルが、パラメーター、価格、備考とともに掲載されています。

## 動画 {#videos}

動画は OpenAI の Videos API に従っています。動画はジョブです。作成、編集、延長、リミックスの呼び出しは、ステータス `queued` の Video オブジェクトとともに、すぐに `200` で応答します。ステータスが `completed` になるまで `GET /v1/videos/{id}` をポーリングするか、[Webhook](#webhooks) を受け取ります。`Prefer` はここでは何も変えません。動画は常に非同期です。

| Endpoint | 内容 |
| --- | --- |
| `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` で拒否されます。

| 名前 | 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_model` | string | いいえ | [画像](#images)と同じ | `x-ai/grok-4.6` | 追加項目。`prompt_expand` と併用：書き直しを行うモデル。[プロンプト拡張](#prompt-expansion)を参照してください。 |
| `prompt_expand`、`locale` | boolean、string | いいえ | [画像](#images)と同じ | `false` | 追加項目。[プロンプト拡張](#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)を参照してください。 |

### 編集、延長、リミックス

| Endpoint | ボディ（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` が必要です。

### 一覧表示、取得、ダウンロード、削除

| Endpoint | パラメーター | 応答 |
| --- | --- | --- |
| `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`） | バイト列（`video/mp4`、またはサムネイルの型）への署名付きリンクへの `302 Found`。リンクの有効期間は 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 }
}
```

| Field | Type | 説明 |
| --- | --- | --- |
| `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 | 編集、延長、リミックスの元の動画。 |
| `usage` | object \| null | ジョブが精算された時点で設定されます：`cost`（USD、JSON の数値）と `seconds`（整数）。 |
| `expanded_prompt` | string \| null | 追加項目。`prompt_expand` 使用時：ジョブ送信後、生成に使われたプロンプト。30 日間保持され、その後は `null`。 |

動画は、リクエストした秒数に基づいて課金されます。金額は事前に確保され、ジョブが失敗した場合は全額が解放されます。

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

モデル `x-ai/grok-imagine-video` は、プロンプトから動画を作成します。開始画像は任意です。`seconds` は 1 〜 15 です。価格：1 秒あたり $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}` と表示されます。

### エラー

| Status | 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` がモデルで許可されていない（メッセージに許可される値が列挙されます）、または URL で指定した動画に必要です。 |
| `400` | `invalid_size` | `size` | `size` が `1280x720` の形式ではありません。 |
| `400` | `unsupported_parameter` | 該当のフィールド | モデルがそのフィールドに対応していない。その解像度が利用できない（`resolution` または `size`）。音声に対応しないモデルでの `audio`。`input_reference.file_id`。 |
| `400` | `unsupported_operation` | `model` | モデルがその操作（編集、延長、リミックス）を列挙していません。 |
| `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 -->
| Model | 動画 1 秒あたりの価格 | 備考 |
| --- | --- | --- |
| `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)）。

### パラメーター

| 名前 | 場所 | Type | 必須 | 説明 |
| --- | --- | --- | --- | --- |
| `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": []
  }
}
```

| Field | Type | 説明 |
| --- | --- | --- |
| `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` は課金額（USD、JSON の数値）です。数値は、リクエストが完了するまで `0` です。 |
| `usage_estimated` | boolean | プロバイダーがトークン数を送ってこなかったため、Hyperouter が数えた場合は `true`。 |
| `ttft_ms`、`latency_ms` | integer \| null | 最初のトークンまでの時間と合計時間（ミリ秒）。 |
| `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"
```

### エラー

| Status | 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` に列挙します。各エントリーには次の項目があります。

| Field | Type | 説明 |
| --- | --- | --- |
| `type` | string | `string`、`integer`、`number`、`boolean`、`array`、`object` のいずれか。 |
| `values` | array | 許可される値。空の場合は、その型の任意の値を意味します。 |
| `price_condition` | boolean | そのフィールドが価格を変える場合は `true`。 |
| `description` | string | そのフィールドの働き。 |

ダッシュボードの[モデルリファレンス](https://dash.hyperouter.app/docs/models)には、アカウントが呼び出せる各モデルの追加パラメーターが記載されています。

### ルール

- 既知のパラメーターであっても、そのモデルが持たないものは拒否されます。コード `unsupported_parameter` の `400 invalid_request_error` が返り、`param` にはフィールド名（たとえば `loras`）、メッセージは `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` には名前が、メッセージには `loras must be of type array.` のような文が入ります。
- `values` の範囲外の値は、`400 invalid_body` とメッセージ `<name> must be one of [...]` で拒否されます。
- どのモデルも宣言していないフィールドは、OpenAI の API が未知のフィールドを無視するのと同様に、無視されます。
- すべてのモデルは、パラメーターを自身のスキーマに照らして検証します。許可される値、最小値と最大値、必須フィールド、リストの長さです。スキーマの範囲外の値には、フィールドを示す `param` を伴う `400 invalid_body` が返ります。たとえば `seconds must be one of 5, 8.` です。
- ベンダーが認めていない組み合わせ（参照メディアとキーフレームの併用など）には、理由を添えた `400 invalid_combination` が返ります。これらの検証は、課金が発生する前に行われます。
- `resolution` や `audio` のように価格を変えるフィールドは、事前のクレジット確保に織り込まれて価格が計算されるため、確保額は正確です。

### 共通機能

これらのフィールドは、対応するすべてのモデルで同じ名前です。モデルが受け付けるものは `supported_parameters` に列挙されます。

| Field | 意味 |
| --- | --- |
| `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` となり、いずれも何かを確保する前に拒否されます。画像を読めるモデルにはリクエストの画像が渡され、読めないモデルはテキストだけから書き直します。
- **料金。** 書き直しは同じリクエストで課金され、使用したトークンに、書き直したモデル（`prompt_expand_model`、指定がなければ `x-ai/grok-4.6`）のトークン単価が適用されます。その上限額は生成分とあわせて事前に確保されます。各モデルの詳細はモデルリファレンスを参照してください。
- **実行されない場合。** 書き直しが失敗した、タイムアウトした、または使用できなかった場合は、送信したプロンプトのまま生成し、`expanded_prompt: null` を返します。料金はかかりません。
- **言語。** 動画のセリフは、モデルがその言語を話せる場合、`locale`（指定がなければ英語）に従います。

#### 書き直しをチャットモデルとして呼び出す {#prompt-expansion-model}

プロンプト拡張が有効なアカウントでは、生成は行わずに書き直しの結果を返すチャットモデルも使えます。モデル名はお使いの[モデルリファレンス](#models)に記載されています。`POST /v1/chat/completions` で、`user` メッセージを 1 つだけ送って呼び出します。そのテキストがプロンプトで、`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"`（1 秒につき 1 行）を含みます。料金は `x-ai/grok-4.6` のトークン価格で、`usage` に表示されます。モデルの指示を出力させようとするプロンプトは `400 prompt_rejected`、書き直しが拒否されたか空だった場合は `422 expansion_refused`、失敗した場合は `503 upstream_error` を返します。いずれも課金されません。

## モデレーション {#moderation}

`moderation` フィールドは OpenAI のものです。`/v1/chat/completions`、`/v1/images/generations`、`/v1/images/edits`、および `/v1/videos` とその編集、延長、リミックスの呼び出しで使えます。

| 値 | 意味 |
| --- | --- |
| `auto`（既定値） | ベンダー独自のスクリーニングが適用されます。Hyperouter は何も追加で送信しません。 |
| `low` | プロバイダーがスクリーニングのオプトアウトを備えているモデルでは、Hyperouter がそのオプトアウトを送信します。それ以外のモデルでは、OpenAI と同様に、`low` はエラーなく無視されます。各モデルにオプトアウトがあるかどうかは、[モデルリファレンス](https://dash.hyperouter.app/docs/models)の各モデルの項目に記載しています。`moderation` はリクエストボディで送信してください。プロバイダー独自のスクリーニング用ヘッダーやフィールドは、これらのエンドポイントでは転送されません。 |

それ以外の値は拒否されます。`400 invalid_request_error`、コード `invalid_body`、`param` は `moderation`、メッセージは `moderation must be auto or low.` です。

`low` は、Hyperouter が有効にした後にアカウントで利用できます。依頼するには、サポートチケットを作成してください。有効になるまでは、`low` を指定したリクエストには `403 permission_error`、コード `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` | raw 呼び出しのタスクが終了したとき（raw 呼び出しが有効なアカウント）：課金された、または確保が解除された。結果をその場で返す raw 呼び出しは送信しません。 |

ペイロードに含まれるのは ID のみで、結果、プロンプト、課金額は含まれません。オブジェクトは API キーで取得してください。`data.id` は、[GET /v1/videos/{id}](#videos) と [GET /v1/generations/{id}](#generations) が受け付ける ID です。raw タスクの場合は、作成時に返された `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" }
}
```

### ヘッダーと検証

各配信は、`content-type: application/json` と次のヘッダーを持つ `POST` です。

- `webhook-id`：イベント ID。再試行のたびに同じ値のため、重複の排除に使用してください。
- `webhook-timestamp`：Unix 秒。
- `webhook-signature`：`v1,` に続けて、`id.timestamp.body` の HMAC-SHA256 を base64 エンコードしたもの。鍵はエンドポイントのシークレットです。

署名用のシークレットは `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 の他の部分と同じベース URL を使用します。

### エンドポイント、リトライ、制限

- エンドポイントは、ポート 443（またはポートなし）の `https` で、IP アドレスではなくホスト名である必要があります。ホストは公開アドレスに解決される必要があり、Hyperouter は接続時にも再確認します。リダイレクトには従いません。
- 1 つのアカウントのエンドポイントは最大 10 個です。各エンドポイントは、受け取りたいイベントの種類を選択します。
- 10 秒以内の `2xx` は成功です。それ以外は、約 5 秒後、1 分後、5 分後、30 分後、2 時間後、5 時間後、10 時間後、10 時間後に再試行され、その後は配信が失敗として記録されます。
- 3 日間すべての配信が失敗したエンドポイントは無効になり、ダッシュボードにその理由が表示されます。受信側を修正した後、再度有効にしてください。
- ダッシュボードには、各エンドポイントの配信が、ステータス、試行回数、最後の HTTP ステータス、最後のエラーとともに一覧表示されます。再送（同じイベント ID）と、テストイベントの送信（`data.id` がエンドポイントの ID である `webhook.test` イベントを配信）が用意されています。

## MCP サーバー {#mcp}

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

AI アシスタントは、Model Context Protocol（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` | ユーザーが使用する権限を持つすべてのツール。 |

トークンはベアラートークンとして送信します。

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

### プロトコル

| メソッド | 応答 |
| --- | --- |
| `initialize` | プロトコルのバージョン（クライアントのバージョン。対応していない場合は `2025-11-25`）、`tools` ケイパビリティ、サーバー情報。 |
| `ping` | 空の結果。 |
| `tools/list` | トークンのユーザーとスコープが許可するツール。 |
| `tools/call` | 1 つのツールの結果。 |

通知、またはサーバーへのレスポンスには、ボディなしの `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` は現在のツールセットを返します。各ツールは 1 つのダッシュボードのルートに対応し、引数用の 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 ボディを格納した 1 つのテキストコンテンツアイテムで応答します。ルートが失敗した場合、結果には `isError: true` と、`<message> (<code>, HTTP <status>)` というテキストが入ります。不明なツール、またはお客様のトークンから見えないツールは、JSON-RPC エラー `-32602` になります。

### 承認

アカウントへのクレジット付与のような機密性の高い書き込みは、その場では実行されません。ツールはそれを実行せず、`status` を `approval_required` にし、ダッシュボード上の `approval_url` を添えて応答します。ユーザーはそのリンクを開き、第 2 要素で確認して、操作を承認します。承認は 24 時間で失効します。ユーザーは拒否することもできます。

<!-- toc: アカウント -->
## 課金と制限 {#billing}

- リクエストの料金は、プリペイドの USD 残高から、そのリクエストを処理したプロバイダーの定価で、上乗せなしで支払われます。
- **確保してから精算。**リクエストの実行前に、Hyperouter はかかりうる最大額を確保します。チャットでは入力に `max_tokens` を加えた分、画像では要求した枚数、動画では秒数です。完了すると、実際に使われた分が課金され、確保額の残りは解放されます。残高がマイナスになることはありません。
- 失敗したリクエスト、または失敗した画像や動画のジョブは無料です。失敗したフォールバックの試行も無料です。
- すべてのレスポンスに、課金額が `usage.cost`（USD の JSON 数値）として含まれます。チャット、画像、精算済みの動画、および `GET /v1/generations/{id}` で確認できます。ダッシュボードでは、すべてのリクエストと、日別・モデル別・キー別の利用額を確認できます。
- 金額は正確です。お金は 10 億分の 1 ドル単位で数えられ、浮動小数点数を経由して丸められることはありません。`GET /v1/models` の価格は 10 進数の文字列です。
- 現時点ではチャージは手動です。[ダッシュボード](https://dash.hyperouter.app/credits)で、金額、支払い参照番号、支払いのスクリーンショットを添えてチャージの依頼を作成してください。スタッフが支払いを確認して残高に反映し、同じチケットで返信します。
- **チャージ手数料。**チャージごとに、支払額の 5.5%（最低 $0.80）の手数料がかかり、チャージが反映される際に差し引かれます。$100 の支払いでは $94.50、$10 の支払いでは $9.20 が反映されます。適用される手数料は、チャージを依頼する前に [Credits](https://dash.hyperouter.app/credits) ページに表示され、履歴の各チャージには支払額と手数料が表示されます。リクエスト自体には手数料はかかりません。

### レート制限 {#rate-limits}

各アカウントには、1 分あたりのリクエスト数と、同時に処理中のリクエスト数の上限があります。どちらもアカウントのすべての API キーを合算してカウントされ、処理を開始するすべてのリクエストに適用されます。チャット補完、画像と動画の作成、raw の作成が対象です。結果の読み取り（`GET /v1/generations/{id}`、`GET /v1/videos…`、raw のタスクのポーリング）はカウントされません。raw のポーリングはプロバイダーごとに別にカウントされ、上限は 1 分あたりのリクエスト数と同じです。

ティアは、チャージ手数料を差し引く前の累計チャージ額に応じて決まります。

| ティア | 累計チャージ額 | 1 分あたりのリクエスト数 | 同時リクエスト数 |
| --- | --- | --- | --- |
| 1 | $10 未満 | 60 | 10 |
| 2 | $10 以上 | 300 | 30 |
| 3 | $100 以上 | 1,200 | 100 |
| 4 | $1,000 以上 | 6,000 | 300 |

現在の上限は [Credits](https://dash.hyperouter.app/credits) ページで確認できます。これらは既定値で、スタッフはプラットフォーム全体または 1 つのアカウントについて変更でき、変更は 1 分以内に反映されます。

いずれかの上限を超えると、クレジットの確保も転送も行われる前にリクエストが拒否され、`429`、`type: rate_limit_error`、`code: rate_limited`、および秒数を示す `Retry-After` ヘッダーが返ります。メッセージには、到達した上限が示されます。拒否されたリクエストも、その 1 分間にカウントされます。ストリームを含め、処理中のリクエストは、終了するまでカウントされます。

キーの推測に対する防御として、Hyperouter は失敗した API キーの確認をクライアントのアドレスごとに数えます。1 分間に 30 回を超えると、そのアドレスからのすべての `/v1` ルートが 15 分間ブロックされ、`Retry-After` を伴う `429`、`rate_limit_error`、`too_many_auth_failures` が返ります。有効なキーを使っても、ブロックは解除されません。

## サポート {#support}

課金、チャージ、API に関するご質問は、[ダッシュボード](https://dash.hyperouter.app/tickets)でチケットを作成してください。スタッフが同じスレッドで返信します。[account@hyperouter.app](mailto:account@hyperouter.app) 宛てにご連絡いただくこともできます。特定のリクエストについて報告する際は、レスポンスの `id` を添えてください。
