控制台

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当 type 为 text 时出现。
sourceObject当 type 为 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。
imagesString图片 URL 数组的 JSON 字符串,如 "[\"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
  }
}