BasicRouter Docs
Quickstart
BasicRouter gives production teams one stable API for model access, routing, fallback, usage tracking, and credit-based billing. LLM token supply is sourced from trusted enterprise cloud original-provider accounts, with privacy protection, high stability, and request traceability built into the gateway.
https://api.basicrouter.ai/apihttps://api.basicrouter.ai/api/v1https://api.basicrouter.ai/api/v1Authorization: Bearer <key>Create an API key
Create a BasicRouter API key in the console. Keep the key on your server and never expose it in browser or mobile client code.
Recommended key strategy:
| Key type | Recommended usage |
|---|---|
| Development key | Local development, staging, testing, and prototypes. |
| Production key | Backend production workloads only. |
| Integration key | Dedicated key for tools such as Cursor, Claude Code, Codex, Hermes, or OpenClaw. |
| Customer / tenant key | Optional key isolation for enterprise customers, tenant traffic, or business units. |
Rotate keys when team access changes. Revoke keys that are no longer used.
Point your SDK at BasicRouter
Most OpenAI-compatible clients only need a new base URL and API key.
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.BASICROUTER_API_KEY,
baseURL: "https://api.basicrouter.ai/api/v1"
});
Send a chat completion
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": "claude-sonnet-5",
"messages": [
{ "role": "user", "content": "Explain BasicRouter in one sentence." }
]
}'
Check usage and balance
curl --request GET \
--url https://api.basicrouter.ai/api/v1/billing/balance \
--header "Authorization: Bearer $BASICROUTER_API_KEY"
Model Discovery
Use the Models page or the Models API to inspect available text models. Model metadata includes vendor, serving provider, modality, context length, supported API families, supported capabilities, availability, account-level limits, and credit pricing.
Endpoint: GET /v1/models Purpose: List
models available to the current account.
curl --request GET \
--url https://api.basicrouter.ai/api/v1/models \
--header "Authorization: Bearer $BASICROUTER_API_KEY"
Capability matrix
| Capability | Description | Commonly used by |
|---|---|---|
streaming | Supports server-sent event streaming. | Chat apps, coding agents, real-time UX. |
tool_calling | Supports tool or function calling. | Agents, workflow automation, coding assistants. |
structured_outputs | Supports schema-constrained or JSON outputs. | Data extraction, workflow automation, enterprise apps. |
json_mode | Can return JSON-formatted output. | Lightweight structured responses. |
vision | Accepts image input. | Multimodal chat, UI analysis, document screenshots. |
prompt_caching | Supports cached input or context reuse. | Long-context agents, repeated system prompts. |
reasoning | Supports explicit reasoning controls where available. | Complex planning, coding, analysis workflows. |
logprobs | Supports token probability output. | Evaluation, ranking, advanced NLP workflows. |
API family compatibility matrix
| API family | Text | Vision input | Tool calling | Structured output | Streaming | Notes |
|---|---|---|---|---|---|---|
| OpenAI Chat Completions | Yes | Model-dependent | Model-dependent | Model-dependent | Yes | Best default for OpenAI-compatible agents and SDKs. |
| OpenAI Responses | Yes | Model-dependent | Model-dependent | Model-dependent | Yes | Recommended for newer OpenAI-style agent workflows. |
| Anthropic Messages | Yes | Model-dependent | Model-dependent | Model-dependent | Yes | Best for Claude-compatible clients and Claude Code. |
| BasicRouter image generation | No | Model-dependent | No | No | No | Uses async task polling or webhook. |
| BasicRouter video generation | No | Model-dependent | No | No | No | Uses async task polling or webhook. |
Authentication
Every API request uses a bearer token. Store keys in server-side environment variables, rotate them when team access changes, and log request IDs for debugging.
| Header | Value | Notes |
|---|---|---|
Authorization | Bearer YOUR_API_KEY | Required for every request. |
Content-Type | application/json | Required for JSON request bodies. |
Key security recommendations
- Keep API keys on the server. Do not expose keys in browser or mobile client code.
- Use separate keys for development, staging, production, and third-party integrations.
- Scope keys by environment, service, customer, or tenant when available.
- Rotate keys after employee departures, vendor access changes, or suspected leakage.
- Store keys in secret managers or environment variables, not source code.
Coding Agents
BasicRouter works with coding agents and AI development tools that support
OpenAI-compatible or Anthropic-compatible API endpoints. Use routing aliases such as
mwf/coding-auto so BasicRouter can route to the best available coding
model without requiring developers to change tool configuration.
Generic OpenAI-compatible setup
Use this setup for Cursor, Codex, Hermes, OpenClaw, Continue, Aider, Cline, LangChain-based agents, LlamaIndex-based agents, and custom OpenAI-compatible agent runtimes.
export OPENAI_BASE_URL="https://api.basicrouter.ai/api/v1"
export OPENAI_API_KEY="$BASICROUTER_API_KEY"
export OPENAI_MODEL="mwf/coding-auto"
Generic Anthropic-compatible setup
Use this setup for Claude-compatible clients and tools that expect Anthropic Messages format.
export ANTHROPIC_BASE_URL="https://api.basicrouter.ai/api/anthropic"
export ANTHROPIC_API_KEY="$BASICROUTER_API_KEY"
export ANTHROPIC_MODEL="mwf/coding-auto"
Recommended agent models
| Use case | Recommended alias | Requirements |
|---|---|---|
| General coding | mwf/coding-auto | Tool calling, streaming, strong coding ability. |
| Fast coding chat | mwf/coding-fast | Low latency and streaming. |
| Large repo analysis | mwf/coding-long | Long context and stable output. |
| Cost-sensitive coding assistant | mwf/low-cost | Lower price and acceptable coding quality. |
| UI screenshot / vision coding | mwf/vision-chat | Vision input and text output. |
Cursor quick guide
Use the OpenAI-compatible endpoint.
Base URL: https://api.basicrouter.ai/api/v1
API Key: BASICROUTER_API_KEY
Model: mwf/coding-auto
Recommended steps:
- Open Cursor settings.
- Add or enable OpenAI-compatible API key configuration.
- Set the OpenAI base URL override to
https://api.basicrouter.ai/api/v1. - Add a custom model such as
mwf/coding-auto,mwf/coding-fast, ormwf/coding-long. - Use a model that supports streaming and tool calling for best agent behavior.
Troubleshooting:
| Issue | Suggested fix |
|---|---|
| Model not shown | Add the model name manually as a custom model. |
| Tool calling fails | Use a model with tool_calling: true in the Models page. |
| Streaming interrupted | Retry with backoff or use a routing alias with fallback. |
| 401 error | Check the API key and base URL. |
| 404 model error | Confirm the model is enabled for the account. |
Claude Code quick guide
Use the Anthropic-compatible gateway endpoint.
export ANTHROPIC_BASE_URL="https://api.basicrouter.ai/api/anthropic"
export ANTHROPIC_API_KEY="$BASICROUTER_API_KEY"
export ANTHROPIC_MODEL="mwf/coding-auto"
BasicRouter supports this Anthropic-compatible path for Claude Code and Anthropic SDK compatibility:
POST /api/v1/messages
Recommended requirements:
| Requirement | Reason |
|---|---|
| Anthropic Messages-compatible request shape | Claude Code expects Anthropic-style messages. |
| Streaming support | Claude Code relies on streaming UX. |
| Tool calling support | Required for agentic coding workflows. |
| Long context | Useful for repository-level tasks. |
| Stable fallback | Useful for long-running coding sessions. |
Codex quick guide
Use BasicRouter as a custom OpenAI-compatible model provider.
Example provider configuration:
[model_providers.basicrouter]
name = "BasicRouter"
base_url = "https://api.basicrouter.ai/api/v1"
env_key = "BASICROUTER_API_KEY"
wire_api = "responses"
model_provider = "basicrouter"
model = "mwf/coding-auto"
Environment variable:
export BASICROUTER_API_KEY="br_xxx"
Recommended models:
| Model | Use case |
|---|---|
mwf/coding-auto | Default coding agent model. |
mwf/coding-long | Large repository context. |
mwf/coding-fast | Fast iteration and small changes. |
Troubleshooting:
| Issue | Suggested fix |
|---|---|
| Auth error | Confirm env_key points to BASICROUTER_API_KEY. |
| Model not found | Add the alias in BasicRouter Console or use a direct model ID. |
| Responses API error | Use wire_api = "responses" only for models and endpoints
that support Responses. |
| Chat Completions-only model | Switch to a chat-compatible wire API if the client supports it. |
Hermes quick guide
Use the OpenAI-compatible endpoint unless your Hermes deployment is configured for another protocol.
export OPENAI_BASE_URL="https://api.basicrouter.ai/api/v1"
export OPENAI_API_KEY="$BASICROUTER_API_KEY"
export OPENAI_MODEL="mwf/coding-auto"
Recommended model policy:
| Hermes workload | Model |
|---|---|
| General code generation | mwf/coding-auto |
| Low-latency task execution | mwf/coding-fast |
| Long-context repo scan | mwf/coding-long |
| Cost-sensitive background tasks | mwf/low-cost |
OpenClaw quick guide
Use the OpenAI-compatible endpoint for OpenAI-style agent runtime configuration.
export OPENAI_BASE_URL="https://api.basicrouter.ai/api/v1"
export OPENAI_API_KEY="$BASICROUTER_API_KEY"
export OPENAI_MODEL="mwf/coding-auto"
If OpenClaw supports multiple providers, configure BasicRouter as an OpenAI-compatible provider and use BasicRouter routing aliases for model selection.
{
"provider": "openai-compatible",
"base_url": "https://api.basicrouter.ai/api/v1",
"api_key_env": "BASICROUTER_API_KEY",
"model": "mwf/coding-auto"
}
Agent compatibility checklist
| Capability | Required for |
|---|---|
| Streaming | Good terminal/editor UX. |
| Tool calling | Agentic coding, file edits, command execution. |
| Long context | Large repositories and multi-file changes. |
| Structured outputs | Planning, task decomposition, automated workflows. |
| Vision input | UI screenshot analysis and design-to-code workflows. |
| Fallback | Production stability and long-running tasks. |
Using the Console
The BasicRouter Console is the operational control plane for API access, model availability, routing policies, usage visibility, and billing administration. It gives account administrators a centralized view of keys, models, requests, credits, and account-level controls for production model traffic.
Managing API keys
Create, rotate, revoke, and label API keys from the console. Use separate keys for development, staging, production, and individual services so usage can be audited and isolated by environment or application.
| Practice | Description |
|---|---|
| Separate environments | Use different API keys for development, staging, and production traffic. |
| Use descriptive labels | Label keys by application, service, environment, or integration. |
| Rotate regularly | Rotate keys when access changes or credentials may have been exposed. |
| Avoid client-side exposure | Keep API keys on server-side systems only. Do not expose keys in browser or mobile client code. |
| Monitor key usage | Review request volume, credit consumption, and error patterns by key. |
Model list
Use the Models page to review models available to the account. Each model entry may include vendor, serving provider, modality, supported API families, context length, capability flags, availability status, and pricing information.
| Filter | Purpose |
|---|---|
| Vendor | Filter by model vendor such as OpenAI, Anthropic, Google, Qwen, DeepSeek, or other providers. |
| Provider | Filter by serving provider or cloud provider. |
| Modality | Filter by text, image, video, embedding, audio, or multimodal support. |
| Capability | Filter by streaming, tool calling, structured outputs, vision, prompt caching, or reasoning support. |
| Availability | Identify models that are currently available to the account. |
For production applications, verify model capabilities before enabling traffic. Some parameters and features are model-dependent and may not be supported across all API families.
Usage & logs
The Usage & Logs view provides operational visibility into API traffic. Teams can inspect request volume, selected models, resolved routing targets, credit consumption, latency, error codes, and request IDs.
- Troubleshoot failed requests.
- Identify high-cost workloads.
- Compare model usage across applications and environments.
- Validate routing and fallback behavior.
- Investigate latency or provider availability issues.
- Provide request IDs when contacting support.
Each API response includes or exposes a BasicRouter request ID. Store this ID in your application logs to make production debugging and support escalation more efficient.
Fallback
Fallback is BasicRouter's resilience mechanism. When the primary model or routing policy fails, the system automatically switches to a backup model to keep processing the request. This keeps your application responsive and minimizes the risk of service disruption.
Fallback acts like a safety net, keeping your application running smoothly even when a model failure, quota limit, or network fluctuation occurs.
Why fallback matters
In production, model services can run into a number of unpredictable issues:
- Model service failure: the upstream API becomes temporarily unavailable or times out.
- Performance fluctuation: high model load leads to slow or failed responses.
- Routing failure: all candidate models selected by smart routing become unavailable.
Fallback keeps your application available by providing a reliable backup path.
Core advantages
| Advantage | Description |
|---|---|
| High availability | Automatic failover keeps the service running and reduces the impact of outages. |
| Transparent switching | The system switches models automatically — no application code changes required. |
| Flexible configuration | Supports both per-request and account-level configuration for different use cases. |
| Cost optimization | Choose a more cost-effective model as the fallback to control emergency costs. |
| Centralized management | Configure once at the account level and it applies automatically to every request. |
Global fallback model configuration
BasicRouter supports setting a global fallback model from the console backend. All requests automatically use this model as a backup when they fail.
How to configure it:
- Go to the BasicRouter strategy settings page.
- Find the Default Fallback Model setting.
- Select your global fallback model from the dropdown list.
- Save the setting to apply it immediately.
Advantages of global configuration:
- No code changes required: configure once and it applies globally, with no need to repeat the setting on every request.
- Centralized management: manage the fallback policy in one place for easier adjustment and monitoring.
- Simplified maintenance: reduces code complexity and the chance of configuration errors.
- Flexible override: request-level fallback configuration takes priority and can override the global setting for specific scenarios.
Request-level fallback configuration
For specific business scenarios, you can specify a fallback model on an individual request to override the global configuration.
Specify the fallback model with the router.fallBackModels parameter:
{
"model": "claude-sonnet-4",
"messages": [
{
"role": "user",
"content": "Explain what quantum computing is"
}
],
"router": {
"fallBackModels": ["glm-5.2"]
}
}
Priority rules
When multiple fallback configurations are present, priority runs from highest to lowest:
- Request-level
router.fallBackModels: the fallback model specified on an individual request. - Global Default Fallback Model: the global fallback model configured in the console.
- No fallback: if neither is configured, the request returns an error on failure.
- If all fallback models fail, the system returns the failure reason from the last model attempted.
- When a fallback occurs, the response indicates the model actually used, making it easy to monitor and analyze.
Account administration
Depending on account type, the console may include account-level model enablement, reseller or distributor controls, billing configuration, and access settings. Administrators can use these controls to align model access, usage visibility, and billing responsibility with applications, customer accounts, or business units.
Production operations checklist
| Item | Recommendation |
|---|---|
| API keys | Use dedicated production keys with clear labels. |
| Models | Confirm model availability, pricing, context length, and required capabilities. |
| Routing | Configure routing aliases or fallback policies for critical workloads. |
| Logs | Ensure request IDs are captured in application logs. |
| Billing | Confirm wallet balance, plan status, and credit deduction rules. |
| Rate limits | Review account-level RPM, TPM, concurrency, and media task limits. |
| Alerts | Monitor usage growth, credit balance, errors, and provider availability. |
Billing & Credits
BasicRouter uses a credit-based billing model across text, image, video, and other supported model workloads. Credits provide a unified unit for multi-model and multi-provider usage so teams can manage consumption consistently across modalities and API families.
Detailed model pricing is available on the Models page or through model metadata APIs. Pricing may vary by model, provider, modality, resolution, token type, output length, task duration, account type, and commercial agreement.
Top up & wallet
Accounts may add pay-as-you-go wallet credits for flexible usage. Wallet credits are used after monthly plan credits and resource packs have been consumed, unless a custom billing rule applies to the account.
Wallet credits do not expire unless otherwise specified in applicable commercial terms. Service fee is charged when recharging the pay-as-you-go wallet.
Monthly plans and resource packs
Each user or account can select one active monthly plan. Monthly plans provide a defined amount of usage capacity, commercial terms, and account-level access configuration for the billing period.
Users can also buy multiple resource packs for additional usage capacity. Resource packs can separate committed usage from pay-as-you-go wallet balance and are useful for high-volume text, image, video, or dedicated workload usage.
Deduction order
Unless custom billing rules are configured, credits are deducted in the following order:
| Priority | Credit source | Description |
|---|---|---|
| 1 | Monthly plan | Included monthly usage capacity is consumed first. |
| 2 | Resource packs | Additional purchased packs are consumed after monthly plan credits. |
| 3 | Pay-as-you-go wallet | Wallet balance is consumed after plan and resource pack credits. |
For accounts with custom commercial terms, deduction order, expiration rules, included usage, and pricing may differ. Account-specific rules are shown in the console or provided through the commercial agreement.
Custom pricing
Pricing can be customized for each user or account. Enterprise customers, reseller accounts, distributor accounts, and high-volume customers may be eligible for custom pricing. Contact sales for a quote.
Custom pricing can be configured by account, model, provider, modality, region, usage volume, or commercial agreement. When custom pricing is enabled, the console and billing APIs reflect account-specific pricing and deduction rules where available.
Pricing units
Different model modalities use different measurement units. BasicRouter converts these units into credits according to the model’s pricing rules.
| Modality | Common pricing basis |
|---|---|
| Text | Input tokens, output tokens, cached read tokens, cached write tokens, reasoning tokens, or model-specific token categories. |
| Image | Model, resolution, number of generated images, input image usage, editing mode, or quality setting. |
| Video | Model, output resolution, generated seconds, aspect ratio, input image or video usage, and task type. |
| Embeddings | Input tokens or number of embedding records. |
| Audio | Input duration, output duration, transcription length, or model-specific audio units. |
Pricing units may vary by model. Always refer to the model detail page or pricing metadata before enabling a model in production.
Usage attribution
BasicRouter usage can be reviewed by account, API key, model, modality, or time range. This allows teams to attribute cost to applications, environments, customers, or internal business units.
| Dimension | Description |
|---|---|
| API key | Group usage by application, service, or environment. |
| Model | Compare cost and volume by selected model. |
| Resolved model | Review the actual model used after routing or fallback. |
| Modality | Separate text, image, video, embedding, and audio usage. |
| Time range | Review daily, monthly, or custom reporting periods. |
| Metadata | Group usage by custom request metadata such as customer ID, tenant ID, user ID, or environment. |
Credit balance
Check how many credits are available across your account. The balance is split into three wallets that are deducted in order: the monthly plan allowance, purchased resource packs, and the pay-as-you-go wallet. A combined resource total (monthly plan + resource packs, excluding pay-as-you-go) is also available for tracking included usage separately from top-up spending.
To retrieve this programmatically, see
GET /v1/billing/balance in the API
Reference.
Usage details
Review a paginated, chronological list of individual usage records for reporting, monitoring, and internal cost allocation. Each record shows the model, model type (text, image, or video), the credits deducted, and a breakdown of which wallet each deduction was drawn from. Results can be filtered to a specific time range.
To retrieve this programmatically, see
GET /v1/usage in the API Reference.
Transaction history
Use transaction history to review credit movements, including top-ups, plan allocations, resource pack grants, usage deductions, adjustments, and administrative corrections.
To retrieve this programmatically, see
GET /v1/billing/transactions in the API
Reference.
Failed requests and refunds
Validation errors, authentication errors, and permission errors are generally not billed because no model execution occurs. Requests that reach an upstream model or generate partial output may consume credits depending on the model, provider, and response state.
For async image and video tasks, billing behavior depends on whether the task was accepted, started, completed, failed, or cancelled. The task detail response includes usage information when credits have been consumed.
Top-ups, monthly plans, resource packs, and consumed credits are non-refundable unless otherwise specified in the applicable commercial agreement or required by law.
API Reference
Common conventions
Base URL
All endpoints are served under the /v1 prefix.
Authentication
Calls to /v1/* endpoints use API Key authentication (not
JWT). The API Key is passed via the following header:
| Header | Format | Description |
|---|---|---|
Authorization | Bearer <api_key> | OpenAI-style. The Anthropic-compatible endpoint also accepts
x-api-key with anthropic-version: 2023-06-01. |
Missing or invalid keys return 401.
Balance pre-check
All model-calling endpoints run a balance pre-check before execution:
- Insufficient balance returns
Insufficient credit, mapped to:- OpenAI protocol: HTTP
400,code = insufficient_quota - Anthropic protocol: HTTP
402,type = billing_error
- OpenAI protocol: HTTP
- Some endpoints also estimate a minimum cost per model for a second pre-check.
POST https://api.basicrouter.ai/api/v1/chat/completions
OpenAI Chat Completions-compatible endpoint. Supports streaming and non-streaming, tool calls, JSON mode, and multimodal input.
| Field | Type | Required | Description |
|---|---|---|---|
model | String | Yes | Model name. |
messages | Message[] | Yes | Conversation messages. |
stream | Boolean | No | Stream mode, default false. |
temperature | Double | No | Sampling temperature. |
max_tokens | Integer | No | Maximum output tokens. |
top_p | Double | No | Nucleus sampling. |
presence_penalty | Double | No | — |
frequency_penalty | Double | No | — |
tools | Tool[] | No | Tool definitions. |
tool_choice | String|Object | No | auto / none / required / specific
function. |
response_format | Object | No | {type, json_schema:{name,schema,strict}};
text/json_object/json_schema. |
parallel_tool_calls | Boolean | No | — |
metadata | Map | No | Pass-through metadata. |
Message fields:
| Field | Type | Description |
|---|---|---|
role | String | system / user / assistant /
tool. |
content | String|Array | Plain text or multimodal content block array
([{type:"text",text},{type:"image_url",image_url:{url}}]). |
tool_call_id | String | Links to the tool_calls when role=tool. |
tool_calls | ToolCall[] | Present when role=assistant makes tool calls. |
| Field | Type | Description |
|---|---|---|
type | String | Fixed function. |
function | Object | Function definition. |
function.name | String | Function name. |
function.description | String | Function description. |
function.parameters | Object | JSON Schema for inputs. |
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}
}
Response fields (non-streaming):
| Field | Type | Description |
|---|---|---|
id | String | Completion id. |
object | String | Fixed chat.completion. |
created | Long | Created timestamp (seconds). |
model | String | Model name. |
choices | Choice[] | {index, message:{role, content, tool_calls?}, finish_reason}. |
usage | Object | {prompt_tokens, completion_tokens, total_tokens}. |
| Field | Type | Description |
|---|---|---|
id | String | Tool call id. |
type | String | Fixed function. |
function | Object | Function call details. |
function.name | String | Function name. |
function.arguments | Object | Function arguments. |
Streaming response example:
data: {"object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant","content":"..."}}]}
data: {"object":"chat.completion.chunk","choices":[{"delta":{"content":"..."}}]}
data: [DONE]
POST https://api.basicrouter.ai/api/v1/responses
OpenAI Responses-compatible endpoint. Uses input instead of
messages, instructions instead of a system message, and a
text block instead of response_format.
| Field | Type | Required | Description |
|---|---|---|---|
model | String | Yes | Model name. |
input | String|Array | Yes | Plain string (user message) or message object array. |
instructions | String | No | System prompt. |
stream | Boolean | No | Default false. |
max_output_tokens | Integer | No | Maximum output tokens. |
temperature | Double | No | Default 1. |
top_p | Double | No | — |
tools | Tool[] | No | Top-level {type, name, description, parameters}. |
tool_choice | String|Object | No | auto/none/required/{type,name}. |
text | Object | No | {format:{type, name, schema, strict}};
text/json_object/json_schema. |
metadata | Map | No | — |
previous_response_id | String | No | Previous response id for multi-turn. |
parallel_tool_calls | Boolean | No | — |
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}
}
Response fields (non-streaming):
| Field | Type | Description |
|---|---|---|
id | String | Response id. |
object | String | Fixed response. |
model | String | Model name. |
status | String | e.g. completed. |
created_at | Long | Created timestamp (seconds). |
output | Array | Output items. Message items:
{id, type:"message", role, content:[{type:"output_text",
text}], status}. Tool-call items:
{type:"function_call", id, name, call_id, arguments, status}. |
usage | Object | {input_tokens, output_tokens, total_tokens}. For Claude models,
input_tokens includes cache_read and
output_tokens includes cache_write. |
Streaming follows the Responses API events:
| Event | Description |
|---|---|
response.created | Start of the response stream. |
response.output_text.delta | Incremental text output update. |
response.completed | End of the response stream. |
POST https://api.basicrouter.ai/api/v1/messages
Anthropic Messages-compatible endpoint. Accepts x-api-key and
anthropic-version: 2023-06-01 headers. Content blocks support
text, image, tool_use, tool_result,
thinking, and redacted_thinking.
| Field | Type | Required | JSON field | Description |
|---|---|---|---|---|
model | String | Yes | model | Model name. |
messages | Message[] | Yes | messages | Conversation messages. |
system | String|Array | No | system | System prompt, string or [{type,text}]. |
maxTokens | Integer | Yes | max_tokens | Maximum output tokens. |
stream | Boolean | No | stream | Streaming. |
temperature | Double | No | temperature | — |
topP | Double | No | top_p | — |
topK | Integer | No | top_k | — |
tools | Tool[] | No | tools | Tool definitions (input_schema). |
toolChoice | Object | No | tool_choice | — |
metadata | Map | No | metadata | — |
thinking | Object | No | thinking | Extended thinking config. |
stopSequences | Object | No | stop_sequences | — |
anthropicBeta | Object | No | anthropic_beta | Beta feature header. |
| Field | Type | Description |
|---|---|---|
role | String | Message role, e.g. user / assistant. |
content | String|ContentBlock[] | Plain text or an array of content blocks. |
| Field | Type | Description |
|---|---|---|
type | String | One of text, image, tool_use,
tool_result, thinking,
redacted_thinking. |
text | String | Present when type is text. |
source | Object | Present when type is image. |
Image block examples:
{ "type": "image", "source": { "type": "base64", "media_type": "...", "data": "..." } }
{ "type": "image", "source": { "type": "url", "url": "..." } }
| Field | Type | Description |
|---|---|---|
name | String | Function name. |
description | String | Function description. |
input_schema | Object | JSON Schema for inputs. |
cache_control | Object | Optional cache control. |
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}
}
Response fields (non-streaming):
| Field | Type | Description |
|---|---|---|
id | String | Message id. |
type | String | Fixed message. |
role | String | Fixed assistant. |
model | String | Model name. |
content | ContentBlock[] | Response content blocks (e.g. {type:"text", text},
{type:"tool_use", ...}). |
stop_reason | String | e.g. end_turn, tool_use, max_tokens. |
usage | Object | {input_tokens, output_tokens}. |
| Event | Description |
|---|---|
message_start | Start of the message stream. |
content_block_start | Start of a new content block. |
content_block_delta | Incremental update for a content block. |
content_block_stop | End of a content block. |
message_delta | Incremental update for the message. |
message_stop | End of the message stream. |
GET https://api.basicrouter.ai/api/v1/models
Returns all online, enabled API models.
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
}
]
}
Each model entry (data[]) fields:
| Field | Type | Description |
|---|---|---|
id | String | Model id. |
object | String | Fixed model. |
display_name | String | Display name. |
created | Long | Created timestamp (seconds). |
owned_by | String | Owner / vendor. |
input_modalities | String[] | e.g. ["text","image"]. |
output_modalities | String[] | e.g. ["text"]. |
context_length | Integer | Maximum context length. |
GET https://api.basicrouter.ai/api/v1/models/{model}
Returns a single model with the same shape as a list entry. Returns HTTP 404 when the model does not exist.
curl --request GET \
--url https://api.basicrouter.ai/api/v1/models/gpt-5.5 \
--header "Authorization: Bearer $BASICROUTER_API_KEY"
Success response: a single model object with the same fields as a
/v1/models list entry.
When the model does not exist, returns HTTP 404:
{"error": {"message": "The model 'xxx' does not exist", "type": "invalid_request_error", "code": "invalid_model_error"}}
GET https://api.basicrouter.ai/api/v1/image-models
Query the resolutions, ratios, and maximum counts supported by an image model before
calling /v1/image-generations. No authentication required.
| Field | Type | Description |
|---|---|---|
id | String | Model id. |
object | String | Fixed image_model. |
displayName | String | Display name. |
description | String | Model description. |
icon | String | Icon URL. |
created | Long | Created timestamp (seconds). |
maxCount | Integer | Max images per request. |
fileMax | Integer | Max reference images. |
resolutions | String[] | Supported resolutions, e.g.
["720p","1080p"]. |
ratios | String[] | Supported aspect ratios, e.g.
["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"]
}
]
}
GET https://api.basicrouter.ai/api/v1/video-models
Query the supported videoType values, duration range, resolutions, and
ratios for a video model before calling /v1/video-generations. No
authentication required.
| Field | Type | Description |
|---|---|---|
id | String | Model id. |
object | String | Fixed video_model. |
displayName | String | Display name. |
description | String | Model description. |
icon | String | Icon URL. |
created | Long | Created timestamp (seconds). |
allowedVideoTypes | VideoTypeOption[] | Supported videoType list. |
videoDurationMin | Integer | Minimum seconds per clip. |
videoDurationMax | Integer | Maximum seconds per clip. |
videoDurationSuggest | Integer[] | Recommended duration steps, e.g. [5,8,10]. |
resolutions | String[] | Supported resolutions. |
ratios | String[] | Supported aspect ratios. |
resolutionOptions | ResolutionOption[] | Structured resolution+ratio+size combos. |
fileMax | Integer | Max reference assets. |
VideoTypeOption fields:
| Field | Type | Description |
|---|---|---|
code | Integer | The videoType value to pass to
/v1/video-generations. |
name | String | Localized type name (text-to-video / image-to-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
}
]
}
POST https://api.basicrouter.ai/api/v1/image-generations
Asynchronously submit an image generation task. Returns a taskId
immediately; retrieve the result by polling
GET /v1/image-generations/{taskId} or via a
callbackUrl webhook.
The model, supported resolution / ratio values,
count upper limit, and reference-image upload limit (fileMax)
must be obtained from
GET /v1/image-models first. Only values
advertised by that model's spec are accepted.
| Field | Type | Required | Description |
|---|---|---|---|
text | String | Yes | Prompt. |
model | String | Yes | Model name. |
imageUrls | String[] | No | Reference image URLs (image-to-image). |
count | Integer | No | Number of images (≥0). |
resolution | String | No | Resolution (see /v1/image-models). |
ratio | String | No | Aspect ratio. |
callbackUrl | String | No | Task-level 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"}
}
Error responses:
// Insufficient credit
{ "code": 500, "message": "Insufficient credit" }
// Model not found
{ "code": 404, "message": "Model not found: xxx" }
GET https://api.basicrouter.ai/api/v1/image-generations/{taskId}
Poll an image generation task. status is pending /
success / failed. images is a JSON-stringified
array of image URLs; text carries any model-attached text description (e.g.
Gemini multimodal output), null otherwise.
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
}
}
Response data fields:
| Field | Type | Description |
|---|---|---|
taskId | String | Task id. |
status | String | pending / success / failed. |
errorMessage | String | Failure reason, null on success. |
images | String | JSON-stringified array of image URLs, e.g.
"[\"https://.../1.png\"]". |
text | String | Model-attached text description (e.g. Gemini multimodal output);
null otherwise. |
Task not found:
{ "code": 500, "message": "task not found" }
If callbackUrl was supplied on submit, the server pushes the final
success / failed result via webhook with the same
data shape.
Complete example (submit + 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}")
POST https://api.basicrouter.ai/api/v1/video-generations
Asynchronously submit a video generation task. Returns a taskId
immediately; retrieve the result by polling
GET /v1/video-generations/{taskId} or via a
callbackUrl webhook.
The model, allowed videoType values, duration range
(videoDurationMin/Max), supported resolution /
ratio, and reference-asset upload limit (fileMax) must be
obtained from GET /v1/video-models first. Only
videoType codes listed in that model's
allowedVideoTypes are accepted.
| Field | Type | Required | Description |
|---|---|---|---|
text | String | Yes | Prompt. |
model | String | Yes | Model name. |
videoType | Integer | Yes | 1 text-to-video / 2 image-to-video (first frame) / 3 image-to-video (first+last frame) / 4 image-to-video (reference) / 5 all reference. |
imageUrls | String[] | No | Image asset URLs. |
videoUrls | VideoUrl[]|String[] | No | Video asset URLs. |
audioUrls | String[] | No | Audio asset URLs. |
resolution | String | No | Resolution. |
ratio | String | No | Aspect ratio. |
duration | Long | No | Seconds (>0). |
callbackUrl | String | No | Task-level webhook URL. |
Examples for each videoType:
1. Text to video (videoType=1)
Generate a video from a text prompt only; no reference assets needed.
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. Image to video - first frame (videoType=2)
Provide a single starting frame in imageUrls; the model generates a video
starting from that frame.
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. Image to video - first and last frame (videoType=3)
Provide both the first and last frame in imageUrls (order:
[first, last]); the model generates a transition video between the two
frames.
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. Image to video - reference (videoType=4)
Provide one or more reference images in imageUrls; the model uses their
style/content as reference (not as a forced first/last frame) to generate the 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. All reference (videoType=5)
Mixed image / video / audio references. Reference assets by position in the prompt: the
1st entry in imageUrls is @图片 1, the 1st in
videoUrls is @视频 1, the 1st in audioUrls is
@音频 1. videoUrls also accepts plain URL strings.
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
}'
Submit response (all five types):
{
"code": 200,
"message": "success",
"data": {"taskId": "vid_xxx"}
}
GET https://api.basicrouter.ai/api/v1/video-generations/{taskId}
Poll a video generation task. status is pending /
success / failed; videoUrl is the generated video
URL and lastFrameUrl is the last-frame URL (image-to-video scenarios).
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
}
}
Response data fields:
| Field | Type | Description |
|---|---|---|
status | String | pending / success / failed. |
videoUrl | String | Generated video URL. |
lastFrameUrl | String | Last-frame URL (image-to-video scenarios); null otherwise. |
message | String | Failure reason, null on success. |
If callbackUrl was supplied on submit, the server pushes the final result
via webhook with the same data shape.
Complete example (submit + 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']}")
GET https://api.basicrouter.ai/api/v1/billing/balance
Returns the account balance split into three wallets: monthly plan, resource packs, and pay-as-you-go credit.
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
}
}
Response fields:
| Field | Type | Description |
|---|---|---|
totalCredit | BigDecimal | Total balance. |
totalResourceCredit | BigDecimal | Sum of resource-pack balances. |
wallets.monthlyPlan | WalletDetail | Monthly plan (null if none). |
wallets.resourcePacks | WalletDetail[] | Resource pack list. |
wallets.payAsYouGo | BigDecimal | Pay-as-you-go balance. |
WalletDetailVO fields::
| Field | Type | Description |
|---|---|---|
id | String | Wallet id. |
credit | BigDecimal | Balance credits. |
name | String | Wallet name. |
GET https://api.basicrouter.ai/api/v1/usage
Paginated model-call billing details, snapshoted by price
(priceSnapshotId), ordered by order creation time descending. Only normal
charge records (reason = model usage) are returned.
Query parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | Integer | No | 1 | Page number, 1-based. |
size | Integer | No | 20 | Page size (paginated by priceSnapshotId). |
startTime | LocalDateTime | No | — | Start time, format yyyy-MM-ddTHH:mm:ss, filters by snapshot
orderCreatedAt. |
endTime | LocalDateTime | No | — | End time, format 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"
Response wrapper:
{
"code": 0,
"message": "success",
"data": { ... }
}
| Field | Type | Description |
|---|---|---|
records | UsageDetailVO[] | Current page records. |
total | Long | Total count. |
current | Long | Current page. |
size | Long | Page size. |
pages | Long | Total pages. |
UsageDetailVO fields:
| Field | Type | Description |
|---|---|---|
priceSnapshotId | String | Price snapshot id. |
taskId | String | Task id. |
credit | BigDecimal | Charged amount. |
model | String | Model name. |
modelType | String | text / image / video. |
inputTokens | Long | Input tokens; null for image/video. |
outputTokens | Long | Output tokens. |
totalTokens | Long | Total tokens. |
cacheReadTokens | Long | Cache-read tokens. |
cacheWriteTokens | Long | Cache-write tokens. |
imageCount | Integer | Image count; set for image models. |
imageResolution | String | Image resolution, e.g. 720P. |
imageRatio | String | Image aspect ratio, e.g. 1:1. |
videoResolution | String | Video resolution, e.g. 1080p. |
videoRatio | String | Video aspect ratio, e.g. 16:9. |
videoDurationSec | Long | Video duration in seconds. |
orderCreatedAt | LocalDateTime | Order creation time (snapshot orderCreatedAt). |
creditDetails | CreditDetailItem[] | Order details under this snapshot (from credit_order_t). |
CreditDetailItem fields:
| Field | Type | Description |
|---|---|---|
credit | BigDecimal | Amount charged by this order. |
deductionSource | String | Deduction source (Balance / Monthly Package /
Resource Package). |
packageName | String | Package name; null if no package. |
Null-value convention: only the fields relevant to each modelType are
populated; the rest are null. text populates the token fields;
image populates imageCount/imageResolution/imageRatio;
video populates
videoResolution/videoRatio/videoDurationSec.
Response example:
{
"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
}
}
GET https://api.basicrouter.ai/api/v1/billing/transactions
Paginated list of the current user's paid (status=2) recharge
transactions, ordered by created_at descending.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page | Integer | No | 1 | Page number. |
size | Integer | No | 20 | Page size. |
startTime | String | No | — | Start time, yyyy-MM-dd HH:mm:ss, inclusive. |
endTime | String | No | — | End time, yyyy-MM-dd HH:mm:ss, inclusive. |
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"
Response wrapper:
{
"code": 0,
"message": "success",
"data": { ... }
}
| Field | Type | Description |
|---|---|---|
records | TransactionVO[] | Current page transactions. |
total | Long | Total count. |
current | Long | Current page. |
size | Long | Page size. |
pages | Long | Total pages. |
TransactionVO fields:
| Field | Type | Description |
|---|---|---|
orderNo | String | Order number. |
thirdPartyOrderNo | String | Third-party order number. |
amount | BigDecimal | Order amount. |
actualAmount | BigDecimal | Actually paid amount. |
discount | BigDecimal | Discount amount. |
paymentMethod | String | Payment method (wechat / alipay / ustd /
stripe / wallyt etc.). |
TransactionVO fields:
| Field | Type | Description |
|---|---|---|
serviceFeeAmount | BigDecimal | Service fee amount. |
paymentChannel | String | Payment platform. |
source | String | Order source (recharge / package_purchase etc.). |
packageName | String | Package name (set for package purchases; null for plain
recharges). |
createdAt | LocalDateTime | Creation time. |
{
"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
}
}
Operational
Errors
BasicRouter returns stable error codes so applications can handle retries, fallbacks, billing issues, and debugging consistently.
Provider-compatible endpoints try to preserve the original API family's error shape where possible. BasicRouter-native endpoints use the BasicRouter error object.
HTTP status and error code mapping
| HTTP status | Error type | Example codes | Retry |
|---|---|---|---|
| 400 | invalid_request_error | invalid_request, unsupported_parameter,
invalid_messages, invalid_image_url | No |
| 401 | authentication_error | missing_api_key, invalid_api_key | No |
| 402 | billing_error | insufficient_credits, payment_required,
quota_exceeded | No |
| 403 | permission_error | model_access_denied, endpoint_access_denied,
key_scope_denied | No |
| 404 | not_found_error | model_not_found, response_not_found,
task_not_found | No |
| 408 | timeout_error | gateway_timeout, provider_timeout | Yes |
| 409 | conflict_error | idempotency_conflict, task_already_cancelled | Depends |
| 422 | validation_error | schema_validation_failed, unsupported_modality | No |
| 429 | rate_limit_error | account_rpm_exceeded, account_tpm_exceeded,
provider_rate_limited | Yes |
| 500 | internal_error | internal_error | Yes |
| 502 | provider_error | provider_bad_gateway, provider_invalid_response | Yes |
| 503 | service_unavailable | model_unavailable, provider_unavailable,
insufficient_capacity | Yes |
| 504 | timeout_error | provider_timeout, gateway_timeout | Yes |
Common error codes
| Code | Meaning | Recommended action |
|---|---|---|
missing_api_key | No API key was provided. | Add the Authorization header. |
invalid_api_key | API key is invalid or revoked. | Create or rotate the API key. |
model_not_found | Model ID does not exist or is not enabled for the account. | Check the Models page or call GET /v1/models. |
model_access_denied | API key or account does not have access to the model. | Enable the model or contact admin. |
unsupported_parameter | Request includes a parameter unsupported by the selected endpoint or model. | Remove the parameter or choose a compatible model. |
unsupported_modality | Input or output modality is not supported by the selected model. | Choose a model that supports the modality. |
account_rpm_exceeded | Account requests per minute limit exceeded. | Retry with backoff or request higher limits. |
account_tpm_exceeded | Account tokens per minute limit exceeded. | Retry with backoff, reduce tokens, or request higher limits. |
provider_rate_limited | Upstream provider rate limited the request. | Retry or enable fallback. |
insufficient_credits | Account has insufficient credits. | Top up wallet, buy a pack, or upgrade plan. |
provider_timeout | Upstream provider did not respond in time. | Retry or enable fallback. |
model_unavailable | Model is temporarily unavailable. | Retry or use a routing alias. |
content_policy_error | Request or output was blocked by a safety policy. | Modify input or choose a suitable workflow. |
Support
Get help with BasicRouter
Find answers to common API, billing, routing, and integration questions. For production issues, send the request ID, API key label, endpoint, model, and timestamp so the team can trace the request quickly.
FAQ
Click a question to expand the answer.
Contact
Choose the best inbox for the request.
For incidents, rate limits, billing questions, production routing issues, SDK migration, provider compatibility, endpoint design questions, enterprise plans, committed usage, or custom provider routing requirements.











