openrouter-analytics-query について
openrouter-analytics-queryは、OpenRouterの分析クエリを作成・実行するスキルです。APIの使用量、コスト、性能を調べる人向けに、クエリ指定、分類器ディメンションとフィルター、JSONを返すCLIスクリプトを説明します。
主な機能
- 01指標とディメンションによるクエリ作成
- 02時間粒度、期間、フィルターの指定
- 03分類器ディメンションとフィルターに対応
- 04CLIのクエリ引数を提供
- 05結果とメタデータをJSONで出力
活用シーン
- 01モデル別のリクエスト数やコストの集計
- 02特定のモデルやプロバイダーのデータ抽出
- 03指標の時系列変化の確認
- 04行数制限による結果の切り詰め確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ openrouterteam/ skills --skill openrouter-analytics-queryインストール後、Claude Code で/openrouter-analytics-queryを入力して読み込まれたか確認します。
同梱ファイルREADME.md
詳細
OpenRouter Analytics クエリの実行
OpenRouter API に対する分析クエリの構築と実行に関する完全なリファレンスです。
前提条件
OPENROUTER_API_KEYに管理キーを設定する必要があります。管理キーは通常の API キーとは別のものです。https://openrouter.ai/settings/management-keys で取得してください。
クエリエンドポイント
POST https://openrouter.ai/api/v1/analytics/query
Authorization: Bearer sk-or-v1-...
Content-Type: application/json
openrouter-analytics スキルのスクリプトから実行することもできます。
cd <openrouter-analytics-skill-path>/scripts && npx tsx query-analytics.ts --metrics request_count
信頼できる情報源(内容の乖離を防ぐため): 以下に示すメトリクス名、ディメンション名、リクエストスキーマは説明用です。最新かつ正式な一覧はメタエンドポイントから取得できます。
GET /api/v1/analytics/meta(またはdiscover-schema.ts)を呼び出し、そのレスポンスを正としてください。エージェントが参照できるドキュメントとして、OpenRouter はllms.txtを公開しています。記載内容に食い違いがある場合は、このファイル内の例よりもそちらを優先してください。
リクエストスキーマ
{
"metrics": ["request_count", "total_usage"],
"dimensions": ["model"],
"granularity": "day",
"time_range": {
"start": "2026-05-01T00:00:00Z",
"end": "2026-05-20T00:00:00Z"
},
"filters": [
{ "field": "model", "operator": "eq", "value": "anthropic/claude-sonnet-4" }
],
"order_by": { "field": "total_usage", "direction": "desc" },
"limit": 100,
"group_limit": 20,
"classifier_dimensions": {
"classifier_id": "<uuid>",
"dimension_names": ["category"],
"include_nulls": false
},
"classifier_filters": {
"classifier_id": "<uuid>",
"filters": [
{ "field": "sentiment", "operator": "eq", "value": "positive" }
]
}
}
必須フィールド
| フィールド | 型 | 説明 |
|---|---|---|
metrics | string[] | 計算するメトリクスを1つ以上指定します。利用可能なメトリクスを確認するには、メタエンドポイントを呼び出してください。 |
オプションフィールド
| フィールド | 型 | デフォルト | 説明 |
|---|---|---|---|
dimensions | string[] | [] | グループ化するディメンションを最大2つ指定します |
granularity | string | なし | 時間の区切り:minute、hour、day、week、month |
time_range | object | 直近7日間 | { start, end } を ISO 8601 UTC 日時文字列で指定します。秒の指定は必須です(YYYY-MM-DDTHH:MM:SSZ。小数秒も指定できます)。2026-05-01T00:00Z のように分単位の値を指定すると、400 エラーになります。 |
filters | object[] | [] | フィルター条件を最大20個指定します |
order_by | object | (granularity を指定した場合)時間の降順 | { field, direction }。field はメトリクス、ディメンション、または "date"(短縮形のエイリアス。granularity に応じて date__day、date__hour などに対応します)です |
limit | integer | 1000 | 返す行の最大合計数(1~10,000)。ディメンションを指定した時系列クエリで group_limit を明示しない場合、想定される時間バケットとディメンションの組み合わせ数に対応できるよう、サーバーがこの値を引き上げることがあります。 |
group_limit | integer | 自動計算 | ディメンションの組み合わせごとに返す行の最大数(ClickHouse の LIMIT n BY)。時系列クエリ(granularity と dimensions を指定)で省略すると、時間範囲から自動計算され、グループごとに時間範囲全体が網羅されます。明示した値はデフォルト値より優先されます。dimensions を指定しない場合は無視されます。 |
classifier_dimensions | object | なし | 分類器が生成したディメンションでグループ化します。詳しくは、以下の分類器ディメンションを参照してください。 |
classifier_filters | object | なし | 分類器が生成したディメンション値でフィルタリングします。詳しくは、以下の分類器フィルターを参照してください。 |
フィルターオブジェクトの形式
{ "field": "<dimension_name>", "operator": "<op>", "value": "<value>" }
- スカラー演算子(
eq、neq、gt、gte、lt、lte):valueは文字列または数値です - 配列演算子(
in、not_in):valueは文字列または数値の配列です in/not_inでは、オプションのinclude_unset: trueを指定できます。この場合、ディメンションに値がない行も一致します。未設定バケットがあるディメンション(api_key_id、app、user)でのみサポートされます。それ以外のディメンションで指定すると、リクエストは 400 エラーになります。- 一部のディメンションはクエリ結果でラベルに変換され、人が読める名前で返されますが、フィルターには元の ID を指定する必要があります。
api_key_id— 数値 ID(生成メタデータから取得)または64文字の SHA-256 ハッシュ(GET /api/v1/keysから取得)。ハッシュはクエリの前に数値 ID に自動変換されます。user— Clerk ユーザー ID(例:user_abc123)。結果に表示される表示名やメールアドレスではありません。workspace— ワークスペース UUID。結果に表示されるワークスペース名ではありません。app— 数値のアプリ ID。アプリのタイトルではありません。model— permaslug(例:openai/gpt-4o)。表示名ではありません。
- その他のディメンション(
provider、origin、country、finish_reason、external_userなど)は拡張されません。フィルター値は結果に返される値と一致します。
並べ替え
{ "field": "<metric_or_dimension_or_date>", "direction": "asc" | "desc" }
granularity が設定されていて order_by が指定されていない場合、結果は時間の降順で並べ替えられます。
分類器のディメンション
分類器のディメンションを使用すると、アカウントに紐付けられた分類器が生成する動的なユーザー定義分類ラベル(トピック、感情、カテゴリなど)でグループ化できます。
{
"classifier_dimensions": {
"classifier_id": "550e8400-e29b-41d4-a716-446655440000",
"dimension_names": ["category"],
"include_nulls": false
}
}
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
classifier_id | string (UUID) | はい | 分類器の ID(呼び出し元のアカウントに属している必要があります) |
dimension_names | string[] | いいえ | グループ化する特定のディメンション名(最大 2 つ)。省略すると、すべての分類器ディメンションが含まれます。名前は有効な識別子(英字、数字、アンダースコア。最大 64 文字)である必要があります。 |
include_nulls | boolean | いいえ | true の場合、未分類の行が結果に含まれます。デフォルトは false(分類済みの行のみ)です。 |
制約:
- クエリの時間範囲は 31 日間に制限されます
- ディメンション名が 1 つの場合 → 結果の列名はその名前になります(例:
category) - ディメンション名が 2 つの場合 → それぞれが個別の結果列となり、両方の値で結果がクロスグループ化されます
dimension_namesを省略した場合 → 結果には汎用のclf_dimension_name/clf_dimension_value列が使用されます(ディメンションと値の組み合わせごとに 1 行)
分類器フィルター
分類器フィルターを使用すると、特定の分類値に一致する生成に結果を絞り込めます。単独でも、classifier_dimensions と併用しても使用できます。
{
"classifier_filters": {
"classifier_id": "550e8400-e29b-41d4-a716-446655440000",
"filters": [
{ "field": "category", "operator": "eq", "value": "billing" },
{ "field": "sentiment", "operator": "in", "value": ["positive", "neutral"] }
]
}
}
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
classifier_id | string (UUID) | はい | 分類器の ID(呼び出し元のアカウントに属している必要があります) |
filters | object[] | はい | 分類器ディメンションに対する 1~10 個のフィルター条件 |
filters[].field | string | はい | 絞り込み対象となる分類器ディメンション名 |
filters[].operator | string | はい | 次のいずれか:eq、neq、in、not_in(値は文字列のため、gt / lt は使用できません) |
filters[].value | string | string[] | はい | eq / neq にはスカラー値、in / not_in には配列を指定します |
制約:
- クエリの時間範囲は 31 日間に制限されます
- 等価/集合演算子のみサポートされます(分類値は文字列のため、順序比較は辞書順になります)
- すべてのフィルターフィールド名は、分類器に設定されているディメンションである必要があります
レスポンススキーマ
{
"data": {
"data": [
{ "date__day": "2026-05-19", "model": "anthropic/claude-sonnet-4", "request_count": "1523", "total_usage": 4.27 },
{ "date__day": "2026-05-18", "model": "openai/gpt-4o", "request_count": "892", "total_usage": 2.15 }
],
"metadata": {
"query_time_ms": 142,
"row_count": 2,
"truncated": false
},
"cachedAt": 1747699200000,
"warnings": ["Could not resolve api_key_id hash: abc123..."]
}
}
レスポンスフィールド
| フィールド | 説明 |
|---|---|
data.data | 結果行の配列です。各行には、要求されたメトリクス、ディメンション、および(粒度が設定されている場合)date__<granularity> のキーが含まれます。classifier_dimensions クエリで dimension_name を1つ指定した場合、列名はその名前(例:category)にエイリアスされます。名前を2つ指定した場合は、それぞれの名前の列が作成され、両方の名前で行がグループ化されます。dimension_names を省略した場合、行には clf_dimension_name 列と clf_dimension_value 列が含まれ、ディメンションと値の組み合わせごとに1行返されます。 |
data.metadata.query_time_ms | クエリの実行時間(ミリ秒) |
data.metadata.row_count | 返された行数 |
data.metadata.truncated | 結果が上限で切り詰められた場合は true |
data.cachedAt | 結果がキャッシュされた時刻を示す Unix タイムスタンプ(ミリ秒)。キャッシュからレスポンスが返された場合に含まれます |
data.warnings | 省略可能な、致命的ではない警告の配列です(例:解決できない api_key_id ハッシュ)。クエリは通常どおり実行されます。これらの警告は、フィルターの解決に関する問題を呼び出し元に知らせます。 |
数値型: カウント系のメトリクス(
request_count、tokens_*など)は文字列("1523")として返されます。コスト系および率系のメトリクス(total_usage、cache_hit_rate、レイテンシ、スループット)は数値(4.27)として返されます。算術演算を行う前に、Number()またはparseInt()でカウント値を変換してください。
ラベルの解決: ディメンション
api_key_id、app、user、workspaceは、データ行で生の ID ではなく、人が読み取れるラベル(キー名、アプリのタイトル、ユーザー名、ワークスペース名)を返します。センチネルバケットは生の値ではなくラベルで返されます。api_key_idの-1はChatroom、appの-1はUnknown、最大 UUID のworkspaceセンチネルはUnattributedとして返されます。modelはラベルが置き換えられることはなく、permaslug のままです。
CLI リファレンス
openrouter-analytics スキルの query-analytics.ts スクリプトでは、次のフラグを使用できます。
| フラグ | 説明 | 例 |
|---|---|---|
--api-key | API キー(OPENROUTER_API_KEY 環境変数がフォールバックとして使用されます) | --api-key sk-or-v1-... |
--metrics | カンマ区切りのメトリクス名(必須) | --metrics request_count,total_usage |
--dimensions | カンマ区切りのディメンション名 | --dimensions model,provider |
--granularity | 時間バケットのサイズ | --granularity day |
--start | 時間範囲の開始(ISO 8601 UTC、秒が必須) | --start 2026-05-01T00:00:00Z |
--end | 時間範囲の終了(ISO 8601 UTC、秒が必須) | --end 2026-05-20T00:00:00Z |
--filter-field | フィルター対象のディメンション名(最初のフィルター。下記の注記を参照) | --filter-field model |
--filter-op | フィルター演算子(最初のフィルター) | --filter-op eq |
--filter-value | フィルター値(in/not_in の場合はカンマ区切り) | --filter-value anthropic/claude-sonnet-4 |
--filter-field-N | N 番目の追加フィルターのディメンション名(N = 1–19) | --filter-field-1 provider |
--filter-op-N | N 番目の追加フィルターの演算子 | --filter-op-1 eq |
--filter-value-N | N 番目の追加フィルターの値 | --filter-value-1 anthropic |
--order-by | 並べ替え対象のフィールド | --order-by total_usage |
--order-dir | 並べ替えの方向 | --order-dir desc |
--limit | 最大合計行数(1–10000) | --limit 100 |
--group-limit | ディメンションの組み合わせごとの最大行数(1–10000)。ディメンションを指定した時系列クエリで省略すると、サーバー側で自動計算されます。 | --group-limit 50 |
CLI は、data(結果行)と metadata の 2 つのキーを含む単一の JSON オブジェクトを stdout に出力します。
{
"data": [ { "model": "anthropic/claude-sonnet-4", "total_usage": 4.27 } ],
"metadata": { "query_time_ms": 142, "row_count": 2, "truncated": false }
}
人が読める形式の統計情報(行数、クエリ時間、切り捨て/キャッシュのフラグ)は、ターミナルでの使用に限り stderr に書き込まれます。
出力をプログラムで解析する場合は、必ず
metadata.truncatedを確認してください。trueの場合、結果は--limitで上限に達しており、不完全なデータセットです。合計やランキングを報告する前に、--limitを増やすか、ページネーションを行ってください。ディメンションapi_key_id、user、app、workspaceは、データ行ですでに人が読める名前に解決されています。
複数フィルターのクエリ: CLI は、インデックスなしの基本フラグ(--filter-field/--filter-op/--filter-value)と、インデックス付きの --filter-field-N/--filter-op-N/--filter-value-N フラグから、複数要素の filters 配列を構築します(条件は AND で結合されます)。各フィルターには 3 つの要素(フィールド、演算子、値)すべてを指定する必要があります。一部だけの指定は拒否されます。API の上限と同じく、合計で最大 20 個のフィルター(基本フラグとインデックス 1~19)を指定できます。インデックスは飛び飛びでも構いません(例:基本フラグに加えて -1 を省略し -2 を指定しても問題ありません。欠番はスキップされ、黙って破棄されることはありません)。model = X AND provider = Y のようなクエリの場合:
npx tsx query-analytics.ts --metrics request_count \
--filter-field model --filter-op eq --filter-value anthropic/claude-sonnet-4 \
--filter-field-1 provider --filter-op-1 eq --filter-value-1 anthropic
フラグ値に関する注意: CLI の引数パーサーは、-- で始まるトークンを新しいフラグとして扱うため、-- で始まるフィルター 値 は CLI フラグから渡せません。ディメンション値(モデル ID、プロバイダー名など)が -- で始まることはないため、実際にはほとんど問題になりません。ただし、そのような値が必要な場合は、代わりに以下の 直接 curl を使う方法 を使用してください。
API の直接利用(curl)
スクリプトを使用せず、API を直接呼び出す場合:
curl -X POST https://openrouter.ai/api/v1/analytics/query \
-H "Authorization: Bearer $OPENROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": ["total_usage", "request_count"],
"dimensions": ["model"],
"granularity": "day",
"time_range": {
"start": "2026-05-13T00:00:00Z",
"end": "2026-05-20T00:00:00Z"
},
"order_by": { "field": "total_usage", "direction": "desc" },
"limit": 10,
"group_limit": 7
}'
クエリ構築ガイド
集計(時系列なし)
granularity を省略すると、ディメンションの組み合わせごとに 1 つの集計行が返されます。
{
"metrics": ["total_usage", "request_count"],
"dimensions": ["model"],
"order_by": { "field": "total_usage", "direction": "desc" },
"limit": 10
}
時系列(granularity を指定)
granularity を追加すると、時間バケットごとに 1 行が返されます(ディメンションを指定した場合は、ディメンションの組み合わせごとにも 1 行が返されます)。
{
"metrics": ["request_count"],
"granularity": "day",
"time_range": {
"start": "2026-05-01T00:00:00Z",
"end": "2026-05-20T00:00:00Z"
}
}
フィルターを使ったクエリ
フィルターで結果を絞り込みます。複数のフィルターは AND で結合されます。
{
"metrics": ["total_usage", "avg_latency"],
"dimensions": ["provider"],
"filters": [
{ "field": "model", "operator": "eq", "value": "anthropic/claude-sonnet-4" }
]
}
複数ディメンションのクエリ
クロス集計には最大 2 つのディメンションを組み合わせます。
{
"metrics": ["request_count"],
"dimensions": ["model", "provider"],
"order_by": { "field": "request_count", "direction": "desc" },
"limit": 20
}
エラー処理
| ステータス | 意味 | 対処方法 |
|---|---|---|
| 400 | クエリが無効です(JSON 本文の形式不正、メトリクス名の誤り、ディメンション数が多すぎる、時間範囲が無効) | 有効な値については meta エンドポイントを確認してください。時間範囲の開始が終了より前であることと、両方のタイムスタンプに秒が含まれていることを確認してください。ディメンションは最大 2 個、フィルターは 20 個です。キャッシュ可能性メトリクスを、サポート対象外のディメンション、フィルター、分類子、または minute 粒度と組み合わせた場合も 400 が返されます。 |
| 401 | API キーが無効、または指定されていません | OPENROUTER_API_KEY が正しく設定されていることを確認してください |
| 403 | 管理用キーではありません | キーはプロビジョニングキーまたは管理キーである必要があります。openrouter.ai/settings/management-keys で作成してください |
| 408 | クエリがタイムアウトしました | 時間範囲を狭める、ディメンションを減らす、またはフィルターを追加してスキャンするデータ量を減らしてください |
| 429 | レート制限を超えています(64 RPM) | しばらく待ってから再試行してください |
| 500 | サーバーエラー | 少し待ってから再試行してください |
時間範囲の動作
start と end は、秒を含む ISO 8601 形式の UTC タイムスタンプである必要があります(2026-05-01T00:00:00Z)。小数秒は使用できますが、分単位の精度のタイムスタンプと UTC 以外のオフセットは、クエリの実行前に拒否されます。
一部のメトリクスとディメンションの組み合わせでは、時間範囲を最大 367 日(日単位の粒度)まで指定できますが、それ以外は 31 日までに制限されます。サーバーは、要求されたメトリクスとディメンションに基づいて自動的に判定します。
使用量の内訳メトリクスも同じパターンに従います。credits_usage、usage_upstream、usage_cache、usage_data、usage_web、usage_upstream_web は最大 367 日まで対応しますが、openrouter_usage、byok_fees、usage_file、usage_upstream_file、usage_web_fetch、usage_upstream_web_fetch は 31 日までに制限されます。
キャッシュ可能性メトリクス(possible_cached_tokens、possible_cache_hit_rate、cache_capture_rate)は、常に時間単位の集計値を読み込みます。粒度にかかわらず 31 日までに制限され、model と provider のディメンションおよびフィルターのみをサポートします。また、minute 粒度、分類子ディメンション、または分類子フィルターと組み合わせると、400 が返されます。
hour 粒度は分単位のマテリアライズドビューを読み込むため、それ以外であれば 367 日まで対応するメトリクスでも、範囲は 31 日までに制限されます。
分類子ディメンションと分類子フィルターを使用すると、常に時間範囲の上限が 31 日になります。
クエリがタイムアウトした場合は、次の方法を試してください。
- 時間範囲を狭める
- レイテンシ/スループットのメトリクスを削除する
- 生成ごとのディメンション(
provider、origin、country、finish_reasonなど)を削除する - 分類子ディメンション/フィルターを削除する(計算コストが高くなります)