OpenRouter APIは、共通endpointから複数のAIモデル・providerへrequestを送り、同一モデル内のprovider failoverと、異なるモデルへのfallbackを設定できるサービスです。JavaScriptではOpenAI互換のChat Completions形式を使い、models 配列へ優先順を指定します。
ただし、APIを一つにしただけでは、品質、料金、データ保持、利用地域、parameter対応まで同じにはなりません。requestごとに候補条件を設定し、responseの model とrouter metadataから、実際にどのmodel・providerが使われたかを記録します。
この記事では、Node.jsの最小request、モデル間fallback、provider条件、価格・速度・ZDR(Zero Data Retention:providerがデータを保存しない方針)、error処理、generation statsを実装します。model IDと料金は変化が速いため、2026年7月20日時点の公式仕様を基準にし、固定ランキングは作りません。
情報確認日:2026年7月20日(日本時間)
結論:候補を絞り、実際の経路を必ず記録する
アプリ
├─ task要件を決める
│ ├─ 必須parameter
│ ├─ 最大価格
│ ├─ latency / throughput
│ └─ data collection / ZDR
↓
model候補を優先順で指定
↓
OpenRouter
├─ model Aのprovider 1
├─ model Aのprovider 2へfailover
└─ model Bへfallback
↓
response
├─ 実使用model
├─ usage
├─ router metadata
└─ generation ID
↓
品質・費用・遅延・providerをtask単位で記録
本番利用の原則
- model IDを環境変数・設定DBで管理する
- fallback候補は同じ入出力契約を満たすmodelに限定する
require_parametersで必須parameterの無視を防ぐ- 機密度に応じて
data_collectionとzdrを指定する - responseの実使用modelとrouting attemptを保存する
- 価格・latency・品質を自分の評価データで定期比較する
OpenRouterを使う理由と注意点
provider failoverとmodel fallbackは別
| 機能 | 切り替えるもの | 設定 | 品質への影響 |
|---|---|---|---|
| Provider failover | 同じmodelを提供する接続先 | 既定で利用。provider条件で制御 | 同じmodelでも速度・設定差を評価 |
| Model fallback | modelそのもの | models 配列 |
出力品質・形式・tokenizationが変わり得る |
failoverは障害時に予備経路へ切り替えること、fallbackは第一候補が使えないとき別の候補へ下げることです。OpenRouterでは、同じmodelのprovider切替は既定で行われ、異なるmodelへのfallbackは models 配列で明示します。
直接契約との違い
| 項目 | OpenRouter | 各社APIへ直接接続 |
|---|---|---|
| 認証・請求 | 一つへ集約しやすい | providerごとに契約・key管理 |
| モデル切替 | 共通形式とroutingを使える | adapterを自作する |
| 最新固有機能 | 対応待ち・互換差があり得る | 公式APIで先に使える場合がある |
| データ経路 | OpenRouterと選択providerを通る | 原則として選択providerへ直接 |
| 障害切替 | provider・modelのrouting機能 | 自分で実装・運用 |
OpenAI互換とは、requestとresponseの形が似ているという意味です。全modelが同じparameter、tool schema、structured output、画像、reasoningを同じ精度で処理する保証ではありません。provider固有機能が重要なら直接APIも比較します。
JavaScriptで最小requestを送る
環境変数を準備する
mkdir openrouter-sample
cd openrouter-sample
npm init -y
npm pkg set type=module
export OPENROUTER_API_KEY="your_api_key_here"
export OPENROUTER_MODELS="provider-a/model-a,provider-b/model-b"
model IDはOpenRouterのModels APIまたはmodel一覧で確認し、organization prefixを含む正確なslugを設定します。記事中の「provider-a/model-a」はplaceholderなので、そのままでは動きません。
fetchでChat Completions endpointを呼ぶ
const apiKey = process.env.OPENROUTER_API_KEY;
const models = (process.env.OPENROUTER_MODELS ?? "")
.split(",")
.map((value) => value.trim())
.filter(Boolean);
if (!apiKey || models.length === 0) {
throw new Error("OpenRouter configuration is missing");
}
const response = await fetch(
"https://openrouter.ai/api/v1/chat/completions",
{
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"X-OpenRouter-Metadata": "enabled",
},
body: JSON.stringify({
models,
messages: [
{
role: "user",
content:
"JavaScriptのAbortControllerを" +
"120文字以内の日本語で説明してください。",
},
],
}),
},
);
const data = await response.json();
if (!response.ok) {
console.error({
status: response.status,
code: data.error?.code,
message: data.error?.message,
routing: data.openrouter_metadata?.summary,
});
process.exitCode = 1;
} else {
console.log(data.choices[0].message.content);
}
models は優先順のmodel一覧です。第一候補がrate limit、downtime、context length、moderation等のerrorになったとき、次のmodelが試されます。どのerrorでも別modelへ送ってよいかを業務要件で確認してください。
fallbackで安全基準を下げない:moderation refusalもfallbackの契機になり得ます。第一候補が拒否した内容を、安全条件の異なるmodelへ無条件で回し続ける設計は避け、用途ごとの入力検査と共通policyを持ちます。
modelとproviderのfallbackを設定する
必須parameterを無視させない
OpenRouterは、選ばれたmodel・providerが一部parameterへ対応しない場合、既定ではそのparameterを無視することがあります。JSON Schemaやtool callingが業務契約なら require_parameters: true を指定します。
const requestBody = {
models,
messages: [
{
role: "user",
content: "次の問い合わせをcategory別に分類してください。",
},
],
response_format: { type: "json_object" },
provider: {
allow_fallbacks: true,
require_parameters: true,
},
};
require_parameters により候補providerが減り、利用可能な接続先がなくなる場合があります。「JSON形式が無視されたまま成功する」より「503として失敗し、手動経路へ戻す」方が安全な業務もあります。
provider順を固定しすぎない
provider.order でprovider slugを優先順に指定でき、only で許可、ignore で除外できます。しかし、1社だけへ絞るとOpenRouterの冗長化が失われます。契約・地域・データ方針で必要な場合だけ制限し、利用可能性低下をテストします。
const fixedProviderRouting = {
provider: {
order: [
"approved-provider-a",
"approved-provider-b",
],
allow_fallbacks: false,
},
};
exact provider slugはmodelページから取得します。表示名を推測で小文字化して作らないでください。allow_fallbacks: false はorder外へ回したくない場合に使いますが、両providerが利用できないとrequestは失敗します。
価格・速度・ZDRで経路を選ぶ
| 要件 | routing候補 | 注意点 |
|---|---|---|
| 費用優先 | price順、max price、安価model候補 | 品質と再試行増加を同時に測る |
| TTFT優先 | latency指標を優先 | 地域・時間帯で変動する |
| 生成速度優先 | throughput指標を優先 | 最初の文字の速さとは別 |
| parameter必須 | require_parameters: true |
候補0件のfailure pathを用意 |
| 学習利用を避ける | data_collection: "deny" |
endpointごとの最新policyを確認 |
| 保存を避ける | zdr: true |
OpenRouterとprovider双方の条件を確認 |
latency(レイテンシ)はrequestから応答開始までの遅れ、throughput(スループット)は1秒あたりに生成できるtoken数です。ZDRはproviderがprompt・responseを一定時間保存しない方針で、「第三者を一切経由しない」「すべての法的要件を満たす」という意味ではありません。
機密度が高いrequestへZDR条件を付ける
const privateProviderRouting = {
provider: {
data_collection: "deny",
zdr: true,
require_parameters: true,
},
};
条件を厳しくすると、modelによっては利用可能なendpointがなくなります。本番では「条件を緩めて自動送信」せず、入力を送らない、承認済みの直接APIへ切り替える、利用者へ再試行を案内するなど明示的なfallbackを選びます。
個人情報を扱う判断は生成AIで個人情報を扱うときの注意点も参照してください。routing parameterは組織の法務・セキュリティ確認を代替しません。
Models APIで候補を事前確認する
model ID、context length、料金、対応parameterは更新されます。起動時または管理用jobでModels APIを取得し、設定したslugが存在し、必須parameterへ対応するかを検証します。
const modelsResponse = await fetch(
"https://openrouter.ai/api/v1/models",
);
const catalog = await modelsResponse.json();
const modelById = new Map(
catalog.data.map((item) => [item.id, item]),
);
for (const modelId of models) {
const item = modelById.get(modelId);
if (!item) {
throw new Error(`Unknown OpenRouter model: ${modelId}`);
}
console.log({
id: item.id,
contextLength: item.context_length,
promptPrice: item.pricing?.prompt,
completionPrice: item.pricing?.completion,
supportedParameters: item.supported_parameters,
});
}
pricingの値はtokenあたりの文字列として返るため、浮動小数点の丸め誤差を避ける料金計算が必要です。記事へ金額をコピーして固定せず、取得日時とcatalog responseの必要項目をsnapshotとして保存します。
実際のroutingをログへ残す
router metadataを読む
request headerへ X-OpenRouter-Metadata: enabled を付けると、成功responseへ openrouter_metadata が追加されます。新しいoptional fieldが増える可能性があるため、未知fieldをerrorにせず無視します。
const metadata = data.openrouter_metadata;
console.log({
generationId: data.id,
servedModel: data.model,
finishReason: data.choices[0].finish_reason,
promptTokens: data.usage?.prompt_tokens,
completionTokens: data.usage?.completion_tokens,
routingStrategy: metadata?.strategy,
attempt: metadata?.attempt,
summary: metadata?.summary,
selectedEndpoints:
metadata?.endpoints?.available
?.filter((endpoint) => endpoint.selected)
.map((endpoint) => ({
provider: endpoint.provider,
model: endpoint.model,
})) ?? [],
});
attempt が2以上なら、前の候補で失敗しfallbackしたことが分かります。metadataがないこと自体を障害にしません。cache replay等ではmetadataが付かない場合があると公式ガイドに明記されています。
generation statsで費用・遅延を監査する
async function getGenerationStats(generationId) {
const response = await fetch(
"https://openrouter.ai/api/v1/generation?" +
new URLSearchParams({ id: generationId }),
{
headers: {
Authorization: `Bearer ${apiKey}`,
},
},
);
if (!response.ok) {
throw new Error(`Stats failed: ${response.status}`);
}
return response.json();
}
const stats = await getGenerationStats(data.id);
console.log({
model: stats.data.model,
provider: stats.data.provider_name,
latency: stats.data.latency,
generationTime: stats.data.generation_time,
totalCost: stats.data.total_cost,
});
generation statsにはprovider、latency、token、cost等が含まれます。金額・性能ログへprompt本文を一緒に保存する必要はありません。task種別、評価dataset version、model、provider、routing条件、response IDを紐付けます。
errorと再試行を設計する
| HTTP | 意味の例 | 対応 |
|---|---|---|
| 400 | parameter・request形式が不正 | 再送せず実装を修正 |
| 401 | API keyが無効 | key・権限を確認 |
| 402 | credit不足 | 予算・残高・上限を確認 |
| 429 | rate limit | Retry-After を尊重 |
| 502 | 選択model/providerのdownstream error | routing attempt確認、上限付き再試行 |
| 503 | 条件を満たすproviderなし | policyを自動緩和せず明示的に処理 |
429や503で Retry-After headerがある場合は、その秒数を待ちます。fetchを使うなら自分で処理し、最大回数、総待機時間、jitter(同時再試行をずらす乱数)を設けます。model fallbackが既に複数回試した後、アプリ側でも無制限に再送しないようにします。
評価表をtask別に作る
| 記録項目 | 目的 |
|---|---|
| task・dataset version | 同じ問題で比較する |
| requested models | 候補と優先順を再現する |
| served model・provider | 実際の経路を特定する |
| routing conditions | ZDR・parameter・価格条件を記録 |
| 品質score | 正確性・形式・安全性を測る |
| TTFT・総時間 | 待ち時間と生成速度を分ける |
| token・total cost | 1件あたりの実費を測る |
| attempt・error | fallback率と失敗原因を測る |
「最も高性能なmodel」を一つ決めるのではなく、coding、分類、要約、長文、tool callingなどtaskごとに評価します。費用管理の設計はAI APIのコストを管理する方法を参照してください。
本番前チェックリスト
- model slugをModels APIで検証し、取得日を記録している
- fallback候補は同じ入出力契約と安全基準を満たす
- 必須parameterへ
require_parametersを使っている - データ分類に応じてcollection・ZDR・providerを制限している
- 条件を満たすproviderが0件のfailure pathがある
- responseのserved model、provider、attemptを保存している
- generation statsでtoken・cost・latencyを照合している
- 429/503のRetry-Afterと再試行上限がある
- modelごとの出力差を評価datasetで回帰テストしている
- 直接APIへ接続すべき固有機能・契約要件を確認した
まとめ:routingは可用性だけでなく、監査対象
OpenRouter APIでは、models 配列で異なるmodelのfallbackを設定し、provider でparameter対応、data collection、ZDR、provider順などを制御できます。同じmodel内のprovider failoverとmodel fallbackを分けて理解することが重要です。
requestが成功したら、回答だけでなくserved model、provider、attempt、usage、cost、latencyを記録してください。価格・速度・ZDRの条件を厳しくしたときに候補がなくなる動作もテストし、条件を黙って緩めない設計にすると、複数modelを安全に運用できます。