APIリファレンス
共通規約
ベースURL
すべてのエンドポイントは /v1 プレフィックスの下で提供されます。
認証
/v1/* エンドポイントへの呼び出しは APIキー認証を使用します (JWTではありません)。APIキーは以下のヘッダーで渡されます:
| ヘッダー | フォーマット | 説明 |
|---|---|---|
Authorization | Bearer <api_key> | OpenAIスタイル。Anthropic互換エンドポイントは x-api-key と anthropic-version: 2023-06-01 も受け付けます。 |
キーが存在しない、または無効な場合は 401 を返します。
残高事前チェック
すべてのモデル呼び出しエンドポイントは実行前に残高事前チェックを行います:
- 残高不足の場合
Insufficient creditを返し、以下にマッピングされます:- OpenAIプロトコル:HTTP
400、code = insufficient_quota - Anthropicプロトコル:HTTP
402、type = billing_error
- OpenAIプロトコル:HTTP
- 一部のエンドポイントは2回目の事前チェックのためにモデルごとの最小コストを見積もります。
Create Chat CompletionPOSThttps://api.basicrouter.ai/api/v1/chat/completions
OpenAI Chat Completions互換エンドポイント。ストリーミングと非ストリーミング、ツール 呼び出し、JSONモード、マルチモーダル入力をサポートします。
| フィールド | タイプ | 必須 | 説明 |
|---|---|---|---|
model | String | はい | モデル名。 |
messages | Message[] | はい | 会話メッセージ。 |
stream | Boolean | いいえ | ストリームモード、デフォルト false。 |
temperature | Double | いいえ | サンプリング温度。 |
max_tokens | Integer | いいえ | 最大出力トークン数。 |
top_p | Double | いいえ | 核サンプリング。 |
presence_penalty | Double | いいえ | — |
frequency_penalty | Double | いいえ | — |
tools | Tool[] | いいえ | ツール定義。 |
tool_choice | String|Object | いいえ | auto / none / required / 特定の 関数。 |
response_format | Object | いいえ | {type, json_schema:{name,schema,strict}}; text/json_object/json_schema。 |
parallel_tool_calls | Boolean | いいえ | — |
metadata | Map | いいえ | パススルーメタデータ。 |
Message フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
role | String | system / user / assistant / tool。 |
content | String|Array | プレーンテキストまたはマルチモーダルコンテンツブロック配列 ([{type:"text",text},{type:"image_url",image_url:{url}}])。 |
tool_call_id | String | role=tool の場合、tool_callsにリンクします。 |
tool_calls | ToolCall[] | role=assistant がツール呼び出しを行う場合に存在します。 |
| フィールド | タイプ | 説明 |
|---|---|---|
type | String | 固定値 function。 |
function | Object | 関数定義。 |
function.name | String | 関数名。 |
function.description | String | 関数の説明。 |
function.parameters | Object | 入力のJSONスキーマ。 |
curl --request POST \
--url https://api.basicrouter.ai/api/v1/chat/completions \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "glm-5.2",
"messages": [{"role": "user", "content": "Describe Hangzhou in one sentence."}],
"stream": false,
"temperature": 0.7
}'{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1721380000,
"model": "glm-5.2",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Hangzhou is ..."},
"finish_reason": "stop"
}
],
"usage": {"prompt_tokens": 12, "completion_tokens": 18, "total_tokens": 30}
}レスポンスフィールド(非ストリーミング):
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | 補完ID。 |
object | String | 固定値 chat.completion。 |
created | Long | 作成タイムスタンプ(秒)。 |
model | String | モデル名。 |
choices | Choice[] | {index, message:{role, content, tool_calls?}, finish_reason}。 |
usage | Object | {prompt_tokens, completion_tokens, total_tokens}。 |
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | ツール呼び出しID。 |
type | String | 固定値 function。 |
function | Object | 関数呼び出しの詳細。 |
function.name | String | 関数名。 |
function.arguments | Object | 関数の引数。 |
ストリーミングレスポンスの例:
data: {"object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":"..."}}]}
data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"..."}}]}
data: [DONE]Create ResponsePOSThttps://api.basicrouter.ai/api/v1/responses
OpenAI Responses互換エンドポイント。messages の代わりに input を、 システムメッセージの代わりに instructions を、response_format の 代わりに text ブロックを使用します。
| フィールド | タイプ | 必須 | 説明 |
|---|---|---|---|
model | String | はい | モデル名。 |
input | String|Array | はい | プレーン文字列(ユーザーメッセージ)またはメッセージオブジェクト配列。 |
instructions | String | いいえ | システムプロンプト。 |
stream | Boolean | いいえ | デフォルト false。 |
max_output_tokens | Integer | いいえ | 最大出力トークン数。 |
temperature | Double | いいえ | デフォルト 1。 |
top_p | Double | いいえ | — |
tools | Tool[] | いいえ | 最上位の {type, name, description, parameters}。 |
tool_choice | String|Object | いいえ | auto/none/required/{type,name}。 |
text | Object | いいえ | {format:{type, name, schema, strict}}; text/json_object/json_schema。 |
metadata | Map | いいえ | — |
previous_response_id | String | いいえ | マルチターン用の前回のレスポンスID。 |
parallel_tool_calls | Boolean | いいえ | — |
curl --request POST \
--url https://api.basicrouter.ai/api/v1/responses \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "glm-5.2",
"input": "Describe Hangzhou in one sentence.",
"instructions": "Be concise.",
"stream": false
}'{
"id": "resp_xxx",
"object": "response",
"model": "glm-5.2",
"status": "completed",
"created_at": 1721380000,
"output": [
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [{"type": "output_text", "text": "Hangzhou is ..."}],
"status": "completed"
}
],
"usage": {"input_tokens": 12, "output_tokens": 18, "total_tokens": 30}
}レスポンスフィールド(非ストリーミング):
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | レスポンスID。 |
object | String | 固定値 response。 |
model | String | モデル名。 |
status | String | 例: completed。 |
created_at | Long | 作成タイムスタンプ(秒)。 |
output | Array | 出力項目。メッセージ項目: {id, type:"message", role, content:[{type:"output_text", text}], status}。ツール呼び出し項目: {type:"function_call", id, name, call_id, arguments, status}。 |
usage | Object | {input_tokens, output_tokens, total_tokens}。Claudeモデルの場合、 input_tokens には cache_read が含まれ、 output_tokens には cache_write が含まれます。 |
ストリーミングはResponses APIのイベントに従います:
| イベント | 説明 |
|---|---|
response.created | レスポンスストリームの開始。 |
response.output_text.delta | テキスト出力の増分更新。 |
response.completed | レスポンスストリームの終了。 |
Create Anthropic MessagePOSThttps://api.basicrouter.ai/api/v1/messages
Anthropic Messages互換エンドポイント。x-api-key と anthropic-version: 2023-06-01 ヘッダーを受け付けます。コンテンツブロックは text、image、tool_use、tool_result、 thinking、redacted_thinking をサポートします。
| フィールド | タイプ | 必須 | JSONフィールド | 説明 |
|---|---|---|---|---|
model | String | はい | model | モデル名。 |
messages | Message[] | はい | messages | 会話メッセージ。 |
system | String|Array | いいえ | system | システムプロンプト、文字列または [{type,text}]。 |
maxTokens | Integer | はい | max_tokens | 最大出力トークン数。 |
stream | Boolean | いいえ | stream | ストリーミング。 |
temperature | Double | いいえ | temperature | — |
topP | Double | いいえ | top_p | — |
topK | Integer | いいえ | top_k | — |
tools | Tool[] | いいえ | tools | ツール定義(input_schema)。 |
toolChoice | Object | いいえ | tool_choice | — |
metadata | Map | いいえ | metadata | — |
thinking | Object | いいえ | thinking | 拡張思考設定。 |
stopSequences | Object | いいえ | stop_sequences | — |
anthropicBeta | Object | いいえ | anthropic_beta | ベータ機能ヘッダー。 |
| フィールド | タイプ | 説明 |
|---|---|---|
role | String | メッセージロール、例:user / assistant。 |
content | String|ContentBlock[] | プレーンテキストまたはコンテンツブロックの配列。 |
| フィールド | タイプ | 説明 |
|---|---|---|
type | String | text、image、tool_use、 tool_result、thinking、 redacted_thinkingのいずれか。 |
text | String | typeがtextの場合に存在します。 |
source | Object | typeがimageの場合に存在します。 |
例:
{ "type": "image", "source": { "type": "base64", "media_type": "...", "data": "..." } }
{ "type": "image", "source": { "type": "url", "url": "..." } }| フィールド | タイプ | 説明 |
|---|---|---|
name | String | 関数名。 |
description | String | 関数の説明。 |
input_schema | Object | 入力のJSONスキーマ。 |
cache_control | Object | オプションのキャッシュ制御。 |
curl --request POST \
--url https://api.basicrouter.ai/api/v1/messages \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "anthropic-version: 2023-06-01" \
--header "Content-Type: application/json" \
--data '{
"model": "claude-sonnet-4.6",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Describe Hangzhou in one sentence."}]
}'{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4.6",
"content": [{"type": "text", "text": "Hangzhou is ..."}],
"stop_reason": "end_turn",
"usage": {"input_tokens": 12, "output_tokens": 18}
}レスポンスフィールド(非ストリーミング):
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | メッセージID。 |
type | String | 固定値 message。 |
role | String | 固定値 assistant。 |
model | String | モデル名。 |
content | ContentBlock[] | レスポンスコンテンツブロック(例:{type:"text", text}、 {type:"tool_use", ...})。 |
stop_reason | String | 例:end_turn、tool_use、max_tokens。 |
usage | Object | {input_tokens, output_tokens}。 |
| イベント | 説明 |
|---|---|
message_start | メッセージストリームの開始。 |
content_block_start | 新しいコンテンツブロックの開始。 |
content_block_delta | コンテンツブロックの増分更新。 |
content_block_stop | コンテンツブロックの終了。 |
message_delta | メッセージの増分更新。 |
message_stop | メッセージストリームの終了。 |
List ModelsGEThttps://api.basicrouter.ai/api/v1/models
オンラインの有効なすべてのAPIモデルを返します。
curl --request GET \
--url https://api.basicrouter.ai/api/v1/models \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"object": "list",
"data": [
{
"id": "glm-5.2",
"object": "model",
"display_name": "glm-5.2",
"created": 1721380000,
"owned_by": "Zai",
"input_modalities": ["text", "image"],
"output_modalities": ["text"],
"context_length": 128000,
"description": "..."
}
]
}各モデルエントリ(data[])のフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | モデルID。 |
object | String | 固定値 model。 |
display_name | String | 表示名。 |
created | Long | 作成タイムスタンプ(秒)。 |
owned_by | String | 所有者 / ベンダー。 |
input_modalities | String[] | 例: ["text","image"]。 |
output_modalities | String[] | 例: ["text"]。 |
context_length | Integer | 最大コンテキスト長。 |
description | String | モデルの説明。 |
Retrieve ModelGEThttps://api.basicrouter.ai/api/v1/models/{model}
リストエントリと同じ形式の単一モデルを返します。モデルが存在しない場合はHTTP 404を返します。
curl --request GET \
--url https://api.basicrouter.ai/api/v1/models/gpt-5.5 \
--header "Authorization: Bearer $BASICROUTER_API_KEY"成功レスポンス: /v1/models リストエントリと同じフィールドを持つ単一モデルオブジェクト。
モデルが存在しない場合、HTTP 404を返します:
{"error": {"message": "The model 'xxx' does not exist", "type": "invalid_request_error", "code": "invalid_model_error"}}List Image ModelsGEThttps://api.basicrouter.ai/api/v1/image-models
画像モデルがサポートする解像度、比率、最大数を /v1/image-generations の呼び出し前に照会します。認証は不要です。
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | モデルID。 |
object | String | 固定値 image_model。 |
displayName | String | 表示名。 |
description | String | モデルの説明。 |
icon | String | アイコンURL。 |
created | Long | 作成タイムスタンプ(秒)。 |
maxCount | Integer | リクエストあたりの最大画像数。 |
fileMax | Integer | 最大参照画像数。0の場合、画像から画像の生成はサポートされません。 |
resolutions | String[] | サポートされる解像度、例: ["720p","1080p"]。 |
ratios | String[] | サポートされるアスペクト比、例: ["1:1","3:2"]。 |
curl --request GET \
--url https://api.basicrouter.ai/api/v1/image-models \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"object": "list",
"data": [
{
"id": "gpt-image-2",
"object": "image_model",
"displayName": "GPT Image 1",
"description": "...",
"icon": "...",
"created": 1721380000,
"maxCount": 4,
"fileMax": 10,
"resolutions": ["720p", "1080p"],
"ratios": ["1:1", "3:2"]
}
]
}List Video ModelsGEThttps://api.basicrouter.ai/api/v1/video-models
動画モデルがサポートする videoType 値、長さの範囲、解像度、比率を /v1/video-generations の呼び出し前に照会します。認証は不要です。
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | モデルID。 |
object | String | 固定値 video_model。 |
displayName | String | 表示名。 |
description | String | モデルの説明。 |
icon | String | アイコンURL。 |
created | Long | 作成タイムスタンプ(秒)。 |
allowedVideoTypes | VideoTypeOption[] | サポートされる videoType リスト。 |
videoDurationMin | Integer | クリップあたりの最小秒数。 |
videoDurationMax | Integer | クリップあたりの最大秒数。 |
videoDurationSuggest | Integer[] | 推奨される長さのステップ、例: [5,8,10]。 |
resolutions | String[] | サポートされる解像度。 |
ratios | String[] | サポートされるアスペクト比。 |
resolutionOptions | ResolutionOption[] | 構造化された解像度+比率+サイズの組み合わせ。 |
fileMax | Integer | 最大参照アセット数。 |
VideoTypeOption のフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
code | Integer | /v1/video-generations に渡す videoType 値。 |
name | String | ローカライズされたタイプ名(テキストから動画 / 画像から動画 / ...)。 |
curl --request GET \
--url https://api.basicrouter.ai/api/v1/video-models \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"object": "list",
"data": [
{
"id": "sora-2",
"object": "video_model",
"displayName": "Sora 2",
"description": "...",
"icon": "...",
"created": 1721380000,
"allowedVideoTypes": [
{"code": 1, "name": "text-to-video"},
{"code": 2, "name": "image-to-video"},
{"code": 3, "name": "image-to-video (first/last frame)"}
],
"videoDurationMin": 5,
"videoDurationMax": 10,
"videoDurationSuggest": [5, 8, 10],
"resolutions": ["1080p", "720p"],
"ratios": ["16:9", "9:16"],
"fileMax": 5
}
]
}価格ティア項目説明
/v1/models、/v1/models/{model}、/v1/image-models、/v1/video-models の 4 つのモデル照会エンドポイントのレスポンスは、現在の呼び出し元(API Key ユーザー)の有効な課金単価を返します。実際の課金と完全に一致し、かつそのモデルの全価格ティアを返します。
フィールド名の違い:/v1/models / /v1/models/{model} は OpenAI 流のスネークケース(price_tiers);/v1/image-models / /v1/video-models は camelCase(priceTiers)。構造は同じです。
price_tiers / priceTiers は配列で、各要素は 1 つの価格ティアです:
| 項目 | 型 | 説明 |
|---|---|---|
outputPrice | decimal | 現在の呼び出し元の有効な出力単価 |
cachePrice | decimal | キャッシュ価格(汎用モデル、旧課金式用) |
cacheReadPrice | decimal | キャッシュ読み取り単価(Bedrock Claude 専用) |
cacheWritePrice | decimal | キャッシュ書き込み単価(Bedrock Claude 専用) |
ratio | decimal | 課金倍率。FIXED モードは 1;RATIO モードはユーザー/グループ倍率 |
mode | string | 価格設定モード:RATIO / FIXED |
planId | string | 適用された価格プラン ID、null 可 |
3 種類のモデル種別で同一の構造を共有し、記述項目の埋め方のみ異なります。該当しない項目は null です:
| モデル種別 | UNIT | 有効な説明項目 |
|---|---|---|
| テキスト | token | region / bandMin / bandMax |
| 画像 | image | resolution / clarity |
| 動画 | video | resolution / clarity |
価格の意味:返される inputPrice / outputPrice / cacheReadPrice / cacheWritePrice などは、価格チェーン(chain)→ guidance → 基礎価格を順に解決した後の、現在の API Key ユーザーに対する最終課金単価であり、実際の課金と一致します。呼び出し元が見る単価は、自身が属する価格チェーン(reseller / distributor / 企業 / ユーザー単位設定)によって異なります。
実際の課金額 = 使用量 ÷ quantity × 対応単価 × ratio。動画が秒単位課金の場合、実際の課金 = duration × outputPrice × ratio。
境界と例外処理(読み取り専用エンドポイントは価格設定の問題で 500 を返しません)
| シナリオ | 動作 |
|---|---|
| 単一ティアの解決失敗(価格ポリシーがアクセスを拒否、設定欠落) | 当該ティアをスキップし、warn ログを記録して残りのティア解決を続行 |
| モデルの全ティアが解決失敗 | 空配列 []、モデルは正常に返される |
| 価格設定がないモデル | 空配列 [] |
| 価格解析で未捕捉例外 | 全体を try-catch、空配列を返し、エンドポイントは 200 |
レスポンス例(/v1/models、テキストモデル):
{
"object": "list",
"data": [
{
"id": "gpt-4o",
"object": "model",
"display_name": "gpt-4o",
"context_length": 128000,
"price_tiers": [
{
"region": "GLOBAL",
"bandMin": null,
"bandMax": null,
"resolution": null,
"clarity": null,
"unit": "token",
"quantity": 1000,
"description": "1000 トークンあたり",
"inputPrice": 0.0025,
"outputPrice": 0.01,
"cachePrice": 0.00125,
"cacheReadPrice": 0,
"cacheWritePrice": 0,
"ratio": 1,
"mode": "RATIO",
"planId": null
}
]
}
]
}レスポンス例(/v1/image-models、画像モデル、priceTiers 構造は同じ、unit は image):
{
"object": "list",
"data": [
{
"id": "dall-e-3",
"object": "image_model",
"displayName": "dall-e-3",
"resolutions": ["1024x1024", "1792x1024", "1024x1792"],
"priceTiers": [
{
"region": null,
"bandMin": null,
"bandMax": null,
"resolution": "1024x1024",
"clarity": "standard",
"unit": "image",
"quantity": 1,
"description": "1 枚あたり",
"inputPrice": 0,
"outputPrice": 0.04,
"cachePrice": 0,
"cacheReadPrice": 0,
"cacheWritePrice": 0,
"ratio": 1,
"mode": "RATIO",
"planId": null
}
]
}
]
}Create Image GenerationPOSThttps://api.basicrouter.ai/api/v1/image-generations
非同期で画像生成タスクを送信します。taskId を即座に返します。結果は GET /v1/image-generations/{taskId} でポーリングするか、callbackUrl Webhook経由で取得します。
model、サポートされる resolution / ratio 値、 count の上限、参照画像のアップロード上限(fileMax)は、 最初に GET /v1/image-models から取得する必要があります。そのモデルの仕様で提示された値のみが受け付けられます。
| フィールド | タイプ | 必須 | 説明 |
|---|---|---|---|
text | String | はい | プロンプト。 |
model | String | はい | モデル名。 |
imageUrls | String[] | いいえ | 参照画像URL(image-to-image)。 |
count | Integer | いいえ | 画像数(≥0)。 |
resolution | String | いいえ | 解像度(/v1/image-modelsを参照)。 |
ratio | String | いいえ | アスペクト比。 |
callbackUrl | String | いいえ | タスクレベルのWebhook URL。 |
curl --request POST \
--url https://api.basicrouter.ai/api/v1/image-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"model": "seedream-4.5",
"text": "A cat drinking water by the river",
"count": 1,
"resolution": "2k",
"ratio": "1:1",
"imageUrls": []
}'{
"code": 200,
"message": "image task is commit",
"data": {"taskId": "img_xxx"}
}エラーレスポンス:
// Insufficient credit
{ "code": 500, "message": "Insufficient credit" }
// Model not found
{ "code": 404, "message": "Model not found: xxx" }Retrieve Image GenerationGEThttps://api.basicrouter.ai/api/v1/image-generations/{taskId}
画像生成タスクをポーリングします。status は pending / success / failed です。images は画像URLのJSON文字列化された配列です。text はモデルが添付したテキスト説明(例: Geminiマルチモーダル出力)を運びます。それ以外の場合は null です。
curl --request GET \
--url https://api.basicrouter.ai/api/v1/image-generations/img_xxx \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"code": 200,
"message": "success",
"data": {
"taskId": "img_xxx",
"status": "success",
"errorMessage": null,
"images": "[\"https://.../1.png\"]",
"text": null
}
}レスポンス data フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
taskId | String | タスクID。 |
status | String | pending / success / failed。 |
errorMessage | String | 失敗理由。成功時は null。 |
images | String | 画像URLのJSON文字列化された配列、例: "[\"https://.../1.png\"]"。 |
text | String | モデルが添付したテキスト説明(例: Geminiマルチモーダル出力)。それ以外の場合は null。 |
タスクが見つかりません:
{ "code": 500, "message": "task not found" }送信時に callbackUrl が指定された場合、サーバーは同じ data 構造で最終的な success / failed 結果をWebhook経由でプッシュします。
完全な例(送信 + ポーリング)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class ImageGenerationExample {
private static final String BASE = "https://api.basicrouter.ai/api/v1";
private static final String API_KEY = System.getenv("BASICROUTER_API_KEY");
public static void main(String[] args) throws Exception {
HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)).build();
// 1. Submit the task.
String body = "{"
+ "\"model\":\"seedream-4.5\","
+ "\"text\":\"A cat drinking water by the river\","
+ "\"count\":1,"
+ "\"resolution\":\"2k\","
+ "\"ratio\":\"1:1\","
+ "\"imageUrls\":[]"
+ "}";
HttpResponse<String> submit = http.send(
HttpRequest.newBuilder(URI.create(BASE + "/image-generations"))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)).build(),
HttpResponse.BodyHandlers.ofString());
String taskId = extract(submit.body(), "taskId");
System.out.println("taskId = " + taskId);
// 2. Poll until terminal status.
String status = "pending";
while ("pending".equals(status)) {
Thread.sleep(15_000L);
HttpResponse<String> poll = http.send(
HttpRequest.newBuilder(URI.create(BASE + "/image-generations/" + taskId))
.header("Authorization", "Bearer " + API_KEY).GET().build(),
HttpResponse.BodyHandlers.ofString());
status = extract(poll.body(), "status");
System.out.println("status = " + status);
}
if (!"success".equals(status)) {
throw new RuntimeException("image generation failed: " + status);
}
// images is a JSON-stringified array of URLs.
String images = extract(pollResult(http, taskId), "images");
System.out.println("images = " + images);
}
// Minimal JSON field extractor — use Jackson/Gson in production.
private static String extract(String json, String field) {
int i = json.indexOf("\"" + field + "\":");
if (i < 0) return null;
i += field.length() + 3;
if (json.charAt(i) == '\"') {
int end = json.indexOf('\"', i + 1);
return json.substring(i + 1, end);
}
int end = i;
while (end < json.length() && "0123456789.".indexOf(json.charAt(end)) >= 0) end++;
return json.substring(i, end);
}
private static String pollResult(HttpClient http, String taskId) throws Exception {
return http.send(HttpRequest.newBuilder(URI.create(BASE + "/image-generations/" + taskId))
.header("Authorization", "Bearer " + API_KEY).GET().build(),
HttpResponse.BodyHandlers.ofString()).body();
}
}import os
import time
import requests
BASE = "https://api.basicrouter.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['BASICROUTER_API_KEY']}"}
# 1. Submit the task.
resp = requests.post(
f"{BASE}/image-generations",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "seedream-4.5",
"text": "A cat drinking water by the river",
"count": 1,
"resolution": "2k",
"ratio": "1:1",
"imageUrls": [],
},
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
print(f"taskId = {task_id}")
# 2. Poll until terminal status.
while True:
time.sleep(15)
poll = requests.get(f"{BASE}/image-generations/{task_id}", headers=HEADERS)
poll.raise_for_status()
data = poll.json()["data"]
status = data["status"]
print(f"status = {status}")
if status != "pending":
break
if status != "success":
raise RuntimeError(f"image generation failed: {data.get('errorMessage')}")
# images is a JSON-stringified array of URLs.
import json
images = json.loads(data["images"])
print(f"images = {images}")Create Video GenerationPOSThttps://api.basicrouter.ai/api/v1/video-generations
非同期で動画生成タスクを送信します。taskId を即座に返します。結果は GET /v1/video-generations/{taskId} でポーリングするか、callbackUrl Webhook経由で取得します。
model、許可された videoType 値、長さの範囲 (videoDurationMin/Max)、サポートされる resolution / ratio、参照アセットのアップロード上限(fileMax)は、 最初に GET /v1/video-models から取得する必要があります。そのモデルの allowedVideoTypes にリストされた videoType コードのみが受け付けられます。
| フィールド | タイプ | 必須 | 説明 |
|---|---|---|---|
text | String | はい | プロンプト。 |
model | String | はい | モデル名。 |
videoType | Integer | はい | 1 テキストから動画 / 2 画像から動画(先頭フレーム) / 3 画像から動画(先頭+末尾 フレーム) / 4 画像から動画(参照) / 5 すべて参照。 |
imageUrls | String[] | いいえ | 画像アセットURL。 |
videoUrls | VideoUrl[]|String[] | いいえ | 動画アセットURL。 |
audioUrls | String[] | いいえ | オーディオアセットURL。 |
resolution | String | いいえ | 解像度。 |
ratio | String | いいえ | アスペクト比。 |
duration | Long | いいえ | 秒(>0)。 |
callbackUrl | String | いいえ | タスクレベルのWebhook URL。 |
各 videoType の例:
1. テキストから動画(videoType=1)
テキストプロンプトのみから動画を生成します。参照アセットは不要です。
curl --request POST \
--url https://api.basicrouter.ai/api/v1/video-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"videoType": 1,
"text": "A cat jumping on a bed",
"resolution": "480p",
"ratio": "16:9",
"duration": 4,
"model": "seedance-2.0"
}'2. 画像から動画 - 先頭フレーム(videoType=2)
imageUrls に単一の開始フレームを指定します。モデルはそのフレームから動画を生成します。
curl --request POST \
--url https://api.basicrouter.ai/api/v1/video-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"videoType": 2,
"text": "Happily shaking head",
"resolution": "480p",
"ratio": "16:9",
"duration": 4,
"model": "seedance-2.0",
"imageUrls": ["https://basicrouter-flie.oss-accelerate.aliyuncs.com/test/first-frame.png"]
}'3. 画像から動画 - 先頭および末尾フレーム(videoType=3)
imageUrls に先頭フレームと末尾フレームの両方を指定します(順序: [first, last])。モデルは2つのフレーム間の遷移動画を生成します。
curl --request POST \
--url https://api.basicrouter.ai/api/v1/video-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"videoType": 3,
"text": "Put on the hat",
"resolution": "480p",
"ratio": "16:9",
"duration": 4,
"model": "seedance-2.0",
"imageUrls": [
"https://basicrouter-flie.oss-accelerate.aliyuncs.com/test/first-frame.png",
"https://basicrouter-flie.oss-accelerate.aliyuncs.com/test/last-frame.png"
]
}'4. 画像から動画 - 参照(videoType=4)
imageUrls に1つ以上の参照画像を指定します。モデルはそれらのスタイル/コンテンツを参照(強制された先頭/末尾フレームとしてではなく)として使用し、動画を生成します。
curl --request POST \
--url https://api.basicrouter.ai/api/v1/video-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"videoType": 4,
"text": "Two cats playing together",
"resolution": "480p",
"ratio": "16:9",
"duration": 4,
"model": "kling-v3-omni-video",
"imageUrls": [
"https://basicrouter-flie.oss-accelerate.aliyuncs.com/test/ref-1.png",
"https://basicrouter-flie.oss-accelerate.aliyuncs.com/test/ref-2.png"
]
}'5. すべて参照(videoType=5)
画像 / 動画 / 音声の混在参照です。プロンプト内の位置でアセットを参照します: imageUrls の1番目のエントリは @图片 1、videoUrls の1番目は @视频 1、audioUrls の1番目は @音频 1 です。videoUrls はプレーンなURL文字列も受け付けます。
curl --request POST \
--url https://api.basicrouter.ai/api/v1/video-generations \
--header "Authorization: Bearer $BASICROUTER_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"videoType": 5,
"text": "Use the first-person framing of @视频 1 and @音频 1 as background music. First-person tea ad; start frame is @图片 1 ... end frame is @图片 2.",
"model": "seedance-2.0",
"imageUrls": [
"https://ark-project.tos-cn-beijing.volces.com/doc_image/r2v_tea_pic1.jpg",
"https://ark-project.tos-cn-beijing.volces.com/doc_image/r2v_tea_pic2.jpg"
],
"videoUrls": ["https://ark-project.tos-cn-beijing.volces.com/doc_video/r2v_tea_video1.mp4"],
"audioUrls": ["https://ark-project.tos-cn-beijing.volces.com/doc_audio/r2v_tea_audio1.mp3"],
"resolution": "1080p",
"ratio": "16:9",
"duration": 11
}'送信レスポンス(5つのタイプすべて):
{
"code": 200,
"message": "success",
"data": {"taskId": "vid_xxx"}
}Retrieve Video GenerationGEThttps://api.basicrouter.ai/api/v1/video-generations/{taskId}
動画生成タスクをポーリングします。status は pending / success / failed です。videoUrl は生成された動画の URLで、lastFrameUrl は末尾フレームのURLです(画像から動画のシナリオ)。
curl --request GET \
--url https://api.basicrouter.ai/api/v1/video-generations/vid_xxx \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"code": 200,
"message": "success",
"data": {
"status": "success",
"videoUrl": "https://.../out.mp4",
"lastFrameUrl": null,
"message": null
}
}レスポンス data フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
status | String | pending / success / failed。 |
videoUrl | String | 生成された動画のURL。 |
lastFrameUrl | String | 末尾フレームのURL(画像から動画のシナリオ)。それ以外の場合は null。 |
message | String | 失敗理由。成功時は null。 |
送信時に callbackUrl が指定された場合、サーバーは同じ data 構造で最終結果をWebhook経由でプッシュします。
完全な例(送信 + ポーリング)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class VideoGenerationExample {
private static final String BASE = "https://api.basicrouter.ai/api/v1";
private static final String API_KEY = System.getenv("BASICROUTER_API_KEY");
public static void main(String[] args) throws Exception {
HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)).build();
// 1. Submit the task (videoType=1: text-to-video).
String body = "{"
+ "\"videoType\":1,"
+ "\"text\":\"A cat jumping on a bed\","
+ "\"resolution\":\"480p\","
+ "\"ratio\":\"16:9\","
+ "\"duration\":4,"
+ "\"model\":\"seedance-2.0\""
+ "}";
HttpResponse<String> submit = http.send(
HttpRequest.newBuilder(URI.create(BASE + "/video-generations"))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)).build(),
HttpResponse.BodyHandlers.ofString());
String taskId = extract(submit.body(), "taskId");
System.out.println("taskId = " + taskId);
// 2. Poll until terminal status. Video tasks take longer — poll every 20s.
String status = "pending";
String lastBody = null;
while ("pending".equals(status)) {
Thread.sleep(20_000L);
HttpResponse<String> poll = http.send(
HttpRequest.newBuilder(URI.create(BASE + "/video-generations/" + taskId))
.header("Authorization", "Bearer " + API_KEY).GET().build(),
HttpResponse.BodyHandlers.ofString());
lastBody = poll.body();
status = extract(lastBody, "status");
System.out.println("status = " + status);
}
if (!"success".equals(status)) {
throw new RuntimeException("video generation failed: " + status);
}
String videoUrl = extract(lastBody, "videoUrl");
System.out.println("videoUrl = " + videoUrl);
}
// Minimal JSON field extractor — use Jackson/Gson in production.
private static String extract(String json, String field) {
int i = json.indexOf("\"" + field + "\":");
if (i < 0) return null;
i += field.length() + 3;
if (json.charAt(i) == '\"') {
int end = json.indexOf('\"', i + 1);
return json.substring(i + 1, end);
}
int end = i;
while (end < json.length() && "0123456789.".indexOf(json.charAt(end)) >= 0) end++;
return json.substring(i, end);
}
}import os
import time
import requests
BASE = "https://api.basicrouter.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['BASICROUTER_API_KEY']}"}
# 1. Submit the task (videoType=1: text-to-video).
resp = requests.post(
f"{BASE}/video-generations",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"videoType": 1,
"text": "A cat jumping on a bed",
"resolution": "480p",
"ratio": "16:9",
"duration": 4,
"model": "seedance-2.0",
},
)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
print(f"taskId = {task_id}")
# 2. Poll until terminal status. Video tasks take longer — poll every 20s.
while True:
time.sleep(20)
poll = requests.get(f"{BASE}/video-generations/{task_id}", headers=HEADERS)
poll.raise_for_status()
data = poll.json()["data"]
status = data["status"]
print(f"status = {status}")
if status != "pending":
break
if status != "success":
raise RuntimeError(f"video generation failed: {data.get('message')}")
print(f"videoUrl = {data['videoUrl']}")
if data.get("lastFrameUrl"):
print(f"lastFrameUrl = {data['lastFrameUrl']}")Retrieve Billing BalanceGEThttps://api.basicrouter.ai/api/v1/billing/balance
アカウント残高を月額プラン、リソースパック、従量課金クレジットの3つのウォレットに分割して返します。
curl --request GET \
--url https://api.basicrouter.ai/api/v1/billing/balance \
--header "Authorization: Bearer $BASICROUTER_API_KEY"{
"totalCredit": 128.50,
"totalResourceCredit": 30.00,
"wallets": {
"monthlyPlan": {"id": "pkg_xxx", "credit": 50.00, "name": "Monthly plan"},
"resourcePacks": [
{"id": "rp_xxx", "credit": 30.00, "name": "Video resource pack"}
],
"payAsYouGo": 48.50
}
}レスポンスフィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
totalCredit | BigDecimal | 合計残高。 |
totalResourceCredit | BigDecimal | リソースパック残高の合計。 |
wallets.monthlyPlan | WalletDetail | 月額プラン(ない場合は null)。 |
wallets.resourcePacks | WalletDetail[] | リソースパックのリスト。 |
wallets.payAsYouGo | BigDecimal | 従量課金残高。 |
WalletDetailVO fields::
| フィールド | タイプ | 説明 |
|---|---|---|
id | String | ウォレットID。 |
credit | BigDecimal | 残高クレジット。 |
name | String | ウォレット名。 |
List UsageGEThttps://api.basicrouter.ai/api/v1/usage
モデル呼び出しの課金詳細のページネーションリスト。価格 (priceSnapshotId) ごとにスナップショット化され、注文作成時刻の降順で並べ替えられます。通常の課金レコード (reason = model usage) のみが返されます。
クエリパラメータ:
| パラメータ | タイプ | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
page | Integer | いいえ | 1 | ページ番号(1始まり)。 |
size | Integer | いいえ | 20 | ページサイズ(priceSnapshotId でページネーション)。 |
startTime | LocalDateTime | いいえ | — | 開始時刻。フォーマット yyyy-MM-ddTHH:mm:ss。スナップショットの orderCreatedAt でフィルタリングします。 |
endTime | LocalDateTime | いいえ | — | 終了時刻。フォーマット yyyy-MM-ddTHH:mm:ss。 |
curl --request GET \
--url "https://api.basicrouter.ai/api/v1/usage?page=1&size=20&startTime=2026-07-01T00:00:00&endTime=2026-07-31T23:59:59" \
--header "Authorization: Bearer $BASICROUTER_API_KEY"レスポンスラッパー:
{
"code": 0,
"message": "success",
"data": { ... }
}| フィールド | タイプ | 説明 |
|---|---|---|
records | UsageDetailVO[] | 現在のページのレコード。 |
total | Long | 合計件数。 |
current | Long | 現在のページ。 |
size | Long | ページサイズ。 |
pages | Long | 総ページ数。 |
UsageDetailVO フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
priceSnapshotId | String | 価格スナップショットID。 |
taskId | String | タスクID。 |
credit | BigDecimal | 課金額。 |
model | String | モデル名。 |
modelType | String | text / image / video。 |
inputTokens | Long | 入力トークン。image/videoの場合は null。 |
outputTokens | Long | 出力トークン。 |
totalTokens | Long | 合計トークン。 |
cacheReadTokens | Long | キャッシュ読み取りトークン。 |
cacheWriteTokens | Long | キャッシュ書き込みトークン。 |
imageCount | Integer | 画像数。画像モデルに設定されます。 |
imageResolution | String | 画像の解像度。例: 720P。 |
imageRatio | String | 画像のアスペクト比。例: 1:1。 |
videoResolution | String | 動画の解像度。例: 1080p。 |
videoRatio | String | 動画のアスペクト比。例: 16:9。 |
videoDurationSec | Long | 動画の長さ(秒)。 |
orderCreatedAt | LocalDateTime | 注文作成時刻(スナップショットの orderCreatedAt)。 |
creditDetails | CreditDetailItem[] | このスナップショット下の注文詳細(credit_order_t から取得)。 |
CreditDetailItem フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
credit | BigDecimal | この注文での課金額。 |
deductionSource | String | 控除元(Balance / Monthly Package / Resource Package)。 |
packageName | String | パッケージ名。パッケージがない場合は null。 |
Null値の規約: 各 modelType に関連するフィールドのみが設定され、それ以外は null になります。text はトークンフィールドを設定します; image は imageCount/imageResolution/imageRatio を設定します; video は videoResolution/videoRatio/videoDurationSec を設定します。
レスポンス例:
{
"code": 200,
"message": "success",
"data": {
"records": [
{
"priceSnapshotId": "snap_9f3c1a2b",
"taskId": "task_5e8a1c33",
"credit": 0.0342,
"model": "glm-5.2",
"modelType": "text",
"inputTokens": 1280,
"outputTokens": 642,
"totalTokens": 1922,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"imageCount": null,
"imageResolution": null,
"imageRatio": null,
"videoResolution": null,
"videoRatio": null,
"videoDurationSec": null,
"orderCreatedAt": "2026-07-18T14:23:11",
"creditDetails": [
{
"credit": 0.0342,
"deductionSource": "balance",
"packageName": ""
}
]
},
{
"priceSnapshotId": "snap_a12f77c0",
"taskId": "task_c71e44a2",
"credit": 1.8000,
"model": "seedance-2.0",
"modelType": "video",
"inputTokens": null,
"outputTokens": null,
"totalTokens": null,
"cacheReadTokens": null,
"cacheWriteTokens": null,
"imageCount": null,
"imageResolution": null,
"imageRatio": null,
"videoResolution": "1080p",
"videoRatio": "16:9",
"videoDurationSec": 8,
"orderCreatedAt": "2026-07-17T22:41:09",
"creditDetails": [
{
"credit": 1.5000,
"deductionSource": "Monthly Package",
"packageName": "基础月度套餐"
},
{
"credit": 0.3000,
"deductionSource": "Resource Package",
"packageName": "byteplus视频资源包"
}
]
}
],
"total": 128,
"current": 1,
"size": 20,
"pages": 7
}
}List Billing TransactionsGEThttps://api.basicrouter.ai/api/v1/billing/transactions
現在のユーザーの支払い済み(status=2)チャージ取引のページネーションリスト。created_at の降順で並べ替えられます。
| パラメータ | タイプ | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
page | Integer | いいえ | 1 | ページ番号。 |
size | Integer | いいえ | 20 | ページサイズ。 |
startTime | String | いいえ | — | 開始時刻。yyyy-MM-dd HH:mm:ss。境界を含みます。 |
endTime | String | いいえ | — | 終了時刻。yyyy-MM-dd HH:mm:ss。境界を含みます。 |
curl --request GET \
--url "https://api.basicrouter.ai/api/v1/billing/transactions?page=1&size=20&startTime=2026-07-01%2000:00:00&endTime=2026-07-31%2023:59:59" \
--header "Authorization: Bearer $BASICROUTER_API_KEY"レスポンスラッパー:
{
"code": 0,
"message": "success",
"data": { ... }
}| フィールド | タイプ | 説明 |
|---|---|---|
records | TransactionVO[] | 現在のページの取引。 |
total | Long | 合計件数。 |
current | Long | 現在のページ。 |
size | Long | ページサイズ。 |
pages | Long | 総ページ数。 |
TransactionVO フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
orderNo | String | 注文番号。 |
thirdPartyOrderNo | String | サードパーティの注文番号。 |
amount | BigDecimal | 注文金額。 |
actualAmount | BigDecimal | 実際の支払い額。 |
discount | BigDecimal | 割引額。 |
paymentMethod | String | 支払い方法(wechat / alipay / ustd / stripe / wallyt 等)。 |
TransactionVO フィールド:
| フィールド | タイプ | 説明 |
|---|---|---|
serviceFeeAmount | BigDecimal | サービス手数料。 |
paymentChannel | String | 決済プラットフォーム。 |
source | String | 注文元(recharge / package_purchase 等)。 |
packageName | String | パッケージ名(パッケージ購入時に設定。通常のチャージの場合は null)。 |
createdAt | LocalDateTime | 作成日時。 |
{
"code": 200,
"message": "success",
"data": {
"records": [
{
"orderNo": "R20260718abc123",
"thirdPartyOrderNo": "wx_pay_xxx",
"amount": 50.00,
"actualAmount": 48.50,
"discount": 1.50,
"paymentMethod": "wechat",
"serviceFeeAmount": 0.00,
"paymentChannel": "wechat",
"source": "recharge",
"packageName": null,
"createdAt": "2026-07-18T14:23:11"
}
],
"total": 28,
"current": 1,
"size": 20,
"pages": 2
}
}