Bảng điều khiển

Tài liệu API

Quy ước chung

URL cơ sở

Tất cả các điểm cuối được phục vụ dưới tiền tố /v1.

Xác thực

Các lệnh gọi đến điểm cuối /v1/* sử dụng xác thực Khóa API (không phải JWT). Khóa API được truyền qua header sau:

HeaderĐịnh dạngMô tả
AuthorizationBearer <api_key>Kiểu OpenAI. Điểm cuối tương thích Anthropic cũng chấp nhận x-api-key với anthropic-version: 2023-06-01.

Các khóa bị thiếu hoặc không hợp lệ trả về 401.

Kiểm tra trước số dư

Tất cả các điểm cuối gọi mô hình chạy kiểm tra trước số dư trước khi thực thi:

  • Số dư không đủ trả về Insufficient credit, được ánh xạ tới:
    • Giao thức OpenAI: HTTP 400, code = insufficient_quota
    • Giao thức Anthropic: HTTP 402, type = billing_error
  • Một số điểm cuối cũng ước tính chi phí tối thiểu theo mô hình cho lần kiểm tra thứ hai.

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

Điểm cuối tương thích OpenAI Chat Completions. Hỗ trợ phát trực tuyến và không phát trực tuyến, gọi công cụ, chế độ JSON và đầu vào đa phương thức.

TrườngKiểuBắt buộcMô tả
modelStringCóTên mô hình.
messagesMessage[]CóTin nhắn hội thoại.
streamBooleanKhôngChế độ phát trực tuyến, mặc định false.
temperatureDoubleKhôngNhiệt độ lấy mẫu.
max_tokensIntegerKhôngToken đầu ra tối đa.
top_pDoubleKhôngLấy mẫu hạt nhân.
presence_penaltyDoubleKhông—
frequency_penaltyDoubleKhông—
toolsTool[]KhôngĐịnh nghĩa công cụ.
tool_choiceString|ObjectKhôngauto / none / required / hàm cụ thể.
response_formatObjectKhông{type, json_schema:{name,schema,strict}}; text/json_object/json_schema.
parallel_tool_callsBooleanKhông—
metadataMapKhôngSiêu dữ liệu truyền qua.

Các trường Message:

TrườngKiểuMô tả
roleStringsystem / user / assistant / tool.
contentString|ArrayVăn bản thuần hoặc mảng khối nội dung đa phương thức ([{type:"text",text},{type:"image_url",image_url:{url}}]).
tool_call_idStringLiên kết đến tool_calls khi role=tool.
tool_callsToolCall[]Có mặt khi role=assistant thực hiện gọi công cụ.
TrườngKiểuMô tả
typeStringCố định function.
functionObjectĐịnh nghĩa hàm.
function.nameStringTên hàm.
function.descriptionStringMô tả hàm.
function.parametersObjectJSON Schema cho đầu vào.
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}
}

Các trường phản hồi (không phát trực tuyến):

TrườngKiểuMô tả
idStringID hoàn thành.
objectStringCố định chat.completion.
createdLongDấu thời tạo (giây).
modelStringTên mô hình.
choicesChoice[]{index, message:{role, content, tool_calls?}, finish_reason}.
usageObject{prompt_tokens, completion_tokens, total_tokens}.
TrườngKiểuMô tả
idStringID gọi công cụ.
typeStringCố định function.
functionObjectChi tiết gọi hàm.
function.nameStringTên hàm.
function.argumentsObjectĐối số hàm.

Ví dụ phản hồi phát trực tuyến:

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

Điểm cuối tương thích OpenAI Responses. Sử dụng input thay vì messages, instructions thay vì tin nhắn hệ thống và khối text thay vì response_format.

TrườngKiểuBắt buộcMô tả
modelStringCóTên mô hình.
inputString|ArrayCóChuỗi thuần (tin nhắn người dùng) hoặc mảng đối tượng tin nhắn.
instructionsStringKhôngPrompt hệ thống.
streamBooleanKhôngMặc định false.
max_output_tokensIntegerKhôngToken đầu ra tối đa.
temperatureDoubleKhôngMặc định 1.
top_pDoubleKhông—
toolsTool[]KhôngCấp cao nhất {type, name, description, parameters}.
tool_choiceString|ObjectKhôngauto/none/required/{type,name}.
textObjectKhông{format:{type, name, schema, strict}}; text/json_object/json_schema.
metadataMapKhông—
previous_response_idStringKhôngID phản hồi trước đó cho hội thoại nhiều lượt.
parallel_tool_callsBooleanKhông—
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}
}

Các trường phản hồi (không streaming):

TrườngKiểuMô tả
idStringID phản hồi.
objectStringCố định response.
modelStringTên mô hình.
statusStringvd. completed.
created_atLongDấu thời gian tạo (giây).
outputArrayCác mục đầu ra. Mục tin nhắn: {id, type:"message", role, content:[{type:"output_text", text}], status}. Mục gọi công cụ: {type:"function_call", id, name, call_id, arguments, status}.
usageObject{input_tokens, output_tokens, total_tokens}. Đối với mô hình Claude, input_tokens bao gồm cache_read và output_tokens bao gồm cache_write.

Streaming tuân theo các sự kiện của API Responses:

Sự kiệnMô tả
response.createdBắt đầu luồng phản hồi.
response.output_text.deltaBản cập nhật văn bản đầu ra tăng dần.
response.completedKết thúc luồng phản hồi.

Create Anthropic MessagePOSThttps://api.basicrouter.ai/api/v1/messages

Điểm cuối tương thích Anthropic Messages. Chấp nhận header x-api-key và anthropic-version: 2023-06-01. Các khối nội dung hỗ trợ text, image, tool_use, tool_result, thinking và redacted_thinking.

TrườngKiểuBắt buộcTrường JSONMô tả
modelStringCómodelTên mô hình.
messagesMessage[]CómessagesTin nhắn hội thoại.
systemString|ArrayKhôngsystemPrompt hệ thống, chuỗi hoặc [{type,text}].
maxTokensIntegerCómax_tokensToken đầu ra tối đa.
streamBooleanKhôngstreamPhát trực tuyến.
temperatureDoubleKhôngtemperature—
topPDoubleKhôngtop_p—
topKIntegerKhôngtop_k—
toolsTool[]KhôngtoolsĐịnh nghĩa công cụ (input_schema).
toolChoiceObjectKhôngtool_choice—
metadataMapKhôngmetadata—
thinkingObjectKhôngthinkingCấu hình suy nghĩ mở rộng.
stopSequencesObjectKhôngstop_sequences—
anthropicBetaObjectKhônganthropic_betaHeader tính năng beta.
TrườngKiểuMô tả
roleStringVai trò tin nhắn, ví dụ user / assistant.
contentString|ContentBlock[]Văn bản thuần hoặc một mảng các khối nội dung.
TrườngKiểuMô tả
typeStringMột trong text, image, tool_use, tool_result, thinking, redacted_thinking.
textStringCó mặt khi type là text.
sourceObjectCó mặt khi type là image.

Ví dụ:

{ "type": "image", "source": { "type": "base64", "media_type": "...", "data": "..." } }
{ "type": "image", "source": { "type": "url", "url": "..." } }
TrườngKiểuMô tả
nameStringTên hàm.
descriptionStringMô tả hàm.
input_schemaObjectJSON Schema cho đầu vào.
cache_controlObjectĐiều khiển bộ nhớ đệm tùy chọn.
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}
}

Các trường phản hồi (không phát trực tuyến):

TrườngKiểuMô tả
idStringID tin nhắn.
typeStringCố định message.
roleStringCố định assistant.
modelStringTên mô hình.
contentContentBlock[]Các khối nội dung phản hồi (ví dụ {type:"text", text}, {type:"tool_use", ...}).
stop_reasonStringví dụ end_turn, tool_use, max_tokens.
usageObject{input_tokens, output_tokens}.
Sự kiệnMô tả
message_startBắt đầu luồng tin nhắn.
content_block_startBắt đầu một khối nội dung mới.
content_block_deltaCập nhật tăng dần cho một khối nội dung.
content_block_stopKết thúc một khối nội dung.
message_deltaCập nhật tăng dần cho tin nhắn.
message_stopKết thúc luồng tin nhắn.

List ModelsGEThttps://api.basicrouter.ai/api/v1/models

Trả về tất cả các mô hình API trực tuyến, đã được kích hoạt.

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": "..."
    }
  ]
}

Các trường của mỗi mục mô hình (data[]):

TrườngKiểuMô tả
idStringID mô hình.
objectStringCố định model.
display_nameStringTên hiển thị.
createdLongDấu thời gian tạo (giây).
owned_byStringChủ sở hữu / nhà cung cấp.
input_modalitiesString[]vd. ["text","image"].
output_modalitiesString[]vd. ["text"].
context_lengthIntegerĐộ dài ngữ cảnh tối đa.
descriptionStringMô tả mô hình.

Retrieve ModelGEThttps://api.basicrouter.ai/api/v1/models/{model}

Trả về một mô hình đơn với cùng cấu trúc như một mục danh sách. Trả về HTTP 404 khi mô hình không tồn tại.

curl --request GET \
  --url https://api.basicrouter.ai/api/v1/models/gpt-5.5 \
  --header "Authorization: Bearer $BASICROUTER_API_KEY"

Phản hồi thành công: một đối tượng mô hình đơn với cùng các trường như một mục danh sách /v1/models.

Khi mô hình không tồn tại, trả về 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

Truy vấn các độ phân giải, tỷ lệ và số lượng tối đa được hỗ trợ bởi một mô hình hình ảnh trước khi gọi /v1/image-generations. Không cần xác thực.

TrườngKiểuMô tả
idStringID mô hình.
objectStringCố định image_model.
displayNameStringTên hiển thị.
descriptionStringMô tả mô hình.
iconStringURL biểu tượng.
createdLongDấu thời gian tạo (giây).
maxCountIntegerSố hình ảnh tối đa mỗi yêu cầu.
fileMaxIntegerSố hình ảnh tham chiếu tối đa. Khi bằng 0, không hỗ trợ tạo ảnh từ ảnh.
resolutionsString[]Các độ phân giải được hỗ trợ, vd. ["720p","1080p"].
ratiosString[]Các tỷ lệ khung hình được hỗ trợ, vd. ["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

Truy vấn các giá trị videoType được hỗ trợ, phạm vi thời lượng, độ phân giải và tỷ lệ cho một mô hình video trước khi gọi /v1/video-generations. Không cần xác thực.

TrườngKiểuMô tả
idStringID mô hình.
objectStringCố định video_model.
displayNameStringTên hiển thị.
descriptionStringMô tả mô hình.
iconStringURL biểu tượng.
createdLongDấu thời gian tạo (giây).
allowedVideoTypesVideoTypeOption[]Danh sách videoType được hỗ trợ.
videoDurationMinIntegerSố giây tối thiểu mỗi clip.
videoDurationMaxIntegerSố giây tối đa mỗi clip.
videoDurationSuggestInteger[]Các bước thời lượng đề xuất, vd. [5,8,10].
resolutionsString[]Các độ phân giải được hỗ trợ.
ratiosString[]Các tỷ lệ khung hình được hỗ trợ.
resolutionOptionsResolutionOption[]Các tổ hợp cấu trúc độ phân giải+tỷ lệ+kích thước.
fileMaxIntegerSố tài sản tham chiếu tối đa.

Các trường VideoTypeOption:

TrườngKiểuMô tả
codeIntegerGiá trị videoType để truyền vào /v1/video-generations.
nameStringTên loại đã địa phương hóa (văn bản thành video / hình ảnh thành video / ...).
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
    }
  ]
}

Mô tả trường mức giá

4 endpoint truy vấn mô hình /v1/models, /v1/models/{model}, /v1/image-models và /v1/video-models trả về giá thanh toán hiệu lực cho người gọi (người dùng API Key), hoàn toàn khớp với chi phí thực tế, và trả về toàn bộ các mức giá của mô hình.

Khác biệt tên trường: /v1/models / /v1/models/{model} dùng kiểu OpenAI snake_case (price_tiers); /v1/image-models / /v1/video-models dùng camelCase (priceTiers). Cấu trúc hoàn toàn giống nhau.

price_tiers / priceTiers là mảng, mỗi phần tử là một mức giá:

TrườngKiểuMô tả
outputPricedecimalĐơn giá đầu ra hiệu lực của người gọi hiện tại
cachePricedecimalGiá cache (mô hình chung, dùng cho công thức thanh toán cũ)
cacheReadPricedecimalĐơn giá đọc cache (dành riêng cho Bedrock Claude)
cacheWritePricedecimalĐơn giá ghi cache (dành riêng cho Bedrock Claude)
ratiodecimalHệ số thanh toán. Chế độ FIXED là 1; chế độ RATIO là hệ số người dùng/nhóm
modestringChế độ định giá: RATIO / FIXED
planIdstringID kế hoạch định giá khớp, có thể null

Ba loại mô hình dùng chung một cấu trúc, chỉ khác ở cách điền trường mô tả, các trường không áp dụng là null:

Loại mô hìnhUNITTrường mô tả hiệu lực
Văn bảntokenregion / bandMin / bandMax
Hình ảnhimageresolution / clarity
Videovideoresolution / clarity

Ý nghĩa giá: Các giá trị inputPrice / outputPrice / cacheReadPrice / cacheWritePrice trả về là đơn giá thanh toán cuối cùng cho người dùng API Key hiện tại sau khi giải quyết qua chuỗi giá (chain) → guidance → giá cơ sở, khớp với chi phí thực tế. Đơn giá mà người gọi thấy khác nhau tùy theo chuỗi giá (reseller / distributor / doanh nghiệp / cấu hình cấp người dùng) mà họ thuộc về.

Số tiền thực tế = lượng sử dụng ÷ quantity × đơn giá tương ứng × ratio. Video tính theo giây: số tiền thực tế = duration × outputPrice × ratio.

Xử lý giới hạn & ngoại lệ (các endpoint chỉ đọc không trả về 500 do vấn đề cấu hình giá)

Tình huốngHành vi
Một mức giải quyết thất bại (chính sách giá từ chối truy cập, thiếu cấu hình)Bỏ qua mức đó, ghi log warn, tiếp tục giải quyết các mức còn lại
Tất cả các mức của một mô hình đều giải quyết thất bạiMảng rỗng [], mô hình vẫn trả về bình thường
Mô hình không có cấu hình giá nàoMảng rỗng []
Phân tích giá ném ra ngoại lệ không bắt đượcToàn bộ try-catch, trả về mảng rỗng, endpoint vẫn 200

Ví dụ phản hồi (/v1/models, mô hình văn bản):

{
  "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": "mỗi 1000 token",
          "inputPrice": 0.0025,
          "outputPrice": 0.01,
          "cachePrice": 0.00125,
          "cacheReadPrice": 0,
          "cacheWritePrice": 0,
          "ratio": 1,
          "mode": "RATIO",
          "planId": null
        }
      ]
    }
  ]
}

Ví dụ phản hồi (/v1/image-models, mô hình hình ảnh, cấu trúc priceTiers như trên, unit là 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": "mỗi hình",
          "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

Gửi không đồng bộ một tác vụ tạo hình ảnh. Trả về taskId ngay lập tức; truy xuất kết quả bằng cách polling GET /v1/image-generations/{taskId} hoặc qua webhook callbackUrl.

Các giá trị model, resolution / ratio được hỗ trợ, giới hạn trên count, và giới hạn tải lên hình ảnh tham chiếu (fileMax) phải được lấy từ GET /v1/image-models trước. Chỉ các giá trị được quảng cáo bởi spec của mô hình đó mới được chấp nhận.

TrườngKiểuBắt buộcMô tả
textStringCóPrompt.
modelStringCóTên mô hình.
imageUrlsString[]KhôngURL hình ảnh tham chiếu (hình ảnh thành hình ảnh).
countIntegerKhôngSố hình ảnh (≥0).
resolutionStringKhôngĐộ phân giải (xem /v1/image-models).
ratioStringKhôngTỷ lệ khung hình.
callbackUrlStringKhôngURL webhook cấp tác vụ.
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"}
}

Phản hồi lỗi:

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

Poll một tác vụ tạo hình ảnh. status là pending / success / failed. images là một mảng URL hình ảnh được chuỗi hóa JSON; text mang theo bất kỳ mô tả văn bản nào được mô hình đính kèm (vd. đầu ra đa phương thức Gemini), null nếu không có.

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

Các trường phản hồi data:

TrườngKiểuMô tả
taskIdStringID tác vụ.
statusStringpending / success / failed.
errorMessageStringLý do thất bại, null nếu thành công.
imagesStringMảng URL hình ảnh được chuỗi hóa JSON, vd. "[\"https://.../1.png\"]".
textStringMô tả văn bản do mô hình đính kèm (vd. đầu ra đa phương thức Gemini); null nếu không có.

Không tìm thấy tác vụ:

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

Nếu callbackUrl được cung cấp khi gửi, máy chủ sẽ đẩy kết quả cuối cùng success / failed qua webhook với cùng cấu trúc data.

Ví dụ hoàn chỉnh (gửi + poll)

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

Gửi không đồng bộ một tác vụ tạo video. Trả về taskId ngay lập tức; truy xuất kết quả bằng cách polling GET /v1/video-generations/{taskId} hoặc qua webhook callbackUrl.

Các giá trị model, videoType được phép, phạm vi thời lượng (videoDurationMin/Max), resolution / ratio được hỗ trợ, và giới hạn tải lên tài sản tham chiếu (fileMax) phải được lấy từ GET /v1/video-models trước. Chỉ các mã videoType được liệt kê trong allowedVideoTypes của mô hình đó mới được chấp nhận.

TrườngKiểuBắt buộcMô tả
textStringCóPrompt.
modelStringCóTên mô hình.
videoTypeIntegerCó1 văn bản thành video / 2 hình ảnh thành video (khung đầu) / 3 hình ảnh thành video (khung đầu+cuối) / 4 hình ảnh thành video (tham chiếu) / 5 tất cả tham chiếu.
imageUrlsString[]KhôngURL tài sản hình ảnh.
videoUrlsVideoUrl[]|String[]KhôngURL tài sản video.
audioUrlsString[]KhôngURL tài sản âm thanh.
resolutionStringKhôngĐộ phân giải.
ratioStringKhôngTỷ lệ khung hình.
durationLongKhôngGiây (>0).
callbackUrlStringKhôngURL webhook cấp tác vụ.

Ví dụ cho từng videoType:

1. Văn bản thành video (videoType=1)

Tạo video chỉ từ prompt văn bản; không cần tài sản tham chiếu.

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. Hình ảnh thành video - khung đầu (videoType=2)

Cung cấp một khung hình bắt đầu đơn trong imageUrls; mô hình tạo video bắt đầu từ khung hình đó.

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. Hình ảnh thành video - khung đầu và khung cuối (videoType=3)

Cung cấp cả khung đầu và khung cuối trong imageUrls (thứ tự: [đầu, cuối]); mô hình tạo video chuyển tiếp giữa hai khung hình.

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. Hình ảnh thành video - tham chiếu (videoType=4)

Cung cấp một hoặc nhiều hình ảnh tham chiếu trong imageUrls; mô hình sử dụng phong cách/nội dung của chúng làm tham chiếu (không phải là khung đầu/cuối bắt buộc) để tạo video.

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. Tất cả tham chiếu (videoType=5)

Tham chiếu hình ảnh / video / âm thanh hỗn hợp. Tham chiếu tài sản theo vị trí trong prompt: mục thứ 1 trong imageUrls là @图片 1, mục thứ 1 trong videoUrls là @视频 1, mục thứ 1 trong audioUrls là @音频 1. videoUrls cũng chấp nhận chuỗi URL đơn giản.

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

Phản hồi gửi (tất cả năm loại):

{
  "code": 200,
  "message": "success",
  "data": {"taskId": "vid_xxx"}
}

Retrieve Video GenerationGEThttps://api.basicrouter.ai/api/v1/video-generations/{taskId}

Poll một tác vụ tạo video. status là pending / success / failed; videoUrl là URL video đã tạo và lastFrameUrl là URL khung cuối (trong trường hợp hình ảnh thành video).

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

Các trường phản hồi data:

TrườngKiểuMô tả
statusStringpending / success / failed.
videoUrlStringURL video đã tạo.
lastFrameUrlStringURL khung cuối (trong trường hợp hình ảnh thành video); null nếu không có.
messageStringLý do thất bại, null nếu thành công.

Nếu callbackUrl được cung cấp khi gửi, máy chủ sẽ đẩy kết quả cuối cùng qua webhook với cùng cấu trúc data.

Ví dụ hoàn chỉnh (gửi + poll)

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

Trả về số dư tài khoản chia thành ba ví: gói tháng, gói tài nguyên và tín dụng trả theo mức dùng.

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

Các trường phản hồi:

TrườngKiểuMô tả
totalCreditBigDecimalTổng số dư.
totalResourceCreditBigDecimalTổng số dư các gói tài nguyên.
wallets.monthlyPlanWalletDetailGói tháng (null nếu không có).
wallets.resourcePacksWalletDetail[]Danh sách gói tài nguyên.
wallets.payAsYouGoBigDecimalSố dư trả theo mức dùng.

Các trường WalletDetailVO:

TrườngKiểuMô tả
idStringID ví.
creditBigDecimalSố dư tín dụng.
nameStringTên ví.

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

Chi tiết thanh toán cuộc gọi mô hình phân trang, được chụp nhanh theo giá (priceSnapshotId), sắp xếp theo thời gian tạo đơn hàng giảm dần. Chỉ các bản ghi tính phí bình thường (reason = model usage) được trả về.

Tham số truy vấn:

Tham sốKiểuBắt buộcMặc địnhMô tả
pageIntegerKhông1Số trang, bắt đầu từ 1.
sizeIntegerKhông20Kích thước trang (phân trang theo priceSnapshotId).
startTimeLocalDateTimeKhông—Thời gian bắt đầu, định dạng yyyy-MM-ddTHH:mm:ss, lọc theo snapshot orderCreatedAt.
endTimeLocalDateTimeKhông—Thời gian kết thúc, định dạng 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"

Bọc phản hồi:

{
  "code": 0,
  "message": "success",
  "data": { ... }
}
TrườngKiểuMô tả
recordsUsageDetailVO[]Bản ghi trang hiện tại.
totalLongTổng số.
currentLongTrang hiện tại.
sizeLongKích thước trang.
pagesLongTổng số trang.

Các trường UsageDetailVO:

TrườngKiểuMô tả
priceSnapshotIdStringID snapshot giá.
taskIdStringID tác vụ.
creditBigDecimalSố tiền tính phí.
modelStringTên mô hình.
modelTypeStringtext / image / video.
inputTokensLongToken đầu vào; null với image/video.
outputTokensLongToken đầu ra.
totalTokensLongTổng token.
cacheReadTokensLongToken đọc cache.
cacheWriteTokensLongToken ghi cache.
imageCountIntegerSố lượng hình ảnh; đặt cho mô hình hình ảnh.
imageResolutionStringĐộ phân giải hình ảnh, vd. 720P.
imageRatioStringTỷ lệ khung hình hình ảnh, vd. 1:1.
videoResolutionStringĐộ phân giải video, vd. 1080p.
videoRatioStringTỷ lệ khung hình video, vd. 16:9.
videoDurationSecLongThời lượng video tính bằng giây.
orderCreatedAtLocalDateTimeThời gian tạo đơn hàng (snapshot orderCreatedAt).
creditDetailsCreditDetailItem[]Chi tiết đơn hàng trong snapshot này (từ credit_order_t).

Các trường CreditDetailItem:

TrườngKiểuMô tả
creditBigDecimalSố tiền tính phí bởi đơn hàng này.
deductionSourceStringNguồn khấu trừ (Balance / Monthly Package / Resource Package).
packageNameStringTên gói; null nếu không có gói.

Quy ước giá trị null: chỉ các trường liên quan đến từng modelType mới được điền; các trường còn lại là null. text điền các trường token; image điền imageCount/imageResolution/imageRatio; video điền videoResolution/videoRatio/videoDurationSec.

Ví dụ phản hồi:

{
  "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

Danh sách phân trang các giao dịch nạp tiền đã thanh toán (status=2) của người dùng hiện tại, sắp xếp theo created_at giảm dần.

Tham sốKiểuBắt buộcMặc địnhMô tả
pageIntegerKhông1Số trang.
sizeIntegerKhông20Kích thước trang.
startTimeStringKhông—Thời gian bắt đầu, yyyy-MM-dd HH:mm:ss, bao gồm.
endTimeStringKhông—Thời gian kết thúc, yyyy-MM-dd HH:mm:ss, bao gồm.
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"

Bọc phản hồi:

{
  "code": 0,
  "message": "success",
  "data": { ... }
}
TrườngKiểuMô tả
recordsTransactionVO[]Giao dịch trang hiện tại.
totalLongTổng số.
currentLongTrang hiện tại.
sizeLongKích thước trang.
pagesLongTổng số trang.

Các trường TransactionVO:

TrườngKiểuMô tả
orderNoStringMã đơn hàng.
thirdPartyOrderNoStringMã đơn hàng bên thứ ba.
amountBigDecimalSố tiền đơn hàng.
actualAmountBigDecimalSố tiền thực tế đã thanh toán.
discountBigDecimalSố tiền chiết khấu.
paymentMethodStringPhương thức thanh toán (wechat / alipay / ustd / stripe / wallyt v.v.).

Các trường TransactionVO (tiếp theo):

TrườngKiểuMô tả
serviceFeeAmountBigDecimalSố tiền phí dịch vụ.
paymentChannelStringNền tảng thanh toán.
sourceStringNguồn đơn hàng (recharge / package_purchase v.v.).
packageNameStringTên gói (đặt cho mua gói; null cho nạp tiền thông thường).
createdAtLocalDateTimeThời gian tạo.
{
  "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
  }
}