控制台

API 參考

通用慣例

Base URL

所有端點皆在 /v1 前綴下提供。

驗證

對 /v1/* 端點的呼叫使用 API Key 驗證(非 JWT)。API Key 透過以下標頭傳遞:

標頭格式說明
AuthorizationBearer <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
  • 部分端點也會為每個模型估算最低成本以進行第二次預檢。

Create Chat CompletionPOSThttps://api.basicrouter.ai/api/v1/chat/completions

OpenAI Chat Completions 相容端點。支援串流與非串流、工具呼叫、JSON 模式與多模態輸入。

欄位類型必填說明
modelString是模型名稱。
messagesMessage[]是對話訊息。
streamBoolean否串流模式,預設為 false。
temperatureDouble否取樣溫度。
max_tokensInteger否最大輸出 token 數。
top_pDouble否核取樣。
presence_penaltyDouble否—
frequency_penaltyDouble否—
toolsTool[]否工具定義。
tool_choiceString|Object否auto / none / required / 指定函式。
response_formatObject否{type, json_schema:{name,schema,strict}}; text/json_object/json_schema。
parallel_tool_callsBoolean否—
metadataMap否透傳中繼資料。

Message 欄位:

欄位類型說明
roleStringsystem / user / assistant / tool。
contentString|Array純文字或多模態內容區塊陣列 ([{type:"text",text},{type:"image_url",image_url:{url}}])。
tool_call_idString當 role=tool 時,關聯到 tool_calls。
tool_callsToolCall[]當 role=assistant 發起工具呼叫時出現。
欄位類型說明
typeString固定 function。
functionObject函式定義。
function.nameString函式名稱。
function.descriptionString函式說明。
function.parametersObject輸入的 JSON Schema。
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}
}

回應欄位(非串流):

欄位類型說明
idString補全 ID。
objectString固定 chat.completion。
createdLong建立時間戳記(秒)。
modelString模型名稱。
choicesChoice[]{index, message:{role, content, tool_calls?}, finish_reason}。
usageObject{prompt_tokens, completion_tokens, total_tokens}。
欄位類型說明
idString工具呼叫 ID。
typeString固定 function。
functionObject函式呼叫詳情。
function.nameString函式名稱。
function.argumentsObject函式引數。

串流回應範例:

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 相容端點。使用 input 代替 messages,使用 instructions 代替系統訊息,並使用 text 區塊代替 response_format。

欄位類型必填說明
modelString是模型名稱。
inputString|Array是純字串(使用者訊息)或訊息物件陣列。
instructionsString否系統提示。
streamBoolean否預設 false。
max_output_tokensInteger否最大輸出 token 數。
temperatureDouble否預設 1。
top_pDouble否—
toolsTool[]否頂層 {type, name, description, parameters}。
tool_choiceString|Object否auto/none/required/{type,name}。
textObject否{format:{type, name, schema, strict}}; text/json_object/json_schema。
metadataMap否—
previous_response_idString否多輪對話的前一回應 ID。
parallel_tool_callsBoolean否—
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}
}

回應欄位(非串流):

欄位類型說明
idString回應 ID。
objectString固定值 response。
modelString模型名稱。
statusString如 completed。
created_atLong建立時間戳記(秒)。
outputArray輸出項目。訊息項目: {id, type:"message", role, content:[{type:"output_text", text}], status}。工具呼叫項目: {type:"function_call", id, name, call_id, arguments, status}。
usageObject{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 欄位說明
modelString是model模型名稱。
messagesMessage[]是messages對話訊息。
systemString|Array否system系統提示,字串或 [{type,text}]。
maxTokensInteger是max_tokens最大輸出 token 數。
streamBoolean否stream串流。
temperatureDouble否temperature—
topPDouble否top_p—
topKInteger否top_k—
toolsTool[]否tools工具定義(input_schema)。
toolChoiceObject否tool_choice—
metadataMap否metadata—
thinkingObject否thinking擴充思考設定。
stopSequencesObject否stop_sequences—
anthropicBetaObject否anthropic_betaBeta 功能標頭。
欄位類型說明
roleString訊息角色,例如 user / assistant。
contentString|ContentBlock[]純文字或內容區塊陣列。
欄位類型說明
typeStringtext、image、tool_use、tool_result、thinking、redacted_thinking 其中之一。
textString類型為 text 時出現。
sourceObject類型為 image 時出現。

範例:

{ "type": "image", "source": { "type": "base64", "media_type": "...", "data": "..." } }
{ "type": "image", "source": { "type": "url", "url": "..." } }
欄位類型說明
nameString函式名稱。
descriptionString函式說明。
input_schemaObject輸入的 JSON Schema。
cache_controlObject可選的快取控制。
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}
}

回應欄位(非串流):

欄位類型說明
idString訊息 ID。
typeString固定 message。
roleString固定 assistant。
modelString模型名稱。
contentContentBlock[]回應內容區塊(如 {type:"text", text}、{type:"tool_use", ...})。
stop_reasonString如 end_turn、tool_use、max_tokens。
usageObject{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[])欄位:

欄位類型說明
idString模型 ID。
objectString固定值 model。
display_nameString顯示名稱。
createdLong建立時間戳記(秒)。
owned_byString擁有者 / 廠商。
input_modalitiesString[]如 ["text","image"]。
output_modalitiesString[]如 ["text"]。
context_lengthInteger最大上下文長度。
descriptionString模型描述。

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 前,查詢圖像模型支援的解析度、比例與最大數量。無需驗證。

欄位類型說明
idString模型 ID。
objectString固定 image_model。
displayNameString顯示名稱。
descriptionString模型說明。
iconString圖示 URL。
createdLong建立時間戳記(秒)。
maxCountInteger每次請求最大圖像數。
fileMaxInteger最大參考圖像數。當為0時,不支援圖生圖。
resolutionsString[]支援的解析度,例如 ["720p","1080p"]。
ratiosString[]支援的寬高比,例如 ["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

在呼叫 /v1/video-generations 前,查詢影片模型支援的 videoType 值、時長範圍、解析度與比例。無需驗證。

欄位類型說明
idString模型 ID。
objectString固定 video_model。
displayNameString顯示名稱。
descriptionString模型說明。
iconString圖示 URL。
createdLong建立時間戳記(秒)。
allowedVideoTypesVideoTypeOption[]支援的 videoType 清單。
videoDurationMinInteger每個片段最小秒數。
videoDurationMaxInteger每個片段最大秒數。
videoDurationSuggestInteger[]建議的時長步進,例如 [5,8,10]。
resolutionsString[]支援的解析度。
ratiosString[]支援的寬高比。
resolutionOptionsResolutionOption[]結構化的解析度+寬高比+尺寸組合。
fileMaxInteger最大參考資產數。

VideoTypeOption 欄位:

欄位類型說明
codeInteger傳遞給 /v1/video-generations 的 videoType 值。
nameString本地化類型名稱(文生影片 / 圖生影片 / ...)。
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 為陣列,每個元素是一個價格檔位:

欄位類型說明
outputPricedecimal目前呼叫方有效輸出單價
cachePricedecimal快取價格(通用模型,舊計費公式用)
cacheReadPricedecimal快取讀取單價(Bedrock Claude 專用)
cacheWritePricedecimal快取寫入單價(Bedrock Claude 專用)
ratiodecimal計費倍率。FIXED 模式為 1;RATIO 模式為使用者/分組倍率
modestring定價模式:RATIO / FIXED
planIdstring命中的定價計畫 id,可為 null

三種模型類型共用同一結構,僅描述欄位填充不同,不適用欄位為 null:

模型類型UNIT生效的描述欄位
文本tokenregion / bandMin / bandMax
圖片imageresolution / clarity
影片videoresolution / 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": "每千 token",
          "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": "每張",
          "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 取得。僅接受該模型規格宣告的值。

欄位類型必填說明
textString是提示詞。
modelString是模型名稱。
imageUrlsString[]否參考圖像 URL(圖生圖)。
countInteger否圖像數量(≥0)。
resolutionString否解析度(參見 /v1/image-models)。
ratioString否寬高比。
callbackUrlString否任務級 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 欄位:

欄位類型說明
taskIdString任務 ID。
statusStringpending / success / failed。
errorMessageString失敗原因,成功時為 null。
imagesStringJSON 字串化的圖像 URL 陣列,例如 "[\"https://.../1.png\"]"。
textString模型附加的文字描述(例如 Gemini 多模態輸出);否則為 null。

找不到任務:

{ "code": 500, "message": "task not found" }

若提交時提供了 callbackUrl,伺服器會透過 webhook 推送最終的 success / failed 結果,data 結構相同。

完整範例(提交 + 輪詢)

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 代碼。

欄位類型必填說明
textString是提示詞。
modelString是模型名稱。
videoTypeInteger是1 文生影片 / 2 圖生影片(首幀)/ 3 圖生影片(首尾幀)/ 4 圖生影片(參考)/ 5 全部參考。
imageUrlsString[]否圖像素材 URL。
videoUrlsVideoUrl[]|String[]否影片素材 URL。
audioUrlsString[]否音訊素材 URL。
resolutionString否解析度。
ratioString否寬高比。
durationLong否秒數(>0)。
callbackUrlString否任務級 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 中同時提供首幀與尾幀(順序: [首幀, 尾幀]);模型會在兩幀之間生成過渡影片。

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 中提供一張或多張參考圖像;模型將其風格/內容作為參考 (不強制作為首/尾幀)來生成影片。

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
  }'

提交回應(全部五種類型):

{
  "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 欄位:

欄位類型說明
statusStringpending / success / failed。
videoUrlString生成的影片 URL。
lastFrameUrlString尾幀 URL(圖生影片場景);否則為 null。
messageString失敗原因,成功時為 null。

若提交時提供了 callbackUrl,伺服器會透過 webhook 推送最終結果, data 結構相同。

完整範例(提交 + 輪詢)

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

回傳帳戶餘額,分為三個錢包:月度方案、資源包與隨用隨付積分。

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
  }
}

回應欄位:

欄位類型說明
totalCreditBigDecimal總餘額。
totalResourceCreditBigDecimal資源包餘額總和。
wallets.monthlyPlanWalletDetail月度方案(無則為 null)。
wallets.resourcePacksWalletDetail[]資源包列表。
wallets.payAsYouGoBigDecimal隨用隨付餘額。

WalletDetailVO 欄位:

欄位類型說明
idString錢包 ID。
creditBigDecimal餘額積分。
nameString錢包名稱。

List UsageGEThttps://api.basicrouter.ai/api/v1/usage

分頁回傳模型呼叫帳務明細,依價格(priceSnapshotId)快照劃分, 按訂單建立時間遞減排序。僅回傳正常扣費記錄(reason = model usage)。

查詢參數:

參數類型必填預設說明
pageInteger否1頁碼,從 1 開始。
sizeInteger否20每頁大小(依 priceSnapshotId 分頁)。
startTimeLocalDateTime否—起始時間,格式 yyyy-MM-ddTHH:mm:ss,依快照 orderCreatedAt 篩選。
endTimeLocalDateTime否—結束時間,格式 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": { ... }
}
欄位類型說明
recordsUsageDetailVO[]當前頁記錄。
totalLong總數。
currentLong當前頁。
sizeLong每頁大小。
pagesLong總頁數。

UsageDetailVO 欄位:

欄位類型說明
priceSnapshotIdString價格快照 ID。
taskIdString任務 ID。
creditBigDecimal扣費金額。
modelString模型名稱。
modelTypeStringtext / image / video。
inputTokensLong輸入 token 數;圖像/影片模型為 null。
outputTokensLong輸出 token 數。
totalTokensLong總 token 數。
cacheReadTokensLong快取讀取 token 數。
cacheWriteTokensLong快取寫入 token 數。
imageCountInteger圖像數量;為圖像模型設定。
imageResolutionString圖像解析度,例如 720P。
imageRatioString圖像寬高比,例如 1:1。
videoResolutionString影片解析度,例如 1080p。
videoRatioString影片寬高比,例如 16:9。
videoDurationSecLong影片時長(秒)。
orderCreatedAtLocalDateTime訂單建立時間(快照 orderCreatedAt)。
creditDetailsCreditDetailItem[]此快照下的訂單明細(來自 credit_order_t)。

CreditDetailItem 欄位:

欄位類型說明
creditBigDecimal此訂單扣費金額。
deductionSourceString扣費來源(Balance / Monthly Package / Resource Package)。
packageNameString套餐名稱;無套餐時為 null。

空值慣例:僅填入與各 modelType 相關的欄位;其餘為 null。 text 填入 token 欄位; 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 遞減排序。

參數類型必填預設說明
pageInteger否1頁碼。
sizeInteger否20每頁大小。
startTimeString否—起始時間,yyyy-MM-dd HH:mm:ss,含邊界。
endTimeString否—結束時間,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": { ... }
}
欄位類型說明
recordsTransactionVO[]當前頁交易。
totalLong總數。
currentLong當前頁。
sizeLong每頁大小。
pagesLong總頁數。

TransactionVO 欄位:

欄位類型說明
orderNoString訂單編號。
thirdPartyOrderNoString第三方訂單編號。
amountBigDecimal訂單金額。
actualAmountBigDecimal實際支付金額。
discountBigDecimal折扣金額。
paymentMethodString支付方式(wechat / alipay / ustd / stripe / wallyt 等)。

TransactionVO 欄位:

欄位類型說明
serviceFeeAmountBigDecimal服務費金額。
paymentChannelString支付平台。
sourceString訂單來源(recharge / package_purchase 等)。
packageNameString套餐名稱(套餐購買時設定;純儲值為 null)。
createdAtLocalDateTime建立時間。
{
  "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
  }
}