API reference
WorldRouter exposes an OpenAI-compatible /chat/completions endpoint. Any SDK or HTTP client that accepts a custom base URL can call it with no code changes. For image and video generation, see Media Generation.
New to WorldRouter? Run through the Quickstart first for an API key, the base URL, and a connection test. This page assumes you already have both.
Chat completions
Endpoint
POST https://inference-api-pre-d80ca3.worldrouter.ai/v1/chat/completionsAuthentication
Pass your API key as a Bearer token in the Authorization header:
Authorization: Bearer your_api_keyKeys are scoped to your account. Create and rotate them in the API Keys dashboard.
Request body
| Field | Required | Description |
|---|---|---|
model | yes | Model ID to route to, e.g. gpt-5.4. See the Models catalog. |
messages | yes | Array of chat messages. Must contain at least one entry. |
temperature | no | Sampling temperature. Defaults depend on the model. |
max_tokens | no | Upper bound on output tokens. On reasoning models the budget can be fully consumed by hidden reasoning tokens, which returns an empty content with finish_reason: "length". |
stream | no | When true, the response is a Server-Sent Events stream of deltas. |
tools / tool_choice | no | Function calling, same schema as OpenAI. Add a {"type":"worldrouter:web_search"} tool — or the :online model suffix — to ground answers in live web results. See Web search. |
Any other field in the OpenAI /chat/completions schema (top_p, stop, seed, response_format, …) is accepted unchanged.
Web search
WorldRouter can ground any model’s answer in live web results. There is no account-level toggle: search runs only when a request asks for it, and a request that doesn’t ask never incurs a search fee.
The simplest way to enable it is the :online model suffix:
{
"model": "qwen3.5-flash:online",
"messages": [
{ "role": "user", "content": "What changed in the latest release?" }
]
}For control over how searching behaves, add the tool explicitly instead:
{
"model": "qwen3.5-flash",
"messages": [
{ "role": "user", "content": "What changed in the latest release?" }
],
"tools": [
{
"type": "worldrouter:web_search",
"parameters": {
"max_uses": 3,
"max_results": 5,
"allowed_domains": ["worldrouter.ai"],
"excluded_domains": ["example.com"]
}
}
]
}The model decides when and how often to search: it may search, read the results, refine the query and search again, or answer without searching at all. Sources are cited as [1], [2], and so on.
| Parameter | Default | Description |
|---|---|---|
engine | auto | Which engine serves the search. auto uses the provider’s native search on models that have one (OpenAI models today) and WorldRouter’s search everywhere else. exa always uses WorldRouter’s search. native always uses the provider’s, and fails on models without one. |
max_uses | 3 | Most searches one request may run. Values above the server ceiling are lowered, not rejected. |
max_results | 5 | Results returned per search, up to 25. |
max_total_results | — | Cumulative cap on results across all searches in the request. |
allowed_domains / excluded_domains | — | Restrict results to, or keep them away from, up to 20 domains each. |
search_context_size | — | How much excerpt each result carries: low, medium, or high. |
max_characters | — | Exact per-result excerpt length; takes precedence over search_context_size. |
Migrating from OpenRouter? Requests written for its web search work here with
the tool type changed to worldrouter:web_search — the :online suffix, the
parameter names, and the plugins: [{ "id": "web" }] form are all accepted.
Pricing
WorldRouter searches cost $0.007 each, covering the first 10 results; results beyond 10 add $0.001 apiece. Fees appear in your usage history alongside the model call that used them — a multi-hop answer shows one row per search round, each labelled with its round number. That is itemization, not duplicate billing. When engine resolves to a provider’s native search, the provider’s own search pricing applies instead.
If your balance cannot cover the request’s worst case (max_uses × the per-search fee), the request is rejected with 402 before anything runs.
Citations
When WorldRouter’s search ran, the response carries the sources it used — annotations on the message, in the same url_citation shape OpenAI uses, and a search counter under usage:
{
"choices": [
{
"message": {
"content": "The latest release added ... [1]",
"annotations": [
{
"type": "url_citation",
"url_citation": {
"url": "https://worldrouter.ai/changelog",
"title": "Changelog",
"content": "…excerpt from the page…",
"start_index": 30,
"end_index": 33
}
}
]
}
}
],
"usage": {
"server_tool_use": { "web_search_requests": 1 }
}
}Response
A non-streaming response matches the OpenAI shape:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1738960610,
"model": "gpt-5.4",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Hello! How can I help you today?" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 13,
"completion_tokens": 9,
"total_tokens": 22
}
}Examples
curl https://inference-api-pre-d80ca3.worldrouter.ai/v1/chat/completions \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4",
"messages": [{ "role": "user", "content": "Hello" }]
}'from openai import OpenAI
client = OpenAI(
api_key="your_api_key",
base_url="https://inference-api-pre-d80ca3.worldrouter.ai/v1",
)
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
apiKey: "your_api_key",
baseURL: "https://inference-api-pre-d80ca3.worldrouter.ai/v1",
});
const response = await client.chat.completions.create({
model: "gpt-5.4",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content);Streaming
Set stream: true in the request body. The response becomes a Server-Sent Events stream. Each chunk follows the OpenAI chat.completion.chunk shape, and the stream terminates with a data: [DONE] line:
curl https://inference-api-pre-d80ca3.worldrouter.ai/v1/chat/completions \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4",
"stream": true,
"messages": [{ "role": "user", "content": "Hello" }]
}'from openai import OpenAI
client = OpenAI(
api_key="your_api_key",
base_url="https://inference-api-pre-d80ca3.worldrouter.ai/v1",
)
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)import OpenAI from "openai";
const client = new OpenAI({
apiKey: "your_api_key",
baseURL: "https://inference-api-pre-d80ca3.worldrouter.ai/v1",
});
const stream = await client.chat.completions.create({
model: "gpt-5.4",
messages: [{ role: "user", content: "Hello" }],
stream: true,
});
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}Error codes
| Code | Meaning | Fix |
|---|---|---|
| 400 | Invalid request (unknown model, malformed body, unsupported parameter) | Verify the model ID matches the Models page (IDs are case-sensitive) and check the request body against the field table above. |
| 401 | Invalid or missing API key | Check that your key is set correctly and has not been revoked in the dashboard. |
| 402 | Insufficient credits | Top up on the Credits page, then retry. |
| 429 | Rate limited | Back off and retry with exponential delay. Consider spreading load across models. |
| 500 | Server error | Retry the request. If it persists, try a different model or contact support. |
See also
- OpenAI Chat Completions reference : WorldRouter mirrors this schema.
- Media Generation: async image tasks, plus Seedance, Kling, and PixVerse video.
- Async image tasks: create image-generation jobs, poll status, and receive stored image URLs.
- Seedance video guide: async video generation with
/api/v3/contents/generations/tasks. - PixVerse video guide: async video generation with
/openapi/v2/video/.... - Models: full catalog with live pricing.
- Quickstart: API key, base URL, and first call.