# AI Tool Docs Entry
Source: https://docs.crazyrouter.com/en/ai-tools
Crazyrouter documentation entry points for Codex, Claude Code, ChatGPT, Cursor, and other AI tools
Use this page when you want an AI tool to read Crazyrouter documentation. Prefer these stable entry points.
## Recommended Entry Points
A compact index of key pages and summaries, useful when the AI should decide what to read next.
A single-file full documentation context for AI tools that can read URLs or pasted text.
Standard sitemap for search engines, crawlers, and custom indexing jobs.
Add `.md` to a documentation URL to read a single page as Markdown.
## Prompt for AI Tools
```text theme={null}
First read https://docs.crazyrouter.com/llms.txt to identify the relevant pages.
If full context is needed, read https://docs.crazyrouter.com/llms-full.txt.
For OpenAI-compatible clients, use base_url https://crazyrouter.com/v1 or https://cn.crazyrouter.com/v1.
For Claude Code / Anthropic-native clients, use the root domain and do not append /v1.
```
## Common Pages
| Use case | Docs |
| -------------------- | ----------------------------------------------------- |
| First integration | [Quick Start](/en/quickstart) |
| Base URLs and routes | [API Endpoints](/en/api-endpoint) |
| API keys | [Authentication](/en/authentication) |
| Claude Code | [Claude Code Setup](/en/integrations/claude-code) |
| Codex CLI | [Codex CLI Setup](/en/integrations/codex) |
| OpenAI Chat | [Create Chat Completion](/en/chat/openai/completions) |
| Claude Messages | [Claude Native Format](/en/chat/anthropic/messages) |
| Gemini Native | [Gemini Native Format](/en/chat/gemini/native) |
| Image generation | [GPT Image](/en/images/gpt-image) |
| Video generation | [Unified Video API](/en/video/unified) |
# API Endpoints
Source: https://docs.crazyrouter.com/en/api-endpoint
API endpoint addresses and reference
## API Base URL
```
https://crazyrouter.com
```
China-optimized API route:
```text theme={null}
https://cn.crazyrouter.com
```
The China route is for API requests only. Account login, billing, and the dashboard still use:
```text theme={null}
https://crazyrouter.com
```
## Which Base URL To Use
| Use case | Default global route | China-optimized route | Notes |
| -------------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| OpenAI-compatible SDKs / clients | `https://crazyrouter.com/v1` | `https://cn.crazyrouter.com/v1` | The client appends paths such as `/chat/completions` and `/models` |
| Claude Code / Anthropic-native clients | `https://crazyrouter.com` | `https://cn.crazyrouter.com` | The client appends `/v1/messages` itself, so do not add `/v1` manually |
| curl / raw HTTP requests | Full endpoint, for example `https://crazyrouter.com/v1/chat/completions` | Full endpoint, for example `https://cn.crazyrouter.com/v1/chat/completions` | Raw requests must include the full API path |
If logs show `/v1/v1/models`, `/v1/v1/messages`, or `/v1/messages/v1/messages`, the client is duplicating API paths. For Claude Code / Anthropic-native clients, reset the base URL to the root domain. For OpenAI-compatible clients, keep only the `/v1` base URL.
## Main Endpoints
### Chat API
| Endpoint | Method | Description |
| ---------------------- | ------ | ----------------------- |
| `/v1/chat/completions` | POST | OpenAI Chat format |
| `/v1/messages` | POST | Anthropic Claude format |
| `/v1/responses` | POST | OpenAI Responses API |
| `/v1/completions` | POST | Legacy Completions |
### Gemini Native Format
| Endpoint | Method | Description |
| ---------------------------------------------- | ------ | -------------------- |
| `/v1beta/models/{model}:generateContent` | POST | Content generation |
| `/v1beta/models/{model}:streamGenerateContent` | POST | Streaming generation |
### Image API
| Endpoint | Method | Description |
| ---------------------------------------- | ------ | --------------------------- |
| `/v1/images/generations` | POST | OpenAI image generation |
| `/v1/images/edits` | POST | Image editing |
| `/mj/submit/imagine` | POST | Midjourney image generation |
| `/ideogram/v1/ideogram-v3/generate` | POST | Ideogram V3 |
| `/kling/v1/images/generations` | POST | Kling image generation |
| `/kling/v1/images/kolors-virtual-try-on` | POST | Kling virtual try-on |
### Video API
| Endpoint | Method | Description |
| ------------------------------------ | ------ | --------------------------------- |
| `/v1/video/create` | POST | Unified video creation |
| `/v1/video/query` | GET | Unified video query |
| `/kling/v1/videos/text2video` | POST | Kling text-to-video |
| `/kling/v1/videos/image2video` | POST | Kling image-to-video |
| `/kling/v1/videos/multi-image2video` | POST | Kling multi-image reference video |
| `/kling/v1/videos/omni-video` | POST | Kling omni-video |
| `/jimeng/submit/videos` | POST | Jimeng video submit |
| `/jimeng/fetch/{task_id}` | GET | Jimeng task query |
| `/luma/generations` | POST | Luma video generation |
| `/runwayml/v1/tasks` | POST | Runway video generation |
### Audio API
| Endpoint | Method | Description |
| -------------------------- | ------ | --------------------- |
| `/v1/audio/speech` | POST | Text-to-Speech (TTS) |
| `/v1/audio/transcriptions` | POST | Speech-to-Text (STT) |
| `/suno/submit/music` | POST | Suno music generation |
### Other APIs
| Endpoint | Method | Description |
| ---------------- | ------ | ----------- |
| `/v1/embeddings` | POST | Embeddings |
| `/v1/rerank` | POST | Reranking |
| `/v1/models` | GET | Model list |
All endpoints support HTTPS. OpenAI-compatible clients use `https://crazyrouter.com/v1` or `https://cn.crazyrouter.com/v1`; Claude Code and other Anthropic-native clients use the root domain, not a `/v1` URL.
# Authentication
Source: https://docs.crazyrouter.com/en/authentication
How to obtain and use API Keys
## Bearer Token Authentication
All API requests require an API Key in the header:
```
Authorization: Bearer YOUR_API_KEY
```
## Getting an API Key
1. Log in to [Crazyrouter](https://crazyrouter.com)
2. After signing in, go to the [Token Management](https://crazyrouter.com/console/token) page
3. Click "Create Token"
4. Set the token name, quota limit, available models, etc.
5. Copy the generated key starting with `sk-`
The API Key is only displayed once at creation time. Please save it securely. If lost, you will need to create a new one.
## Usage Examples
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Authorization: Bearer sk-xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-5.4", "messages": [{"role": "user", "content": "Hi"}]}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxxxxxxx",
base_url="https://crazyrouter.com/v1"
)
```
```javascript Node.js theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'sk-xxxxxxxx',
baseURL: 'https://crazyrouter.com/v1'
});
```
## Token Permission Controls
When creating a token, you can configure:
* **Name**: For easy identification of its purpose
* **Quota Limit**: Set the maximum available quota
* **Expiration Time**: Set a validity period
* **Available Models**: Restrict which models can be called
* **IP Whitelist**: Restrict the source IPs allowed to make calls
# Claude OpenAI-Compatible Chat
Source: https://docs.crazyrouter.com/en/chat/anthropic/completions
Claude Chat Completions compatibility path verified against Crazyrouter production on 2026-03-23
# Claude OpenAI-Compatible Chat
```
POST /v1/chat/completions
```
As of March 23, 2026, Crazyrouter production has verified:
* non-stream `claude-sonnet-4-6` requests return `object: "chat.completion"`
* the current `message` reliably includes `role` and `content`
* streaming requests return `chat.completion.chunk`
* the SSE stream still ends with `data: [DONE]`
***
## Non-Streaming Request
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Compare PostgreSQL and MySQL in one paragraph."}
],
"max_tokens": 256,
"temperature": 0.2
}'
```
Observed response shape:
```json theme={null}
{
"object": "chat.completion",
"model": "claude-sonnet-4-6",
"choices": [
{
"message": {
"role": "assistant",
"content": "PostgreSQL and MySQL are both popular..."
}
}
]
}
```
***
## Streaming Request
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [
{"role": "user", "content": "Say hello in one sentence."}
],
"max_tokens": 128,
"stream": true
}'
```
The 2026-03-23 production streaming probe began like this:
```text theme={null}
data: {"object":"chat.completion.chunk","model":"claude-sonnet-4-6","choices":[{"delta":{"role":"assistant"}}]}
data: {"object":"chat.completion.chunk","model":"claude-sonnet-4-6","choices":[{"delta":{"content":"Hello! ..."}}]}
data: [DONE]
```
If you need Claude-native `thinking`, native tool blocks, or document inputs, prefer [Claude Messages](/chat/anthropic/messages).
# Claude Token Counting
Source: https://docs.crazyrouter.com/en/chat/anthropic/count-tokens
POST /v1/messages/count_tokens estimate the input token count for a Claude Messages request
# Claude Token Counting
```
POST /v1/messages/count_tokens
```
Use this endpoint to estimate input token usage before you send the real `POST /v1/messages` request. It is useful for Claude CLI, Claude Code, budget checks, and context-trimming logic.
## Authentication
The recommended headers follow Anthropic-style requests:
```http theme={null}
x-api-key: YOUR_API_KEY
anthropic-version: 2023-06-01
```
Standard Bearer authentication also works, but Anthropic ecosystem clients usually send the headers above.
## Request Body
The body follows the Claude Messages shape. The smallest practical request usually includes:
* `model`
* `messages`
If your request also includes `system`, `tools`, tool results, or text content, those are included in the estimate too.
## Request Example
```bash cURL theme={null}
curl https://crazyrouter.com/v1/messages/count_tokens -H "Content-Type: application/json" -H "x-api-key: YOUR_API_KEY" -H "anthropic-version: 2023-06-01" -d '{
"model": "claude-sonnet-4-6",
"messages": [
{"role": "user", "content": "hello"}
]
}'
```
```python Python theme={null}
import requests
resp = requests.post(
"https://crazyrouter.com/v1/messages/count_tokens",
headers={
"x-api-key": "YOUR_API_KEY",
"anthropic-version": "2023-06-01",
"Content-Type": "application/json",
},
json={
"model": "claude-sonnet-4-6",
"messages": [
{"role": "user", "content": "hello"}
],
},
)
print(resp.json())
```
## Response Example
```json theme={null}
{
"input_tokens": 4
}
```
## Response Fields
| Field | Type | Description |
| -------------- | ------- | ----------------------------------------------------------------------------------- |
| `input_tokens` | integer | Estimated input tokens for the text portion of the request |
| `warning` | string | Optional warning; may appear when images or files were not included in the estimate |
## Current Limits
The current implementation mainly estimates:
* `system`
* text content in `messages`
* text and JSON content in tool definitions and tool results
If the request contains images or files, those image/file tokens are not included in `input_tokens`. In that case the response may include a `warning`, and real billing can be higher than this estimate.
This endpoint returns an estimate, not a final billing record. Actual usage is determined by the real model call.
# Claude Native Format
Source: https://docs.crazyrouter.com/en/chat/anthropic/messages
Production-revalidated Anthropic Messages usage for Claude on Crazyrouter
# Claude Native Format
```
POST /v1/messages
```
This page only documents Claude Messages behavior that was revalidated against Crazyrouter production on `2026-03-22`.
Current primary example models:
* `claude-sonnet-4-6`
* `claude-opus-4-7`
## Authentication
This recheck confirmed that both of the following auth styles work:
```text theme={null}
x-api-key: YOUR_API_KEY
```
```text theme={null}
Authorization: Bearer YOUR_API_KEY
```
Keep:
```text theme={null}
anthropic-version: 2023-06-01
```
***
## Basic conversation
```bash cURL theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 128,
"messages": [
{
"role": "user",
"content": "Explain quantum computing in one sentence."
}
]
}'
```
Verified response shape:
```json theme={null}
{
"type": "message",
"content": [
{
"type": "text",
"text": "..."
}
]
}
```
***
## Function calling
In the current production environment, Claude tool calling is reproducible through `/v1/messages` and returns `tool_use`.
For first-pass validation, use:
* an explicit `tool_choice`
* a prompt that clearly says Claude must call the tool and not answer directly
```bash cURL theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 256,
"tools": [
{
"name": "get_time",
"description": "Get the current time for a timezone",
"input_schema": {
"type": "object",
"properties": {
"timezone": {
"type": "string"
}
},
"required": ["timezone"]
}
}
],
"tool_choice": {
"type": "any"
},
"messages": [
{
"role": "user",
"content": "Use the get_time tool for Asia/Shanghai. Do not answer directly."
}
]
}'
```
Verified response shape:
```json theme={null}
{
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"name": "get_time",
"input": {
"timezone": "Asia/Shanghai"
}
}
]
}
```
***
## Extended thinking
In this production recheck, the combination that clearly returned a `thinking` block was:
* `claude-opus-4-7`
Base `claude-opus-4-6` did not produce an equally explicit thinking block in this round, so the docs prioritize the thinking variant here.
```bash cURL theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-4-7",
"max_tokens": 320,
"thinking": {
"type": "enabled",
"budget_tokens": 128
},
"messages": [
{
"role": "user",
"content": "Which is larger, 9.11 or 9.9? Explain briefly."
}
]
}'
```
Verified response shape:
```json theme={null}
{
"content": [
{
"type": "thinking",
"thinking": "..."
},
{
"type": "text",
"text": "..."
}
]
}
```
When using `thinking`, `max_tokens` must be greater than `budget_tokens`. Thinking tokens are billed as well.
***
## Current recommendation
* Standard text chat: use `claude-sonnet-4-6`
* Tool calling: use `claude-sonnet-4-6`, and include `tool_choice` in first-pass validation
* Explicit thinking blocks: use `claude-opus-4-7`
Related pages:
* [Feature Hub: Tool Calling](/en/features/tool-calling)
* [Feature Hub: Reasoning](/en/features/reasoning)
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Claude Chat Object
Source: https://docs.crazyrouter.com/en/chat/anthropic/overview
Production-revalidated Anthropic Message object and native SSE events as of 2026-03-23
# Claude Chat Object
Crazyrouter supports the Anthropic native Messages API.
This page only documents Message-object and streaming-event behavior that was revalidated in production on `2026-03-23`.
## Message object
The current minimal production request uses:
* `model: "claude-sonnet-4-6"`
* `POST /v1/messages`
Typical production response skeleton:
```json theme={null}
{
"id": "msg_xxx",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "..."
}
],
"model": "claude-sonnet-4-6",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 15,
"output_tokens": 20
}
}
```
### Common fields
| Field | Type | Meaning |
| ------------- | ------ | ----------------------------------------------------------- |
| `id` | string | Unique message identifier |
| `type` | string | Always `message` |
| `role` | string | Always `assistant` |
| `content` | array | Content block list |
| `model` | string | Actual model used |
| `stop_reason` | string | Stop reason such as `end_turn`, `tool_use`, or `max_tokens` |
| `usage` | object | Token usage |
### Common content block types
Text block:
```json theme={null}
{
"type": "text",
"text": "..."
}
```
Tool-use block:
```json theme={null}
{
"type": "tool_use",
"id": "toolu_xxx",
"name": "get_time",
"input": {
"timezone": "Asia/Shanghai"
}
}
```
Thinking block:
```json theme={null}
{
"type": "thinking",
"thinking": "..."
}
```
***
## Streaming event types
In the `2026-03-23` production recheck, native streaming for `claude-sonnet-4-6` returned these SSE events:
* `message_start`
* `content_block_start`
* `content_block_delta`
* `content_block_stop`
* `message_delta`
* `message_stop`
### Event examples
`message_start`
```text theme={null}
event: message_start
data: {"type":"message_start","message":{...}}
```
`content_block_start`
```text theme={null}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
```
`content_block_delta`
```text theme={null}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
```
`content_block_stop`
```text theme={null}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
```
`message_delta`
```text theme={null}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":20}}
```
`message_stop`
```text theme={null}
event: message_stop
data: {"type":"message_stop"}
```
***
## Practical interpretation
* If `content` only contains `text`, it is a normal answer
* If `stop_reason = "tool_use"` and `content` contains `tool_use`, the model is making a tool call
* If `content` contains `thinking`, the current model and request shape triggered extended thinking
A `thinking` block is not returned by every Claude model by default. The currently revalidated explicit thinking path is `claude-opus-4-7`.
Related pages:
* [Claude Native Format](/en/chat/anthropic/messages)
* [Feature Hub: Tool Calling](/en/features/tool-calling)
* [Feature Hub: Reasoning](/en/features/reasoning)
# Claude PDF Support
Source: https://docs.crazyrouter.com/en/chat/anthropic/pdf
Claude PDF input verified against Crazyrouter production on 2026-03-23
# Claude PDF Support
```
POST /v1/messages
```
As of March 23, 2026, Crazyrouter production has verified that `claude-sonnet-4-6` can read a Base64 PDF through the native Messages API and return a text summary.
***
## Verified Minimal Request
```bash theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 512,
"messages": [
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": "JVBERi0xLjQK..."
}
},
{
"type": "text",
"text": "Summarize the document in one sentence."
}
]
}
]
}'
```
Observed production response shape:
```json theme={null}
{
"model": "claude-sonnet-4-6",
"content": [
{
"type": "text",
"text": "The document is a simple Crazyrouter PDF test document..."
}
]
}
```
This page keeps only the Base64 PDF path that was revalidated successfully. Remote URLs, multi-PDF comparison, and streamed PDF output were not rechecked item by item in this pass.
# Claude Vision
Source: https://docs.crazyrouter.com/en/chat/anthropic/vision
Claude image understanding verified against Crazyrouter production on 2026-03-23
# Claude Vision
As of March 23, 2026, Crazyrouter production has verified two Claude image-input paths:
* native `POST /v1/messages` with `type: "image"` and Base64 PNG
* OpenAI-compatible `POST /v1/chat/completions` with `type: "image_url"` and a data URL
***
## Native Format: `/v1/messages`
```bash theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 128,
"messages": [
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgoAAA..."
}
},
{
"type": "text",
"text": "What color is this image?"
}
]
}
]
}'
```
This production check returned:
* `model: "claude-sonnet-4-6"`
* `content[0].type = "text"`
***
## OpenAI-Compatible Format: `/v1/chat/completions`
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What color is this image?"},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgoAAA..."
}
}
]
}
],
"max_tokens": 128
}'
```
In the 2026-03-23 production check, `message.content` came back as plain text describing the image color.
This page keeps only the Base64 PNG / data-URL paths that were revalidated successfully. Remote URLs, additional image formats, and more complex multi-image cases were not rechecked item by item in this pass.
# Gemini Audio Understanding
Source: https://docs.crazyrouter.com/en/chat/gemini/audio
Gemini native audio understanding documented from successful Crazyrouter request patterns on 2026-04-08
# Gemini Audio Understanding
```text theme={null}
POST /v1beta/models/{model}:generateContent
```
As of `2026-04-08`, successful Crazyrouter and local `:4000` retests show:
* `gemini-2.5-pro` can read `audio/wav`
* the currently verified primary path is `inlineData`
* short audio classification, transcription, language hints, and summaries can be requested directly in text
***
## Verified Minimal Request
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-2.5-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"inlineData": {
"mimeType": "audio/wav",
"data": "BASE64_WAV_DATA"
}
},
{
"text": "Return JSON with transcript, language, and summary."
}
]
}
],
"generationConfig": {
"maxOutputTokens": 512
}
}'
```
Observed successful response shape:
````json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"text": "```json\n{\n \"transcript\": \"ding\",\n \"language\": \"zh-CN\",\n \"summary\": \"The audio contains one short notification sound.\"\n}\n```"
}
]
}
}
]
}
````
## Request Notes
* Prefer `inlineData` for audio understanding
* Keep `mimeType` aligned with the actual format, such as `audio/wav` or `audio/mpeg`
* Put raw Base64 into `data` without a Data URL prefix
* If you need strict JSON instead of JSON-looking text, combine this route with [Structured Outputs](/en/features/structured-outputs)
This page only covers the short-audio understanding path that was actually rechecked successfully. For longer STT workflows, realtime audio, or TTS, see the existing [STT](/en/audio/stt), [Realtime](/en/audio/realtime), and [TTS](/en/audio/tts) pages.
# Gemini Document Understanding
Source: https://docs.crazyrouter.com/en/chat/gemini/document
Gemini PDF understanding and structured extraction verified against Crazyrouter production on 2026-03-23
# Gemini Document Understanding
```
POST /v1beta/models/{model}:generateContent
```
As of March 23, 2026, Crazyrouter production has verified that `gemini-3-pro` supports:
* Reading PDFs through `inlineData`
* Returning parseable JSON when `responseMimeType` and `responseSchema` are provided
***
## PDF Summary
The following request successfully read a PDF and returned a summary in production:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Summarize the attached PDF in one sentence."},
{
"inlineData": {
"mimeType": "application/pdf",
"data": "JVBERi0xLjQK..."
}
}
]
}
]
}'
```
In the production check, the model returned a one-sentence summary of the attached PDF.
***
## PDF + Structured Output
The following request returned JSON text that could be parsed directly with `json.loads()` in production:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Extract the key topic and whether the document mentions gamma."},
{
"inlineData": {
"mimeType": "application/pdf",
"data": "JVBERi0xLjQK..."
}
}
]
}
],
"generationConfig": {
"responseMimeType": "application/json",
"responseSchema": {
"type": "object",
"properties": {
"topic": {"type": "string"},
"mentions_gamma": {"type": "boolean"}
},
"required": ["topic", "mentions_gamma"]
}
}
}'
```
Observed production response:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"text": "{\n \"topic\": \"Crazyrouter PDF test document\",\n \"mentions_gamma\": false\n}"
}
]
}
}
]
}
```
You can parse it directly:
```python theme={null}
import json
text = response["candidates"][0]["content"]["parts"][0]["text"]
data = json.loads(text)
```
This page only confirms the PDF-input path and JSON structured output path. For table extraction, long-document comparison, or other higher-variance workflows, revalidate with your own sample documents first.
Large PDFs materially increase input-token usage. Validate prompts and schemas with small documents first, then scale up.
# Gemini Image Editing
Source: https://docs.crazyrouter.com/en/chat/gemini/image-edit
Current Gemini image-editing availability note updated from the 2026-04-14 Crazyrouter production retest
# Gemini Image Editing
```
POST /v1beta/models/{model}:generateContent
```
As of April 14, 2026, the latest Crazyrouter retest for Gemini image-editing-related routes showed:
* native `nano-banana-2:generateContent` can now return image output again
* native `nano-banana:generateContent` can also return image output, but billing consistency is still under review
* the Nano Banana-family public Images-compatible route through `POST /v1/images/generations` is currently unhealthy
The unhealthy path right now is the older public Images-compatible layer, not every Gemini-native image path. For editing and reference-image workloads, the current guidance should converge on native Gemini `generateContent`.
Do not keep documenting Nano Banana-family `POST /v1/images/generations` as the stable image-editing route. `nano-banana-2` should move to `nano-banana-2:generateContent`, while `nano-banana` remains controlled-testing only.
The more usable path right now is [Nano Banana 2](/en/images/nano-banana-2), which now points to native Gemini `nano-banana-2:generateContent`.
[Nano Banana](/en/images/nano-banana) now keeps only the controlled-test note for `nano-banana:generateContent`, not a stable production recommendation.
***
## Current Recommendation
1. If your goal is Gemini text-to-image, use [Gemini Image Generation](/en/chat/gemini/image-gen)
2. If your goal is a currently usable reference-image editing route, start with [Nano Banana 2](/en/images/nano-banana-2)
3. If you must evaluate `nano-banana`, follow the controlled-test guidance on [Nano Banana](/en/images/nano-banana)
4. Do not keep treating `POST /v1/images/generations` as the default entry point for the Nano Banana family
***
## Retest Template
This is now the more recommended minimal template for retesting or integration. The same workload should no longer be documented through `/v1/images/generations`:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/nano-banana-2:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Edit this image: change the background to blue and keep the main square visible. Return image output."},
{
"inlineData": {
"mimeType": "image/png",
"data": "iVBORw0KGgoAAA..."
}
}
]
}
],
"generationConfig": {
"responseModalities": ["IMAGE"]
}
}'
```
# Gemini Image Generation
Source: https://docs.crazyrouter.com/en/chat/gemini/image-gen
Current Gemini image-generation behavior updated from the 2026-04-14 Crazyrouter production retest
# Gemini Image Generation
```
POST /v1beta/models/{model}:generateContent
```
As of April 14, 2026, the latest production retest against Crazyrouter showed:
* `nano-banana-2` returned `inlineData` when called with `responseModalities: ["IMAGE"]`
* `nano-banana-pro` returned `text` containing a Markdown image with a `data:image/...;base64,...` payload
* `nano-banana` also returned `text` containing `data:image/...;base64,...`
* `nano-banana` returned `text` containing a hosted image URL
Gemini image models do not currently share one uniform response shape on Crazyrouter. Do not assume every model will return `inlineData`.
If you are migrating from the Nano Banana family, do not keep using `/v1/images/generations`. `nano-banana-2` should now move directly to `nano-banana-2:generateContent`. `nano-banana` can return image output through `nano-banana:generateContent`, but billing consistency is still under review.
***
## Most Practical Current Example
For the specific goal of getting image bytes directly, the easiest current model to handle is `nano-banana-2`:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/nano-banana-2:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Generate an IMAGE of a simple red square on a white background. Return image output."}
]
}
],
"generationConfig": {
"responseModalities": ["IMAGE"]
}
}'
```
Observed production response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"inlineData": {
"mimeType": "image/png",
"data": "iVBORw0KGgoAAA..."
}
}
]
}
}
]
}
```
***
## Other Observed Output Shapes
The same-day production check also showed these model-specific differences:
* `nano-banana-pro`: `parts[0].text` looked like ``
* `nano-banana`: `parts[0].text` looked like ``
* `nano-banana`: `parts[0].text` looked like ``
If you need to support multiple Gemini image models, parse in this order:
1. Check `inlineData` first
2. Then check whether `text` contains `data:image/`
3. Then check whether `text` contains a hosted image URL
This page no longer keeps aspect-ratio or multi-image parameter guidance, because those parameters were not revalidated in this production pass.
# Imagen 4
Source: https://docs.crazyrouter.com/en/chat/gemini/imagen
Google Imagen 4 image generation model, called through the Gemini API
# Imagen 4
Google Imagen 4 is a professional image generation model, called through the Gemini API endpoint.
Imagen 4 is currently in development. Features and availability may change.
```
POST /v1beta/models/imagen-4:generateContent
```
***
## Basic Usage
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/imagen-4:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "A golden Labrador retriever running on a sunny meadow, photographic quality, shallow depth of field"}
]
}
],
"generationConfig": {
"responseModalities": ["IMAGE"],
"imageGenerationConfig": {
"numberOfImages": 1,
"aspectRatio": "16:9"
}
}
}'
```
```python Python theme={null}
import google.generativeai as genai
import base64
genai.configure(
api_key="YOUR_API_KEY",
transport="rest",
client_options={"api_endpoint": "https://crazyrouter.com"}
)
model = genai.GenerativeModel("imagen-4")
response = model.generate_content(
"A golden Labrador retriever running on a sunny meadow, photographic quality",
generation_config=genai.GenerationConfig(
response_modalities=["IMAGE"],
image_generation_config={
"number_of_images": 1,
"aspect_ratio": "16:9"
}
)
)
for part in response.candidates[0].content.parts:
if hasattr(part, "inline_data"):
with open("imagen_output.png", "wb") as f:
f.write(base64.b64decode(part.inline_data.data))
print("Image saved")
```
### Response Format
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"inlineData": {
"mimeType": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUg..."
}
}
],
"role": "model"
},
"finishReason": "STOP"
}
]
}
```
***
## Parameter Description
### imageGenerationConfig
| Parameter | Type | Description |
| ---------------- | ------- | ------------------------------------------------- |
| `numberOfImages` | integer | Number of images to generate, 1-4 |
| `aspectRatio` | string | Aspect ratio: `1:1`, `16:9`, `9:16`, `4:3`, `3:4` |
***
## Batch Generation
```json theme={null}
{
"generationConfig": {
"responseModalities": ["IMAGE"],
"imageGenerationConfig": {
"numberOfImages": 4,
"aspectRatio": "1:1"
}
}
}
```
Imagen 4 is a pure image generation model, so `responseModalities` should be set to `["IMAGE"]`. If you need text descriptions alongside images, use the Gemini image generation model instead.
For Imagen 4 prompts, it is recommended to use detailed descriptive language including style, lighting, composition, and other details for better generation results.
# Gemini Native Format
Source: https://docs.crazyrouter.com/en/chat/gemini/native
Production-revalidated Gemini 3 Pro native API usage on Crazyrouter
# Gemini Native Format
This page only documents Gemini Native behavior that was revalidated against Crazyrouter production on `2026-03-22`.
Current primary example model:
* `gemini-3-pro`
Dedicated multimodal pages based on successful request patterns:
* [Gemini Image Understanding](/en/chat/gemini/vision)
* [Gemini Video Understanding](/en/chat/gemini/video)
* [Gemini Audio Understanding](/en/chat/gemini/audio)
## Endpoints
```text theme={null}
POST /v1beta/models/{model}:generateContent
POST /v1beta/models/{model}:streamGenerateContent
```
## Authentication
Pass the API key through the URL parameter:
```text theme={null}
?key=YOUR_API_KEY
```
***
## Basic text generation
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Explain machine learning in one sentence."
}
]
}
],
"generationConfig": {
"maxOutputTokens": 128
}
}'
```
Verified response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"text": "...",
"thoughtSignature": "..."
}
]
}
}
]
}
```
***
## Streaming generation
This recheck confirmed that `streamGenerateContent` returns incremental SSE output.
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:streamGenerateContent?key=YOUR_API_KEY&alt=sse" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Write one short sentence about AI."
}
]
}
]
}'
```
Observed SSE chunk shape:
```text theme={null}
data: {"candidates":[{"content":{"parts":[{"text":"...","thoughtSignature":"..."}]}}]}
```
***
## Structured outputs
This production recheck confirmed that `responseMimeType + responseSchema` works:
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Return a JSON object with keys city and country for Tokyo."
}
]
}
],
"generationConfig": {
"responseMimeType": "application/json",
"responseSchema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"}
},
"required": ["city", "country"]
}
}
}'
```
Verified production output:
```json theme={null}
{"city":"Tokyo","country":"Japan"}
```
***
## Google Search
This production recheck confirmed that the `googleSearch` tool works:
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Use Google Search to find one recent headline from a major technology news site."
}
]
}
],
"tools": [
{
"googleSearch": {}
}
]
}'
```
Verified fields include:
* `groundingMetadata.webSearchQueries`
* `groundingMetadata.groundingChunks`
* `groundingMetadata.groundingSupports`
***
## Thinking
This production recheck confirmed that `thinkingConfig` works:
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Which is larger, 9.11 or 9.9? Explain briefly."
}
]
}
],
"generationConfig": {
"thinkingConfig": {
"thinkingBudget": 256
},
"maxOutputTokens": 512
}
}'
```
Verified marker:
```json theme={null}
{
"usageMetadata": {
"thoughtsTokenCount": 120
}
}
```
***
## Common `generationConfig` fields
| Field | Type | Description |
| ------------------ | ------- | -------------------------------- |
| `maxOutputTokens` | integer | Maximum output tokens |
| `temperature` | number | Sampling temperature |
| `responseMimeType` | string | MIME type for structured outputs |
| `responseSchema` | object | Structured output constraint |
| `thinkingConfig` | object | Thinking mode configuration |
Gemini Native uses the `contents[].parts[]` structure rather than OpenAI-style `messages`. If you want an OpenAI-style route instead, use [Gemini OpenAI-Compatible Format](/en/chat/gemini/openai-compat).
Related pages:
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Gemini OpenAI-Compatible Format
Source: https://docs.crazyrouter.com/en/chat/gemini/openai-compat
Production-revalidated Gemini 3 Pro via /v1/chat/completions
# Gemini OpenAI-Compatible Format
You can call Gemini through the OpenAI Chat Completions compatible route.
```
POST /v1/chat/completions
```
This page only documents compatibility-layer behavior that was revalidated against Crazyrouter production on `2026-03-22`.
Current primary example model:
* `gemini-3-pro`
## Current conclusion
This production recheck confirmed that:
* `gemini-3-pro` works through `/v1/chat/completions` for normal text chat
* streaming returns standard `chat.completion.chunk` SSE objects
* for Gemini-specific capabilities such as structured outputs, Google Search, and thinking, you should still prefer [Gemini Native Format](/en/chat/gemini/native)
***
## Basic conversation
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gemini-3-pro",
"messages": [
{
"role": "system",
"content": "You are a concise assistant."
},
{
"role": "user",
"content": "Explain quantum entanglement in one sentence."
}
],
"max_tokens": 128
}'
```
Verified response shape:
```json theme={null}
{
"object": "chat.completion",
"model": "gemini-3-pro",
"choices": [
{
"message": {
"role": "assistant",
"content": "..."
}
}
]
}
```
***
## Python example
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="gemini-3-pro",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Explain quantum entanglement in one sentence."}
],
max_tokens=128
)
print(response.choices[0].message.content)
```
***
## Streaming output
This production recheck also confirmed streaming compatibility:
```python Python theme={null}
stream = client.chat.completions.create(
model="gemini-3-pro",
messages=[
{"role": "user", "content": "Write one short sentence about AI."}
],
max_tokens=64,
stream=True
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content is not None:
print(delta.content, end="")
```
Observed SSE shape:
```text theme={null}
data: {"object":"chat.completion.chunk","model":"gemini-3-pro",...}
data: {"choices":[{"delta":{"content":"..."}}],...}
data: [DONE]
```
***
## When to use compatible vs native
* If you already have OpenAI SDK code and only need standard chat, use the compatible route
* If you need Gemini-native structured outputs, Google Search, thinking, or native metadata, use [Gemini Native Format](/en/chat/gemini/native)
This page still only covers the `/v1/chat/completions` compatibility layer and does not fold Gemini-backed image behavior into it. For image workloads, do not keep documenting the Nano Banana family as a stable `/v1/images/generations` contract.
The currently preferred entry point is [Nano Banana 2](/en/images/nano-banana-2), which now points to native Gemini `POST /v1beta/models/nano-banana-2:generateContent`.
[Nano Banana](/en/images/nano-banana) remains controlled-testing only.
# Gemini-Compatible OpenAI Model List
Source: https://docs.crazyrouter.com/en/chat/gemini/openai-models
Production-revalidated GET /v1beta/openai/models usage for retrieving an OpenAI-style model list
# Gemini-Compatible OpenAI Model List
```
GET /v1beta/openai/models
```
This endpoint is a compatibility bridge:
* the auth style can be Gemini-like
* the response shape is still OpenAI-style model-list JSON
This page only documents behavior that was revalidated against Crazyrouter production on `2026-03-23`.
## When to use it
* your client prefers `?key=`
* your middleware already uses `x-goog-api-key`
* you want an OpenAI-style `list + data[]` response rather than native Gemini model metadata
If you are using a normal OpenAI-compatible client, prefer [GET /v1/models](/en/chat/openai/models).
## Authentication
This recheck confirmed that all three of the following work:
```http theme={null}
Authorization: Bearer YOUR_API_KEY
```
```http theme={null}
x-goog-api-key: YOUR_API_KEY
```
```text theme={null}
GET /v1beta/openai/models?key=YOUR_API_KEY
```
## Request examples
```bash cURL theme={null}
curl "https://crazyrouter.com/v1beta/openai/models?key=YOUR_API_KEY"
```
```bash cURL with Header theme={null}
curl https://crazyrouter.com/v1beta/openai/models \
-H "x-goog-api-key: YOUR_API_KEY"
```
***
## Current production findings
In the `2026-03-23` production recheck:
* the `?key=` request returned `200`
* the `x-goog-api-key` request returned `200`
* the top-level `object` was `list`
* the top-level `success` was `true`
* the current model count was `541`
* common fields inside `data[]` included:
* `id`
* `object`
* `created`
* `owned_by`
* `supported_endpoint_types`
***
## Response example
```json theme={null}
{
"object": "list",
"success": true,
"data": [
{
"id": "gpt-5.4",
"object": "model",
"created": 1700000000,
"owned_by": "openai",
"supported_endpoint_types": ["openai"]
},
{
"id": "claude-sonnet-4-6",
"object": "model",
"created": 1700000000,
"owned_by": "anthropic",
"supported_endpoint_types": ["openai", "anthropic"]
},
{
"id": "gemini-3-pro",
"object": "model",
"created": 1700000000,
"owned_by": "google",
"supported_endpoint_types": ["openai", "gemini"]
}
]
}
```
## Field notes
| Field | Type | Meaning |
| -------------------------- | ------- | ------------------------------------- |
| `data[]` | array | Models available to the current token |
| `id` | string | Model identifier |
| `owned_by` | string | Upstream source or owner label |
| `supported_endpoint_types` | array | Supported API styles for the model |
| `object` | string | Always `list` |
| `success` | boolean | Whether the request succeeded |
Read the path meaning of `supported_endpoint_types` from `supported_endpoint` in `GET /api/pricing`. At the moment, `openai` maps to `POST /v1/chat/completions`, `anthropic` maps to `POST /v1/messages`, and only `openai-response` maps to `POST /v1/responses`. Claude currently exposes `openai` + `anthropic`, not `openai-response`.
This endpoint does not return only Gemini models. It returns the OpenAI-style model list visible to the current token, but exposes it through a Gemini-friendly access path.
Related pages:
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Gemini Tools
Source: https://docs.crazyrouter.com/en/chat/gemini/tools
Gemini native tool capabilities verified against Crazyrouter production on 2026-03-23
# Gemini Tools
```
POST /v1beta/models/{model}:generateContent
```
As of March 23, 2026, Crazyrouter production has verified that `gemini-3-pro` can reliably trigger these Gemini-native tool capabilities:
* `codeExecution`
* `googleSearch`
* `urlContext`
* `functionDeclarations`
This page keeps only request patterns and response markers that were reproduced against production.
***
## Code Execution
The following request returned both `executableCode` and `codeExecutionResult` in production:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Use code execution. Compute the sum of the first 20 prime numbers and state the result."}
]
}
],
"tools": [
{
"codeExecution": {}
}
]
}'
```
Observed response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"executableCode": {
"language": "PYTHON",
"code": "..."
}
},
{
"codeExecutionResult": {
"outcome": "OUTCOME_OK",
"output": "639\n"
}
},
{
"text": "The sum is 639."
}
]
}
}
]
}
```
***
## Google Search
The following request returned `groundingMetadata` in production, confirming that Google Search was actually used:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Use Google Search. What are two AI news items from March 2026?"}
]
}
],
"tools": [
{
"googleSearch": {}
}
]
}'
```
Current markers to check:
* `candidates[0].groundingMetadata`
* Normal text output in `candidates[0].content.parts[*].text`
***
## URL Context
The following request returned `urlContextMetadata` in production, along with `groundingMetadata`:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Use URL context to summarize https://example.com/ in one sentence."}
]
}
],
"tools": [
{
"urlContext": {}
}
]
}'
```
Current markers to check:
* `candidates[0].urlContextMetadata`
* `candidates[0].groundingMetadata`
***
## Custom Function Calling
The following request returned `functionCall` in production:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "What is the weather in Beijing? Use the provided function."}
]
}
],
"tools": [
{
"functionDeclarations": [
{
"name": "get_weather",
"description": "Get weather info for a city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": ["city"]
}
}
]
}
]
}'
```
Observed response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"functionCall": {
"name": "get_weather",
"args": {
"city": "Beijing"
}
}
}
]
}
}
]
}
```
To continue the tool loop, send the tool result back with Gemini-native `functionResponse`.
# Gemini Video Understanding
Source: https://docs.crazyrouter.com/en/chat/gemini/video
Gemini native video understanding documented from successful Crazyrouter request patterns on 2026-04-08
# Gemini Video Understanding
```text theme={null}
POST /v1beta/models/{model}:generateContent
```
As of `2026-04-08`, successful Crazyrouter and local `:4000` retests show:
* `gemini-2.5-pro` can read `video/mp4`
* the currently verified primary path is `fileData.fileUri`
* the video URL must be publicly reachable by the Gemini upstream
***
## Verified Minimal Request
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-2.5-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"fileData": {
"mimeType": "video/mp4",
"fileUri": "https://example.com/demo.mp4"
}
},
{
"text": "Describe the main subject, motion, and whether the camera is static."
}
]
}
],
"generationConfig": {
"maxOutputTokens": 512
}
}'
```
Observed successful response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"text": "The main subject is a red ball rolling from left to right, and the camera is static."
}
]
}
}
]
}
```
## Request Notes
* The primary recommended path for video understanding is `fileData.fileUri`
* Set `mimeType` to the real file type, such as `video/mp4`
* `fileUri` must be reachable by the Gemini upstream
* Private-network URLs, signed flows that cannot be crawled, or inaccessible storage links are likely to fail
Do not assume the image-understanding request shape is the same as the video-understanding request shape. Images currently work best through `inlineData`, while the verified video path here uses `fileData.fileUri`.
# Gemini Image Understanding
Source: https://docs.crazyrouter.com/en/chat/gemini/vision
Gemini native image understanding documented from successful Crazyrouter request patterns on 2026-04-08
# Gemini Image Understanding
```
POST /v1beta/models/{model}:generateContent
```
As of `2026-04-08`, successful Crazyrouter and local `:4000` retests show:
* `gemini-2.5-pro` can reliably read images through `inlineData`
* remote image URLs through `fileData.fileUri` have shown repeated fetch and upstream-body failures
* the primary recommended request shape for image understanding is therefore `inlineData`
***
## Verified Minimal Request
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-2.5-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"inlineData": {
"mimeType": "image/png",
"data": "BASE64_PNG_DATA"
}
},
{
"text": "Describe this image in one short sentence."
}
]
}
]
}'
```
Observed production response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"text": "This image shows a smooth multi-color gradient background."
}
]
}
}
]
}
```
## Request Notes
* Prefer `inlineData` for image understanding
* Keep `mimeType` aligned with the actual file format, such as `image/png` or `image/jpeg`
* Put raw Base64 into `data` without the `data:image/...;base64,` prefix
* If you only have a remote image URL, do not treat it as the current primary Gemini image-understanding path on Crazyrouter
For video understanding, see [Gemini Video Understanding](/en/chat/gemini/video). For audio understanding, see [Gemini Audio Understanding](/en/chat/gemini/audio).
# Create Chat Completion
Source: https://docs.crazyrouter.com/en/chat/openai/completions
Production-oriented usage of POST /v1/chat/completions based on current live behavior
# Create Chat Completion
```
POST /v1/chat/completions
```
Generates model responses from a message list and supports both non-streaming and streaming output.
This page only documents common behavior revalidated against Crazyrouter production on `2026-03-23`.
## Authentication
```text theme={null}
Authorization: Bearer YOUR_API_KEY
```
## Core parameters
| Parameter | Type | Required | Meaning |
| ----------------- | -------------- | -------- | -------------------------------------------------------------------- |
| `model` | string | Yes | Model name such as `gpt-5.4`, `claude-sonnet-4-6`, or `gemini-3-pro` |
| `messages` | array | Yes | Message list |
| `stream` | boolean | No | Whether to stream output |
| `max_tokens` | integer | No | Maximum output tokens |
| `temperature` | number | No | Sampling temperature |
| `response_format` | object | No | Structured output constraint |
| `tools` | array | No | Tool list |
| `tool_choice` | string\|object | No | Tool-selection strategy |
| `stream_options` | object | No | Streaming extras such as `include_usage` |
Optional parameter support varies by model. Client code should rely on the stable common fields first rather than assuming every model supports the same advanced options.
***
## Non-streaming request
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Explain artificial intelligence in one sentence."
}
],
"max_tokens": 64
}'
```
Typical production shape:
```json theme={null}
{
"object": "chat.completion",
"model": "gpt-5.4",
"choices": [
{
"message": {
"role": "assistant",
"content": "...",
"reasoning_content": null,
"tool_calls": null
},
"finish_reason": "stop"
}
]
}
```
### Important interpretation
* `message.content` is the most stable final-text field
* `message.tool_calls` only appears when the model is requesting tool execution
* `message.reasoning_content` may exist as a key, but should not currently be treated as guaranteed usable content
***
## Streaming request
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Explain AI in one short sentence."
}
],
"stream": true,
"stream_options": {
"include_usage": true
},
"max_tokens": 64
}'
```
This production recheck confirmed that:
* streaming returns `chat.completion.chunk`
* SSE chunks are sent as `data: ...`
* the stream still ends with `data: [DONE]`
Observed SSE shape:
```text theme={null}
data: {"object":"chat.completion.chunk","model":"gpt-5.4","choices":[{"delta":{"role":"assistant","content":"AI","reasoning_content":null,"tool_calls":null}}]}
```
```text theme={null}
data: [DONE]
```
***
## Python example
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[
{"role": "user", "content": "Explain AI in one short sentence."}
],
stream=True,
stream_options={"include_usage": True},
max_tokens=64
)
for chunk in stream:
delta = chunk.choices[0].delta
if delta.content is not None:
print(delta.content, end="")
```
***
## Current recommendation
* For normal text chat, use `/v1/chat/completions`
* For reasoning summaries or OpenAI-style web search, prefer `/v1/responses`
* For more specific capability guarantees, use the dedicated capability pages rather than this generic endpoint page
Related pages:
* [Chat Completion Object](/en/chat/openai/overview)
* [Reasoning Models](/en/chat/openai/reasoning)
* [Web Search](/en/chat/openai/web-search)
# Create Completion (Legacy)
Source: https://docs.crazyrouter.com/en/chat/openai/completions-legacy
Current production status of the POST /v1/completions compatibility endpoint
# Create Completion (Legacy)
```
POST /v1/completions
```
This is a compatibility endpoint, not the primary recommended path. For new integrations, prefer `/v1/chat/completions` or `/v1/responses`.
## Current Production Status
As of March 23, 2026, Crazyrouter production confirms:
* the route still exists
* a request using the classic example model `gpt-4.1-mini` returned `503`
* the error code was `model_not_found`
* the message said the model was temporarily unavailable
In practice, this means the endpoint should be treated as legacy-client compatibility only, not as the default path for new work.
***
## Current Recommendation
1. Use [`Chat Completions`](/chat/openai/completions) for new chat-style integrations
2. Use [`Responses`](/chat/responses/overview) when you need GPT-5 reasoning, web search, or newer response shapes
3. Only keep testing `/v1/completions` if you already depend on a legacy client and have confirmed that your legacy model is currently available
***
## Retest Template
If you must verify whether a legacy model still works on this endpoint, first confirm the model ID through [`/v1/models`](/chat/openai/models), then send a minimal request:
```bash theme={null}
curl https://crazyrouter.com/v1/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "YOUR_LEGACY_MODEL",
"prompt": "Say hello in three words.",
"max_tokens": 16
}'
```
Observed production error example:
```json theme={null}
{
"error": {
"code": "model_not_found",
"message": "Model gpt-4.1-mini is temporarily unavailable",
"type": "new_api_error"
}
}
```
# Function Calling
Source: https://docs.crazyrouter.com/en/chat/openai/function-calling
Chat Completions tool calling verified against Crazyrouter production on 2026-03-23
# Function Calling
```
POST /v1/chat/completions
```
As of March 23, 2026, Crazyrouter production has verified that `gpt-5.4` on the Chat Completions path returns `tool_calls`.
***
## Step 1: Define the Tool
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "What is the weather in Beijing? Use the tool."}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather info for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
}
]
}'
```
Observed production response shape:
```json theme={null}
{
"object": "chat.completion",
"model": "gpt-5.4",
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_...",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Beijing\"}"
}
}
]
}
}
]
}
```
***
## Step 2: Return the Tool Result
Once you receive `tool_calls`, send your tool result back as a `role: "tool"` message:
```json theme={null}
{
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "What is the weather in Beijing? Use the tool."},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Beijing\"}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_123",
"content": "{\"temperature\":22,\"condition\":\"sunny\"}"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather info for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
}
]
}
```
This production pass confirmed the primary `tool_calls` path. It also observed that `message.reasoning_content` may appear as a key, but it should not be treated as a stable dependency for tool-calling flows.
# Grok Models
Source: https://docs.crazyrouter.com/en/chat/openai/grok
Call Grok text models through the OpenAI Chat Completions format
# Grok Models
```
POST /v1/chat/completions
```
Grok text models use the OpenAI-compatible Chat Completions format. Point `base_url` to Crazyrouter and pass the Grok model ID in `model`.
Model availability depends on channel status, token permissions, and the live pricing configuration. Before production use, call `GET /v1/models` with the same API key and confirm that the target model is visible.
## Common Models
| Model | Description |
| --------------------------- | --------------------------------- |
| `grok-4` | Main Grok 4 model |
| `grok-4-fast` | Grok 4 fast variant |
| `grok-4-fast-non-reasoning` | Grok 4 fast non-reasoning variant |
| `grok-4-fast-reasoning` | Grok 4 fast reasoning variant |
| `grok-4.1` | Grok 4.1 |
| `grok-4.1-fast` | Grok 4.1 fast |
| `grok-4.1-thinking` | Grok 4.1 thinking |
| `grok-4.2` | Grok 4.2 |
| `grok-4-0709` | Dated Grok 4 model |
Older `grok-4` / `grok-4.1` names may still appear in historical calls or compatibility setups, but the public pricing surface primarily keeps the `grok-4*` family. New integrations should start with `grok-4`, `grok-4.1`, `grok-4.2`, or the fast/reasoning variants.
## Minimal Request
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "grok-4",
"messages": [
{
"role": "user",
"content": "Reply with one short sentence: what is Grok?"
}
],
"temperature": 0.7,
"max_tokens": 120
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1",
)
response = client.chat.completions.create(
model="grok-4",
messages=[
{"role": "user", "content": "Reply with one short sentence: what is Grok?"}
],
temperature=0.7,
max_tokens=120,
)
print(response.choices[0].message.content)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const response = await client.chat.completions.create({
model: "grok-4",
messages: [
{ role: "user", content: "Reply with one short sentence: what is Grok?" },
],
temperature: 0.7,
max_tokens: 120,
});
console.log(response.choices[0].message.content);
```
## Streaming
Set `stream: true` to use SSE streaming.
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "grok-4-fast",
"stream": true,
"messages": [
{
"role": "user",
"content": "Write a concise API migration checklist."
}
]
}'
```
## Reasoning Variants
For Grok models containing `reasoning` or `thinking` in the name, keep the request shape simple:
```json theme={null}
{
"model": "grok-4-fast-reasoning",
"messages": [
{
"role": "user",
"content": "Compare two implementation options and explain the tradeoffs."
}
],
"max_tokens": 800
}
```
Reasoning fields, search fields, and experimental parameters can differ by upstream channel. For cross-channel stability, prefer standard OpenAI Chat fields: `model`, `messages`, `temperature`, `top_p`, `max_tokens`, and `stream`.
## Related Image Models
Grok image generation does not use Chat Completions. Use:
```text theme={null}
POST /v1/images/generations
```
See [Grok Image Models](/en/images/grok) for image parameters.
Related pages:
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Chat Image Generation
Source: https://docs.crazyrouter.com/en/chat/openai/image-creation
Chat-image behavior and stable alternatives verified against Crazyrouter production on 2026-03-23
# Chat Image Generation
```
POST /v1/chat/completions
```
As of March 23, 2026, production checks against Crazyrouter showed:
* `gpt-4o` returns `200`, but `message.content` is plain text, not standard multipart image content
* `gpt-image-2` also returns `200`, but the current response shape is still text or Markdown containing a parameter block, an ID, and a preview link, not the standard OpenAI `image_url` multipart structure
* If you need stable, machine-readable image output, the current recommended path is [`/v1/images/generations`](/en/images/gpt-image) with `gpt-image-2`; for Grok image models, see [`Grok Image Models`](/en/images/grok)
* If you need reference-image editing or multi-image input, do not keep treating the Nano Banana family as a stable `/v1/images/generations` entry point. Start with the native Gemini path documented on [`Nano Banana 2`](/en/images/nano-banana-2); [`Nano Banana`](/en/images/nano-banana) is currently controlled-testing only
Do not parse the current Crazyrouter chat-image response as if it were standard OpenAI `content: [{type: "image_url", ...}]`.
***
## Currently Reproducible Chat Behavior
The following request hit `gpt-image-2` in production and returned `200`:
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"messages": [
{
"role": "user",
"content": "Generate an image of a red square on a white background."
}
],
"max_tokens": 512
}'
```
The observed `message.content` was a string shaped roughly like:
```text theme={null}
{
"prompt": "Generate an image of a red square on a white background.",
"ratio": "1:1",
"n": 1
}
ID: ...
Data Preview: https://...
```
That means the current chat path behaves more like text-wrapped image-task output than a standardized multipart image message object.
***
## Stable Path: Images API
If you need programmatic image retrieval, use:
```bash theme={null}
curl -X POST https://cn.crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "A red square on a white background",
"size": "1024x1024",
"quality": "low",
"output_format": "png"
}'
```
The current `gpt-image-2` stable path uses the primary image route `https://cn.crazyrouter.com/v1`. Responses usually include:
* `data[0].url`
`gpt-image-2` does not support `response_format`; do not send `response_format="url"` or `response_format="b64_json"`. To choose the image file format, use `output_format="png"`, `"jpeg"`, or `"webp"`.
So the stable automation path is still the Images API, not the chat-image compatibility path.
If you are only testing manually, the `gpt-image-2` chat path is still useful for observation. If you need backend automation, storage, or post-processing, use the [`GPT Image docs`](/en/images/gpt-image) or [`Grok Image Models`](/en/images/grok). If your workload depends on reference-image editing or multi-image input, start with the native Gemini route documented on [`Nano Banana 2`](/en/images/nano-banana-2). Do not keep treating Nano Banana-family `/v1/images/generations` as the stable recommendation.
# List Models
Source: https://docs.crazyrouter.com/en/chat/openai/models
Production-revalidated GET /v1/models usage for listing models available to the current token
# List Models
```
GET /v1/models
```
Returns the list of models available to the current API key.
This page only documents behavior that was revalidated against Crazyrouter production on `2026-04-14`.
## Authentication
```text theme={null}
Authorization: Bearer YOUR_API_KEY
```
## Request example
```bash cURL theme={null}
curl https://crazyrouter.com/v1/models \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
models = client.models.list()
for model in models.data:
print(model.id)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const models = await client.models.list();
for (const model of models.data) {
console.log(model.id);
}
```
***
## Current production findings
In the `2026-04-14` production recheck:
* the endpoint returned `200`
* the top-level `success` field was `true`
* the top-level `object` was `list`
* the current model count was `605`
* the following models were confirmed present:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `claude-opus-4-7`
* `gemini-3-pro`
The exact count and model set can change with upstream configuration, token permissions, and platform updates. Treat the examples here as current examples, not a fixed complete inventory.
***
## Response example
```json theme={null}
{
"success": true,
"object": "list",
"data": [
{
"id": "gpt-5.4",
"object": "model",
"created": 1700000000,
"owned_by": "openai"
},
{
"id": "claude-sonnet-4-6",
"object": "model",
"created": 1700000000,
"owned_by": "anthropic"
},
{
"id": "claude-opus-4-7",
"object": "model",
"created": 1700000000,
"owned_by": "anthropic"
},
{
"id": "gemini-3-pro",
"object": "model",
"created": 1700000000,
"owned_by": "google"
}
]
}
```
## Common fields
| Field | Type | Meaning |
| ---------- | ------- | ----------------------------------- |
| `success` | boolean | Whether the request succeeded |
| `id` | string | Model identifier used in API calls |
| `object` | string | Always `model` |
| `created` | integer | Timestamp |
| `owned_by` | string | Owning organization or source label |
***
## Pricing information
If you also need public pricing data, see:
```text theme={null}
GET /api/pricing
```
This production recheck confirmed that the endpoint returns a JSON object with common top-level keys such as:
* `data`
* `popular_models`
* `supported_endpoint`
* `vendors`
Use `supported_endpoint_types` / `public_endpoint_types` from `GET /api/pricing` for endpoint support. `openai` maps to `POST /v1/chat/completions`, `anthropic` maps to `POST /v1/messages`, and only `openai-response` maps to `POST /v1/responses`. Claude currently exposes `openai` + `anthropic`, not `openai-response`.
Related page:
* [Gemini-Compatible OpenAI Model List](/en/chat/gemini/openai-models)
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Chat Completion Object
Source: https://docs.crazyrouter.com/en/chat/openai/overview
Core production-oriented structure of Chat Completion and Chat Completion Chunk objects
# Chat Completion Object
`/v1/chat/completions` returns `chat.completion` for non-streaming requests and `chat.completion.chunk` for streaming requests.
This page focuses on the most stable, broadly useful OpenAI-compatible response structure on Crazyrouter today.
## Non-streaming object
Minimal production request:
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Explain what a REST API is in one sentence."
}
],
"max_tokens": 64
}'
```
Typical production response skeleton:
```json theme={null}
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1774177466,
"model": "gpt-5.4",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "...",
"reasoning_content": null,
"tool_calls": null
},
"finish_reason": "stop"
}
]
}
```
### How to read it
* `message.content` is the final text answer
* `message.tool_calls` only appears when the model is requesting tool execution
* `message.reasoning_content` may appear for some models or routes, but should not currently be treated as a guaranteed field
***
## Streaming object
For streaming requests, the server returns `chat.completion.chunk` SSE events:
```json theme={null}
{
"id": "chatcmpl-xxx",
"object": "chat.completion.chunk",
"created": 1774177466,
"model": "gpt-5.4",
"choices": [
{
"index": 0,
"delta": {
"role": "assistant",
"content": "..."
},
"finish_reason": null
}
]
}
```
Common SSE shape:
```text theme={null}
data: {"object":"chat.completion.chunk",...}
data: {"choices":[{"delta":{"content":"..."}}],...}
data: [DONE]
```
***
## Fields you will usually care about
| Field | Meaning |
| ------------------------------ | -------------------------------------------------------------------------- |
| `object` | `chat.completion` for non-streaming, `chat.completion.chunk` for streaming |
| `model` | The actual model used for the response |
| `choices[].message.content` | Final non-streaming text |
| `choices[].message.tool_calls` | Non-streaming tool requests |
| `choices[].delta.content` | Streaming text delta |
| `choices[].finish_reason` | Stop reason such as `stop`, `length`, or `tool_calls` |
Upstream models may pass through extra fields. Client code should rely on the stable common fields first rather than assuming every model exposes the same extensions.
# Reasoning Models
Source: https://docs.crazyrouter.com/en/chat/openai/reasoning
Production-revalidated guidance for using Crazyrouter reasoning features and choosing the right protocol
# Reasoning Models
This page only documents reasoning behavior that was revalidated against Crazyrouter production on `2026-03-22`.
For OpenAI-compatible integrations, the current guidance is:
* If you only want stronger reasoning and only need the final answer, use Chat Completions with `reasoning_effort`
* If you need a stable, inspectable reasoning output, prefer the Responses API and see [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
## Verified combinations
| Route | Model | Request parameter | Current production behavior |
| ---------------- | --------- | ---------------------------------------- | ------------------------------------------------- |
| Chat Completions | `gpt-5.4` | `reasoning_effort` | Request succeeds and returns a final answer |
| Responses | `gpt-5.4` | `reasoning.effort` / `reasoning.summary` | `output` includes `reasoning` and `message` items |
***
## Chat Completions: `reasoning_effort`
The following request shape currently works in production:
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Which is larger, 9.11 or 9.9? Explain briefly."
}
],
"reasoning_effort": "high",
"max_tokens": 120
}'
```
Available `reasoning_effort` values:
| Value | Meaning |
| -------- | --------------------------------- |
| `low` | Faster response for simpler tasks |
| `medium` | Balanced default-style setting |
| `high` | More reasoning for harder tasks |
### Current response behavior
In the `2026-03-22` production recheck:
* the request succeeded
* the final answer was returned in `message.content`
* `message.reasoning_content` did not reliably contain usable content
So if you only want stronger reasoning, Chat Completions with `reasoning_effort` is still usable. If you need a visible reasoning summary field, do not treat Chat Completions as the primary path.
***
## When you need inspectable reasoning output
The more reliable production path is the Responses API:
```bash cURL theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Which is larger, 9.11 or 9.9? Explain briefly.",
"reasoning": {
"effort": "high",
"summary": "detailed"
}
}'
```
Verified `output.type` values:
```json theme={null}
["reasoning", "message"]
```
For concrete response shapes, summary fields, and streaming event names, see:
* [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
* [AI Thinking Fields](/en/reference/thinking)
***
## Current recommendation
* For new builds that need to log or display reasoning summaries, start with the Responses API
* For existing Chat Completions integrations that only care about the final answer, `reasoning_effort` is still a valid path
* Do not assume all OpenAI-compatible reasoning models will reliably expose `reasoning_content`
Reasoning requests usually increase both latency and token usage. Higher `reasoning_effort` generally costs more.
# Special Models
Source: https://docs.crazyrouter.com/en/chat/openai/special-models
Production-revalidated availability notes for special-purpose models as of 2026-03-23
# Special Models
This page only documents facts revalidated against Crazyrouter production on `2026-03-23`.
Unlike the main capability pages, special-purpose models are much more likely to change with channel inventory, temporary upstream outages, or token-level availability. So this page no longer treats older examples as stable-success patterns by default.
## Current recheck results
### `qwen3.5-plus`
Production findings on `2026-03-23`:
* it did not appear in `GET /v1/models`
* a direct request returned:
* `503`
* `model_not_found`
* `Model qwen3.5-plus is temporarily unavailable`
So the docs no longer present `qwen3.5-plus` as a currently stable available model.
### `deepseek-ocr`
Production findings on `2026-03-23`:
* it did appear in `GET /v1/models`
* but an actual call returned:
* `500`
* `get_channel_failed`
* `model deepseek-ocr is temporarily unavailable, please try again later`
That means it is currently at least "visible in the model list, but not callable right now".
***
## Current recommendation
* If you need to know whether a special model is usable today, check [GET /v1/models](/en/chat/openai/models) first
* A model appearing in the list still does not guarantee that it is callable at that moment
* For these models, your first integration step should be a minimal live probe request
## Minimal probe template
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "YOUR_SPECIAL_MODEL",
"messages": [
{
"role": "user",
"content": "Hello"
}
],
"max_tokens": 64
}'
```
If the result contains:
* normal `choices`
the channel is currently usable
* `model_not_found`
the model is not currently available to the token
* `temporarily unavailable` or `get_channel_failed`
the model name is visible, but the current serving channel is unavailable
This page is especially likely to age quickly. For translation, OCR, and experimental special-purpose models, always treat the same-day `/v1/models` response plus one real request as the source of truth.
# Structured Outputs
Source: https://docs.crazyrouter.com/en/chat/openai/structured-output
OpenAI-style structured output verified against Crazyrouter production on 2026-03-23
# Structured Outputs
```
POST /v1/chat/completions
```
As of March 23, 2026, Crazyrouter production has verified that `gpt-5.4` with `response_format.type = "json_schema"` returns directly parseable JSON.
***
## Recommended Path: `json_schema`
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Return the people and roles from: Alice is CTO. Bob is PM."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "people_roles",
"strict": true,
"schema": {
"type": "object",
"properties": {
"people": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"role": {"type": "string"}
},
"required": ["name", "role"],
"additionalProperties": false
}
}
},
"required": ["people"],
"additionalProperties": false
}
}
}
}'
```
The observed production `message.content` parsed directly as:
```json theme={null}
{
"people": [
{
"name": "Alice",
"role": "CTO"
},
{
"name": "Bob",
"role": "PM"
}
]
}
```
***
## Consumer-Side Handling
```python theme={null}
import json
content = response["choices"][0]["message"]["content"]
data = json.loads(content)
```
This production pass only revalidated the strict `json_schema` path. The older `json_object` mode was not rechecked separately, so it is no longer kept as the primary example here.
# Vision via Chat
Source: https://docs.crazyrouter.com/en/chat/openai/vision
OpenAI-style image input, covering both base64 and remote URL usage
# Vision via Chat
```
POST /v1/chat/completions
```
Crazyrouter production has verified OpenAI-style `image_url` input on the usual vision models:
* `gpt-4o`, `gpt-4o-mini`, `gpt-4.1`, `gpt-5.4`, and other OpenAI vision models
* Both `data:image/...;base64,...` data URLs and public `https://` URLs work
* The returned `message.content` is currently a plain string
> Recommended order: for local files, use the [image upload endpoint](/en/upload) first to get a `media.crazyrouter.com` temporary URL, then pass it as `image_url`; or send a base64 data URL directly. Remote public URLs also work, but must satisfy the "Remote URL limits" below.
***
## Using a base64 data URL (most reliable)
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What color is this image?"},
{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgoAAA..."
}
}
]
}
],
"max_tokens": 100
}'
```
Sample response:
```json theme={null}
{
"model": "gpt-4o-mini",
"choices": [
{
"message": {
"role": "assistant",
"content": "Red."
}
}
]
}
```
***
## Using a remote https URL
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "Describe in 5 words."},
{
"type": "image_url",
"image_url": {
"url": "https://www.gstatic.com/webp/gallery/1.jpg"
}
}
]
}
],
"max_tokens": 40
}'
```
### Remote URL limits
The URL must be **reachable from the Crazyrouter server**, not merely "openable in a browser". Common failure modes:
| Failure | Cause | Fix |
| -------------------------- | --------------------------------------------------------------------- | ----------------------------------------------- |
| Domain cannot resolve | Private/invalid host | Use a public https URL |
| 403 Forbidden | Some CDNs (wikimedia, private S3) block server UAs or require Referer | Use the [upload endpoint](/en/upload) or base64 |
| Content-Type not `image/*` | URL returns HTML or redirects to a login page | Make sure it's a direct image link |
| File over 20MB | Single-file size limit | Compress or crop before uploading |
If you see `Unable to process the image you provided. Please verify the image URL is publicly accessible, or upload it as base64.`, the URL is not reachable from the server — work down the table above.
***
## Recommended practice
* For internal assets, private images, or anything whose reachability is uncertain: call [`POST /v1/files/uploads`](/en/upload) first for a 72-hour `media.crazyrouter.com/...` URL, then pass it to `image_url`
* For small (\< 1MB) or one-off images: send a base64 data URL directly, avoiding an extra upload round-trip
* Multi-image inputs and `detail` parameter: the OpenAI upstream supports them; pass them through following OpenAI's official spec
# Web Search
Source: https://docs.crazyrouter.com/en/chat/openai/web-search
Production-revalidated OpenAI-style web search on Crazyrouter
# Web Search
This page only documents OpenAI-style web search behavior that was revalidated against Crazyrouter production on `2026-03-22`.
The current primary path is:
* `gpt-5.4`
* `POST /v1/responses`
* `tools: [{ "type": "web_search_preview" }]`
## Current conclusion
In today's production recheck:
* `gpt-5.4` via the Responses API reliably returned `web_search_call`
* the older Chat Completions probe using `tools: [{ "type": "web_search" }]` returned `200`, but did not provide a stable, verifiable search trigger signal, so it is not used as the primary documented pattern
***
## Verified request
```bash cURL theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Use web search to find one current technology headline published recently.",
"tools": [
{
"type": "web_search_preview"
}
]
}'
```
Verified `output.type` values:
```json theme={null}
["web_search_call", "message"]
```
This shows that the search step and the final answer are returned separately.
***
## Python example
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.responses.create(
model="gpt-5.4",
input="Use web search to find one current technology headline published recently.",
tools=[
{"type": "web_search_preview"}
]
)
print(response.output_text)
```
***
## How to confirm search actually ran
Inspect `response.output` directly:
```python Python theme={null}
for item in response.output:
print(item.type)
```
If you see:
```text theme={null}
web_search_call
message
```
then the model searched first and answered second.
***
## Older pattern not recommended as primary
This production recheck also probed the older Chat Completions shape:
```json theme={null}
{
"tools": [
{
"type": "web_search"
}
]
}
```
Result:
* the request returned `200`
* but no stable, verifiable search trigger marker was observed
So for Crazyrouter docs, OpenAI-style web search should currently be documented through the Responses API first.
Related pages:
* [Responses Web Search](/en/chat/responses/web-search)
* [Feature Hub: Web Search](/en/features/web-search)
# Create Response
Source: https://docs.crazyrouter.com/en/chat/responses/create
Responses API basics verified against Crazyrouter production on 2026-03-23
# Create Response
```
POST /v1/responses
```
As of March 23, 2026, Crazyrouter production has verified:
* `gpt-5.4` returns `object: "response"`
* basic text requests currently return `output` items of type `message`
* streaming requests consistently expose `response.created`, `response.in_progress`, `response.output_item.added`, `response.content_part.added`, and `response.output_text.delta`
Claude does not currently support `POST /v1/responses`. Use `POST /v1/messages` or `POST /v1/chat/completions` for Claude instead.
***
## Basic Request
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Explain what an API is in one sentence."
}'
```
Observed production response shape:
```json theme={null}
{
"object": "response",
"model": "gpt-5.4",
"output": [
{
"type": "message"
}
]
}
```
***
## Streaming Request
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Say hello in one sentence.",
"stream": true
}'
```
The production streaming probe on 2026-03-23 observed this opening event sequence:
```text theme={null}
event: response.created
event: response.in_progress
event: response.output_item.added
event: response.content_part.added
event: response.output_text.delta
```
So the safest current consumer strategy is:
1. accumulate text from `response.output_text.delta`
2. treat `response.completed` or stream termination as the completion signal
***
## Current Recommendation
* Start new GPT text integrations with `gpt-5.4` on `/v1/responses`
* For tool use, continue with [Responses Function Calling](/chat/responses/function-calling)
* For live web access, continue with [Responses Web Search](/chat/responses/web-search)
* For visible reasoning markers, continue with [GPT-5 Thinking](/chat/responses/gpt5-thinking)
# Responses Function Calling
Source: https://docs.crazyrouter.com/en/chat/responses/function-calling
Responses tool calling verified against Crazyrouter production on 2026-03-23
# Responses Function Calling
```
POST /v1/responses
```
As of March 23, 2026, Crazyrouter production has verified that `gpt-5.4` on the Responses API reliably returns `function_call`.
Claude does not currently support `POST /v1/responses`. If you need Claude tool calling, use `POST /v1/messages` or `POST /v1/chat/completions`.
***
## Step 1: Let the Model Produce a Function Call
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "What is the weather in Beijing? Use the tool.",
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get weather info for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
]
}'
```
Observed production response shape:
```json theme={null}
{
"output": [
{
"type": "function_call",
"name": "get_weather",
"arguments": "{\"city\":\"Beijing\"}"
}
]
}
```
***
## Step 2: Return the Tool Result
Once you receive the `function_call`, send your actual tool result back as `function_call_output`:
```json theme={null}
{
"model": "gpt-5.4",
"input": [
{
"type": "function_call",
"call_id": "call_123",
"name": "get_weather",
"arguments": "{\"city\":\"Beijing\"}"
},
{
"type": "function_call_output",
"call_id": "call_123",
"output": "{\"temperature\":22,\"condition\":\"sunny\"}"
}
],
"tools": [
{
"type": "function",
"name": "get_weather",
"description": "Get weather info for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"],
"additionalProperties": false
}
}
]
}
```
This page keeps only the `function_call` path that was reproduced in production. For more complex multi-tool chains or streamed argument deltas, revalidate on the same day before depending on them.
# GPT-5 Thinking Mode
Source: https://docs.crazyrouter.com/en/chat/responses/gpt5-thinking
Production-revalidated GPT-5.4 reasoning via the Responses API
# GPT-5 Thinking Mode
This page only documents GPT reasoning behavior that was revalidated against Crazyrouter production on `2026-03-22`.
The current primary example uses:
* `gpt-5.4`
* `POST /v1/responses`
Claude does not currently support `POST /v1/responses`. If you are integrating Claude, use `POST /v1/messages` or `POST /v1/chat/completions` instead of the request shape on this page.
```
POST /v1/responses
```
***
## Basic usage
```bash cURL theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Which is larger, 9.11 or 9.9? Explain briefly.",
"reasoning": {
"effort": "high",
"summary": "detailed"
}
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.responses.create(
model="gpt-5.4",
input="Which is larger, 9.11 or 9.9? Explain briefly.",
reasoning={
"effort": "high",
"summary": "detailed"
}
)
print(response.output_text)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const response = await client.responses.create({
model: "gpt-5.4",
input: "Which is larger, 9.11 or 9.9? Explain briefly.",
reasoning: {
effort: "high",
summary: "detailed",
},
});
console.log(response.output_text);
```
***
## Verified response shape
Verified `output.type` values:
```json theme={null}
["reasoning", "message"]
```
Typical `reasoning` item shape:
```json theme={null}
{
"id": "rs_xxx",
"type": "reasoning",
"encrypted_content": "...",
"summary": [
{
"type": "summary_text",
"text": "..."
}
]
}
```
The final answer is returned through the `message` item:
```json theme={null}
{
"type": "message",
"content": [
{
"type": "output_text",
"text": "..."
}
]
}
```
***
## `reasoning` parameter
| Field | Type | Description |
| --------- | ------ | ------------------------------------------------------------------------ |
| `effort` | string | Reasoning intensity. Verified values include `low`, `medium`, and `high` |
| `summary` | string | Summary granularity. `concise` and `detailed` were revalidated |
### Practical rule
* If you only want stronger reasoning, send `effort`
* If you need an inspectable reasoning summary, send both `effort` and `summary`
In the current recheck:
* with only `effort`, the `reasoning` item existed but `summary` could be an empty array
* with `summary: "detailed"`, `summary_text` was returned reliably
***
## Extract the thinking summary
```python Python theme={null}
response = client.responses.create(
model="gpt-5.4",
input="Design a high-concurrency message queue architecture.",
reasoning={
"effort": "high",
"summary": "detailed"
}
)
for item in response.output:
if item.type == "reasoning":
for part in item.summary:
if part.type == "summary_text":
print("Thinking summary:", part.text)
elif item.type == "message":
for content in item.content:
if content.type == "output_text":
print("Final answer:", content.text)
```
***
## Streaming thinking
The following Responses SSE event names were revalidated in production:
* `response.reasoning_summary_part.added`
* `response.reasoning_summary_text.delta`
* `response.reasoning_summary_text.done`
* `response.output_text.delta`
* `response.output_text.done`
* `response.completed`
Example:
```python Python theme={null}
stream = client.responses.create(
model="gpt-5.4",
input="Explain briefly why 9.9 is larger than 9.11.",
reasoning={
"effort": "high",
"summary": "detailed"
},
stream=True
)
for event in stream:
if event.type == "response.reasoning_summary_text.delta":
print(f"[Thinking summary] {event.delta}", end="")
elif event.type == "response.output_text.delta":
print(event.delta, end="")
```
***
## Current recommendation
* If you need a visible reasoning field, prefer `gpt-5.4` with the Responses API
* Do not treat `gpt-5.4` Chat Completions `reasoning_content` as the current primary contract
* If you only care about the final answer, Chat Completions with `reasoning_effort` is still fine
Reasoning mode increases both latency and token usage. Higher `effort` generally costs more.
# Responses API Overview
Source: https://docs.crazyrouter.com/en/chat/responses/overview
Production-revalidated guidance for choosing between Responses API and Chat Completions on Crazyrouter
# Responses API Overview
The Responses API is currently one of the main routes for newer GPT capabilities on Crazyrouter.
This page only documents conclusions that were revalidated against production on `2026-03-22`.
In the current production-verified scope, Claude supports only `POST /v1/messages` and `POST /v1/chat/completions`, not `POST /v1/responses`. Treat the Responses pages as GPT-first guidance.
## Current framing
* If you need inspectable reasoning output, prefer `/v1/responses`
* If you need OpenAI-style web search, prefer `/v1/responses`
* If you only need ordinary chat or want to keep an existing integration, `/v1/chat/completions` is still fine
## Responses API vs Chat Completions API
| Dimension | Responses API | Chat Completions API |
| ----------------------- | ---------------------------------- | -------------------------------------------------------------------------------------- |
| Endpoint | `/v1/responses` | `/v1/chat/completions` |
| Input shape | `input` | `messages` |
| Output shape | `output[]` item list | `choices[].message` |
| GPT reasoning | Verified `reasoning` item | `reasoning_effort` works, but `reasoning_content` is not stable |
| OpenAI-style web search | Verified `web_search_preview` path | The older `web_search` shape did not produce a stable verifiable trigger in this round |
| Streaming | Richer event types | Traditional delta SSE |
***
## Smallest useful example
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.responses.create(
model="gpt-5.4",
input="Explain what a REST API is in one sentence."
)
print(response.output_text)
```
In the current production recheck, this kind of minimal request returned:
```json theme={null}
{
"object": "response",
"output": [
{
"type": "message"
}
]
}
```
***
## When to prefer Responses
* You need `gpt-5.4` reasoning summaries
* You need to verify whether the model actually triggered `web_search_call`
* You want richer SSE events
Related pages:
* [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
* [Responses Web Search](/en/chat/responses/web-search)
* [Responses Function Calling](/en/chat/responses/function-calling)
***
## When to keep Chat Completions
* You already have a stable Chat Completions integration
* You only care about the final answer, not the `reasoning` item
* You are integrating Claude, Gemini, or other OpenAI-compatible models
Both APIs can coexist in the same project. In practice, the better pattern is usually not a full migration, but moving only the requests that need newer capabilities onto `/v1/responses`.
# Responses Web Search
Source: https://docs.crazyrouter.com/en/chat/responses/web-search
Responses web search verified against Crazyrouter production on 2026-03-23
# Responses Web Search
```
POST /v1/responses
```
As of March 23, 2026, Crazyrouter production has verified `gpt-5.4` on the Responses API using:
* `tools: [{ "type": "web_search_preview" }]`
* an `output` sequence of `web_search_call`, then `message`
Claude does not currently support `POST /v1/responses`. For Claude web search, use `POST /v1/chat/completions` or the native Claude path instead.
***
## Minimal Request
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Find one AI news item from March 2026.",
"tools": [
{
"type": "web_search_preview"
}
]
}'
```
Observed production response shape:
```json theme={null}
{
"output": [
{
"type": "web_search_call"
},
{
"type": "message"
}
]
}
```
***
## Current Verification Rule
If you need to confirm that the model actually searched the web, the safest current checks are:
* whether `web_search_call` appears in `output`
* whether the final answer still arrives as a `message`
This page no longer keeps older outdated examples, and it does not document un-revalidated search parameters as the current primary path.
# Contact Support
Source: https://docs.crazyrouter.com/en/contact
Get help and technical support
## Contact Us
If you encounter any issues while using the service, you can reach us through the following channels:
* **Website**: [crazyrouter.com](https://crazyrouter.com)
* **Documentation**: The documentation site you are currently reading
## FAQ
Before contacting support, we recommend checking:
* [Quick Start Guide](/en/quickstart) - Basic usage tutorial
* [Error Handling](/en/error-handling) - Common error solutions
* [API Endpoints](/en/api-endpoint) - Endpoint address reference
# HTTP Status Codes & Error Handling
Source: https://docs.crazyrouter.com/en/error-handling
Understanding API status codes and error responses
## HTTP Status Codes
| Status Code | Description |
| ----------- | ------------------------------------------------------------------- |
| 200 | Request successful |
| 400 | Invalid request parameters |
| 401 | Authentication failed - API Key is invalid or missing |
| 403 | Insufficient permissions - Token does not have access to this model |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 502 | Upstream service unavailable |
| 503 | Service temporarily unavailable |
## Error Response Format
```json theme={null}
{
"error": {
"message": "Error description",
"type": "error_type",
"code": "error_code"
}
}
```
## Common Errors
### 401 - Authentication Failed
```json theme={null}
{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"code": "invalid_api_key"
}
}
```
**Solution**: Verify that your API Key is correct and starts with `sk-`.
### 429 - Rate Limited
```json theme={null}
{
"error": {
"message": "Rate limit exceeded",
"type": "rate_limit_error",
"code": "rate_limit_exceeded"
}
}
```
**Solution**: Reduce your request frequency, or contact support to increase your limit.
### 403 - Insufficient Balance
```json theme={null}
{
"error": {
"message": "Insufficient quota",
"type": "insufficient_quota",
"code": "insufficient_quota"
}
}
```
**Solution**: Visit the [top-up page](https://crazyrouter.com/topup) to add funds.
## Retry Recommendations
* For 429 errors, use exponential backoff retry
* For 500/502/503 errors, wait a few seconds before retrying
* For 400/401/403 errors, check your request parameters and authentication credentials
# Reasoning
Source: https://docs.crazyrouter.com/en/features/reasoning
Production-verified reasoning and thinking with the latest GPT, Claude, and Gemini models
# Reasoning
This page only documents reasoning flows that were **verified with real requests against Crazyrouter production**.
Verification date:
* `2026-03-22`
Verified models:
* `gpt-5.4`
* `claude-opus-4-7`
* `gemini-3-pro`
## Verified matrix
| Model | Protocol | Endpoint | Success marker |
| ----------------- | ------------------ | --------------------------------------------- | --------------------------------------------- |
| `gpt-5.4` | OpenAI Responses | `POST /v1/responses` | `output` includes a `reasoning` item |
| `claude-opus-4-7` | Anthropic Messages | `POST /v1/messages` | Returns `thinking` block |
| `gemini-3-pro` | Gemini Native | `POST /v1beta/models/{model}:generateContent` | `usageMetadata` includes `thoughtsTokenCount` |
## GPT-5.4
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Which is larger, 9.11 or 9.9? Explain briefly.",
"reasoning": {
"effort": "high",
"summary": "detailed"
}
}'
```
Verified output types:
```json theme={null}
["reasoning", "message"]
```
Verified `reasoning` item shape:
```json theme={null}
{
"type": "reasoning",
"summary": [
{
"type": "summary_text",
"text": "..."
}
]
}
```
## Claude Opus 4.7 Thinking
```bash theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-opus-4-7",
"max_tokens": 320,
"thinking": {
"type": "enabled",
"budget_tokens": 128
},
"messages": [
{
"role": "user",
"content": "Which is larger, 9.11 or 9.9? Explain briefly."
}
]
}'
```
Verified response shape:
```json theme={null}
{
"content": [
{
"type": "thinking"
},
{
"type": "text"
}
]
}
```
## Gemini 3 Pro
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Which is larger, 9.11 or 9.9? Explain briefly."
}
]
}
],
"generationConfig": {
"thinkingConfig": {
"thinkingBudget": 256
},
"maxOutputTokens": 512
}
}'
```
Verified production field:
* `usageMetadata.thoughtsTokenCount`
## Current exclusions
* In the current recheck, `gpt-5.4` via Chat Completions did not reliably surface `reasoning_content`, so this page uses the Responses API as the primary GPT example
* Base `claude-opus-4-6` did not return a thinking block in this verification round
## See Also
* [OpenAI Reasoning](/en/chat/openai/reasoning)
* [GPT-5 Thinking](/en/chat/responses/gpt5-thinking)
* [Thinking Fields](/en/reference/thinking)
* [Claude Native Messages](/en/chat/anthropic/messages)
* [Gemini Native API](/en/chat/gemini/native)
# Structured Outputs
Source: https://docs.crazyrouter.com/en/features/structured-outputs
Production-verified structured JSON output with the latest GPT and Gemini models
# Structured Outputs
This page only documents Structured Output flows that were **verified with real requests against Crazyrouter production**.
Verification date:
* `2026-03-22`
Strictly verified models:
* `gpt-5.4`
* `gemini-3-pro`
Not included as a strict-success example:
* `claude-sonnet-4-6`
Reason:
* Under the current OpenAI-compatible `response_format=json_schema` request shape, `claude-sonnet-4-6` did not show stable strict-JSON behavior across production checks
* Earlier testing produced JSON wrapped in Markdown code fences
* The `2026-03-22` recheck returned empty `content`
* Because the result is not stable or strictly parseable, it is not treated as a verified strict structured-output success example
## Verified matrix
| Model | Protocol | Endpoint | Success marker |
| -------------- | ----------------------- | --------------------------------------------- | --------------------------------------- |
| `gpt-5.4` | OpenAI Chat Completions | `POST /v1/chat/completions` | Response can be parsed directly as JSON |
| `gemini-3-pro` | Gemini Native | `POST /v1beta/models/{model}:generateContent` | Returns JSON text matching schema |
## GPT-5.4
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Return a JSON object with keys city and country for Tokyo."
}
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "city_country",
"strict": true,
"schema": {
"type": "object",
"properties": {
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["city", "country"],
"additionalProperties": false
}
}
}
}'
```
Verified production output:
```json theme={null}
{"city":"Tokyo","country":"Japan"}
```
## Gemini 3 Pro
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Return a JSON object with keys city and country for Tokyo."
}
]
}
],
"generationConfig": {
"responseMimeType": "application/json",
"responseSchema": {
"type": "object",
"properties": {
"city": { "type": "string" },
"country": { "type": "string" }
},
"required": ["city", "country"]
}
}
}'
```
Verified production output:
```json theme={null}
{"city":"Tokyo","country":"Japan"}
```
## See Also
* [OpenAI Structured Output](/en/chat/openai/structured-output)
* [Gemini Document Understanding](/en/chat/gemini/document)
# Tool Calling
Source: https://docs.crazyrouter.com/en/features/tool-calling
Production-verified tool calling with the latest GPT, Claude, and Gemini models
# Tool Calling
This page only documents Tool Calling flows that were **verified with real requests against Crazyrouter production**.
Verification date:
* `2026-03-22`
Verified models:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Verified matrix
| Model | Protocol | Endpoint | Success marker |
| ------------------- | ----------------------- | --------------------------------------------- | ------------------------ |
| `gpt-5.4` | OpenAI Chat Completions | `POST /v1/chat/completions` | Returns `tool_calls` |
| `claude-sonnet-4-6` | Anthropic Messages | `POST /v1/messages` | Returns `tool_use` block |
| `gemini-3-pro` | Gemini Native | `POST /v1beta/models/{model}:generateContent` | Returns `functionCall` |
## GPT-5.4
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "Use the get_time tool for Asia/Shanghai. Do not answer without calling the tool."
}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_time",
"description": "Get the current time for a timezone",
"parameters": {
"type": "object",
"properties": {
"timezone": { "type": "string" }
},
"required": ["timezone"],
"additionalProperties": false
}
}
}
],
"tool_choice": "required"
}'
```
Verified response shape:
```json theme={null}
{
"tool_calls": [
{
"type": "function",
"function": {
"name": "get_time"
}
}
]
}
```
## Claude Sonnet 4.6
```bash theme={null}
curl https://crazyrouter.com/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-6",
"max_tokens": 256,
"tools": [
{
"name": "get_time",
"description": "Get the current time for a timezone",
"input_schema": {
"type": "object",
"properties": {
"timezone": { "type": "string" }
},
"required": ["timezone"]
}
}
],
"tool_choice": {
"type": "any"
},
"messages": [
{
"role": "user",
"content": "Use the get_time tool for Asia/Shanghai. Do not answer directly."
}
]
}'
```
Verified response shape:
```json theme={null}
{
"stop_reason": "tool_use",
"content": [
{
"type": "tool_use",
"name": "get_time"
}
]
}
```
For first-pass validation, use an explicit `tool_choice` and clearly instruct Claude not to answer directly.
## Gemini 3 Pro
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Use the get_time function for Asia/Shanghai."
}
]
}
],
"tools": [
{
"functionDeclarations": [
{
"name": "get_time",
"description": "Get the current time for a timezone",
"parameters": {
"type": "object",
"properties": {
"timezone": { "type": "string" }
},
"required": ["timezone"]
}
}
]
}
]
}'
```
Verified response shape:
```json theme={null}
{
"candidates": [
{
"content": {
"parts": [
{
"functionCall": {
"name": "get_time"
}
}
]
}
}
]
}
```
## See Also
* [OpenAI Function Calling](/en/chat/openai/function-calling)
* [Responses Function Calling](/en/chat/responses/function-calling)
* [Gemini Tools](/en/chat/gemini/tools)
* [Claude Native Messages](/en/chat/anthropic/messages)
# Web Search
Source: https://docs.crazyrouter.com/en/features/web-search
Production-verified web search with the latest GPT, Claude, and Gemini models
# Web Search
This page only documents Web Search flows that were **verified with real requests against Crazyrouter production**.
Verification date:
* `2026-03-22`
Verified models:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Verified matrix
| Model | Protocol | Endpoint | Success marker |
| ------------------- | ---------------------- | --------------------------------------------- | ------------------------------------- |
| `gpt-5.4` | OpenAI Responses | `POST /v1/responses` | `output` includes `web_search_call` |
| `claude-sonnet-4-6` | OpenAI-compatible Chat | `POST /v1/chat/completions` | Returns `remote_web_search` tool call |
| `gemini-3-pro` | Gemini Native | `POST /v1beta/models/{model}:generateContent` | Returns `groundingMetadata` |
## GPT-5.4
```bash theme={null}
curl https://crazyrouter.com/v1/responses \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"input": "Use web search to find one current headline from a major technology news site published recently.",
"tools": [
{
"type": "web_search_preview"
}
]
}'
```
Verified output types:
```json theme={null}
["web_search_call", "web_search_call", "message"]
```
## Claude Sonnet 4.6
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [
{
"role": "user",
"content": "Find one recent technology headline. Use web search and do not answer from memory."
}
],
"web_search_options": {
"search_context_size": "medium",
"user_location": {
"approximate": {
"timezone": "Asia/Shanghai",
"country": "CN"
}
}
},
"max_tokens": 200
}'
```
Verified response shape:
```json theme={null}
{
"tool_calls": [
{
"type": "function",
"function": {
"name": "remote_web_search"
}
}
],
"finish_reason": "tool_calls"
}
```
For first-pass validation, explicitly tell Claude to use web search and not answer from memory. With weaker prompts, it may answer directly without surfacing the tool call.
## Gemini 3 Pro
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Use Google Search to find one recent headline from a major technology news site."
}
]
}
],
"tools": [
{
"googleSearch": {}
}
]
}'
```
Verified production fields:
* `groundingMetadata.webSearchQueries`
* `groundingMetadata.groundingChunks`
* `groundingMetadata.groundingSupports`
## See Also
* [Responses Web Search](/en/chat/responses/web-search)
* [OpenAI Web Search](/en/chat/openai/web-search)
* [Gemini Tools](/en/chat/gemini/tools)
# GPT Image
Source: https://docs.crazyrouter.com/en/images/gpt-image
Generate and edit images with gpt-image-2 through the OpenAI-compatible Images API
# GPT Image
`gpt-image-2` uses the OpenAI-compatible Images API:
```text theme={null}
POST /v1/images/generations
POST /v1/images/edits
```
Use the primary image route `https://cn.crazyrouter.com/v1` for `gpt-image-2`. The full generation endpoint is `https://cn.crazyrouter.com/v1/images/generations`. Account login, billing, and the console remain on `https://crazyrouter.com`.
## Generate Image
### Request Parameters
| Parameter | Type | Required | Description |
| -------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `model` | string | Yes | Fixed as `gpt-image-2` |
| `prompt` | string | Yes | Image description prompt |
| `n` | integer | No | Number of images, default `1`, range `1-10` |
| `size` | string | No | `auto` or `WxH`. Dimensions must be multiples of 16, each side must be at most 3840, total pixels must be 655360 to 8294400, and the long:short side ratio must not exceed 3:1. Common values: `1024x1024`, `1536x1024`, `1024x1536` |
| `quality` | string | No | `auto`, `low`, `medium`, `high`. `hd` is accepted for compatibility and normalized to `high`; `standard` is rejected |
| `background` | string | No | `auto` or `opaque`. `transparent` is not supported for `gpt-image-2` |
| `output_format` | string | No | `png`, `jpeg`, `webp` |
| `output_compression` | integer | No | `0-100`, only with `output_format=jpeg` or `output_format=webp` |
| `moderation` | string | No | `auto` or `low` |
| `stream` | boolean | No | Return an SSE stream |
| `partial_images` | integer | No | `0-3`, only when `stream=true` |
| `user` | string | No | End-user identifier |
These parameters are rejected for `gpt-image-2`: `response_format`, `style`, `input_fidelity`, `background=transparent`, `quality=standard`, and `output_format=png` with `output_compression`.
`response_format` is not a `gpt-image-2` parameter. Do not send `response_format="url"` or `response_format="b64_json"`; use `output_format="png"`, `"jpeg"`, or `"webp"` to choose the image file format, and read `data[0].url` from the response by default. `response_format` notes on DALL-E, Doubao, Qwen, or other image-model pages do not apply to `gpt-image-2`.
### Request Examples
```bash cURL theme={null}
curl -X POST https://cn.crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "A cat wearing a spacesuit walking on the moon with Earth in the background",
"n": 1,
"size": "1024x1024",
"quality": "low",
"output_format": "png"
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://cn.crazyrouter.com/v1",
)
response = client.images.generate(
model="gpt-image-2",
prompt="A cat wearing a spacesuit walking on the moon with Earth in the background",
n=1,
size="1024x1024",
quality="low",
output_format="png",
)
print(response.data[0].url)
```
### Streaming
`gpt-image-2` supports `stream=true`. If you send `partial_images`, you must also set `stream=true`, and the value must be `0-3`.
```bash cURL theme={null}
curl -N -X POST https://cn.crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-image-2",
"prompt": "A simple blue verification icon on a white background",
"size": "1024x1024",
"quality": "high",
"stream": true,
"partial_images": 2
}'
```
Synchronous `quality=high` requests, including the compatibility value `quality=hd`, can take a long time. For image workloads, use `https://cn.crazyrouter.com/v1`; for high-quality jobs, prefer `stream=true` or set your client timeout above 180 seconds.
### Response Example
```json theme={null}
{
"created": 1778990000,
"data": [
{
"url": "https://media.crazyrouter.com/task-artifacts/2026/05/17/sync-image/request-id-1.png"
}
],
"output_format": "png",
"quality": "low",
"size": "1024x1024"
}
```
***
## Edit Image
```
POST /v1/images/edits
```
Edit an existing image with mask-based region editing support. You can also pass multiple reference images for blending, style transfer, or composition work.
### Request Parameters
| Parameter | Type | Required | Description |
| -------------------- | --------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
| `model` | string | Yes | Fixed as `gpt-image-2` |
| `image` / `image[]` | file or file\[] | Yes | Original image or reference image file(s), sent as multipart; `gpt-image-2` supports up to `16` reference images |
| `prompt` | string | Yes | Edit description |
| `mask` | file | No | Mask image; transparent areas indicate regions to edit |
| `n` | integer | No | Number of images, default `1`, range `1-10` |
| `size` | string | No | Same rules as generation |
| `quality` | string | No | `auto`, `low`, `medium`, `high`; `hd` is normalized to `high` |
| `background` | string | No | `auto` or `opaque` |
| `output_format` | string | No | `png`, `jpeg`, `webp` |
| `output_compression` | integer | No | `0-100`, only with `output_format=jpeg` or `output_format=webp` |
| `stream` | boolean | No | Return an SSE stream |
| `partial_images` | integer | No | `0-3`, only when `stream=true` |
### Single-Image Edit Example
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://cn.crazyrouter.com/v1",
)
response = client.images.edit(
model="gpt-image-2",
image=open("original.png", "rb"),
mask=open("mask.png", "rb"),
prompt="Add a rainbow in the sky",
n=1,
size="1024x1024",
quality="low",
)
print(response.data[0].url)
```
### Multi-Reference Edit Example
Multi-image editing requests must use `multipart/form-data`. Prefer multiple `image[]` fields for reference images; repeated `image` fields are also accepted.
```bash cURL theme={null}
curl -X POST https://cn.crazyrouter.com/v1/images/edits \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "model=gpt-image-2" \
-F "prompt=Blend the person from the first image with the background from the second image into one natural campaign visual" \
-F "size=1024x1024" \
-F "quality=low" \
-F "n=1" \
-F "image[]=@person.png" \
-F "image[]=@background.png"
```
```python Python theme={null}
import requests
response = requests.post(
"https://cn.crazyrouter.com/v1/images/edits",
headers={"Authorization": "Bearer YOUR_API_KEY"},
data={
"model": "gpt-image-2",
"prompt": "Blend the person from the first image with the background from the second image into one natural campaign visual",
"size": "1024x1024",
"quality": "low",
"n": "1",
},
files=[
("image[]", ("person.png", open("person.png", "rb"), "image/png")),
("image[]", ("background.png", open("background.png", "rb"), "image/png")),
],
timeout=240,
)
response.raise_for_status()
print(response.json()["data"][0]["url"])
```
`gpt-image-2` supports up to 16 reference images. Multi-image requests are routed to carriers that support multi-reference image editing.
# Grok Image Models
Source: https://docs.crazyrouter.com/en/images/grok
Generate images with grok-4-image and grok-4-image, including supported parameters and differences
# Grok Image Models
```
POST /v1/images/generations
```
Grok image models use the OpenAI-compatible Images path. There are two names you should treat differently:
| Model | Description | Recommendation |
| -------------- | --------------------------------------------------------------------------- | -------------------------------------- |
| `grok-4-image` | Official xAI image model name, billed at the official `$0.02 / image` price | Recommended for new integrations |
| `grok-4-image` | Historical / compatibility model name on third-party compatible channels | Use only the safe subset of parameters |
`grok-4-image` is not the official xAI model name. Do not assume it is fully equivalent to `grok-4-image`. New integrations should prefer `grok-4-image`.
## grok-4-image Parameters
| Parameter | Type | Required | Description |
| ----------------- | ------- | -------- | ----------------------------------------------------------------------------------- |
| `model` | string | Yes | Use `grok-4-image` |
| `prompt` | string | Yes | Image prompt |
| `n` | integer | No | Number of images, official range `1` to `10`. Use `1` first for stable cost control |
| `response_format` | string | No | `url` or `b64_json`. The live Crazyrouter path is stable with `url` |
| `aspect_ratio` | string | No | Examples: `1:1`, `16:9`, `9:16`, `3:2`, `auto` |
| `resolution` | string | No | `1k` or `2k` |
`aspect_ratio` and `resolution` are xAI image endpoint extensions. With the OpenAI Python SDK, pass them through `extra_body`; with cURL or the Node.js SDK, put them directly in the JSON body.
Do not pass these parameters:
| Parameter | Reason |
| --------- | --------------------------------------------------------------- |
| `size` | Not supported by xAI; it returns `Argument not supported: size` |
| `quality` | Not supported by the xAI image endpoint |
| `style` | Not supported by the xAI image endpoint |
## grok-4-image Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "grok-4-image",
"prompt": "A tiny yellow cube on a plain white background, minimal product photo",
"n": 1,
"response_format": "url",
"aspect_ratio": "1:1",
"resolution": "1k"
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1",
)
response = client.images.generate(
model="grok-4-image",
prompt="A tiny yellow cube on a plain white background, minimal product photo",
n=1,
response_format="url",
extra_body={
"aspect_ratio": "1:1",
"resolution": "1k",
},
)
print(response.data[0].url)
```
Image URLs returned with `response_format: "url"` are temporary. Download or store the image after generation if you need durable access.
```javascript Node.js theme={null}
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const response = await client.images.generate({
model: "grok-4-image",
prompt: "A tiny yellow cube on a plain white background, minimal product photo",
n: 1,
response_format: "url",
aspect_ratio: "1:1",
resolution: "1k",
});
console.log(response.data[0].url);
```
## Response Example
The live response may include `url`, `mime_type`, and `revised_prompt`:
```json theme={null}
{
"created": 1776527939,
"data": [
{
"url": "https://...",
"mime_type": "image/jpeg",
"revised_prompt": "A tiny yellow cube on a plain white background..."
}
]
}
```
## grok-4-image Differences
Use only this safe subset for `grok-4-image`:
| Parameter | Support |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| `model` | Use `grok-4-image` |
| `prompt` | Supported |
| `n` | Use `1` only. A live `n=2` test returned 1 image but billed 2 images; the gateway has been narrowed to `1` |
| `response_format` | `url` is stable. `b64_json` may be accepted but the live route still returned `url` |
| `aspect_ratio` | Accepted by the request path, but third-party enforcement should be verified per output |
| `resolution` | Accepted by the request path, but third-party enforcement should be verified per output |
Do not promise these for `grok-4-image`:
* multi-image `n > 1`
* guaranteed `b64_json` output
* `size`
* `quality`
* `style`
* image editing
## grok-4-image Example
```bash theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "grok-4-image",
"prompt": "A single red cube on a plain white background, product photo",
"n": 1,
"response_format": "url"
}'
```
## Billing
| Model | Current Billing |
| -------------- | -------------------------------------------------- |
| `grok-4-image` | `$0.02 / image`, no discount |
| `grok-4-image` | Current pricing is `$0.08 * 0.55 = $0.044 / image` |
The live pricing page and usage logs are the source of truth. Grok image models are billed per image, not by input/output tokens.
## Common Errors
| Error | Fix |
| ------------------------------ | --------------------------------------------------------------------------------------- |
| `Argument not supported: size` | Do not send `size`; use `aspect_ratio` and `resolution` |
| `model_price_error` | The model is missing pricing or the token cannot use it |
| `model_not_found` | Check the model name, token permissions, and channel availability with `GET /v1/models` |
# Ideogram Legacy
Source: https://docs.crazyrouter.com/en/images/ideogram/legacy
Use the Ideogram Legacy API for image generation, remixing, upscaling, and description
# Ideogram Legacy
The Ideogram Legacy API provides basic image generation capabilities.
We recommend using [Ideogram V3](/en/images/ideogram/v3) for better generation results.
## Generate Image
```
POST /ideogram/generate
```
### Request Parameters
| Parameter | Type | Required | Description |
| ----------------------------------- | ------ | -------- | --------------------------------- |
| `image_request` | object | Yes | Image request object |
| `image_request.prompt` | string | Yes | Prompt |
| `image_request.model` | string | No | Model version: `V_2`, `V_2_TURBO` |
| `image_request.aspect_ratio` | string | No | Aspect ratio |
| `image_request.magic_prompt_option` | string | No | Prompt enhancement |
| `image_request.style_type` | string | No | Style type |
| `image_request.negative_prompt` | string | No | Negative prompt |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/generate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"image_request": {
"prompt": "A futuristic cityscape at night with neon lights",
"model": "V_2",
"aspect_ratio": "ASPECT_16_9",
"magic_prompt_option": "AUTO"
}
}'
```
### Response Example
```json theme={null}
{
"created": 1709123456,
"data": [
{
"url": "https://ideogram.ai/assets/image/...",
"prompt": "A futuristic cityscape at night with neon lights",
"resolution": "1344x768",
"seed": 67890
}
]
}
```
***
## Remix
```
POST /ideogram/remix
```
Generate variations based on a reference image.
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/remix \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"image_request": {
"prompt": "Same scene in anime style",
"model": "V_2"
},
"image_file": "https://example.com/photo.jpg"
}'
```
***
## Upscale Image
```
POST /ideogram/upscale
```
Upscale an image to a higher resolution.
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/upscale \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"image_request": {
"prompt": "high quality detailed image"
},
"image_file": "https://example.com/photo.jpg"
}'
```
***
## Describe Image
```
POST /ideogram/describe
```
Let the model describe the image content and generate corresponding prompts.
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/describe \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"image_file": "https://example.com/photo.jpg"
}'
```
### Response Example
```json theme={null}
{
"descriptions": [
{
"text": "A futuristic cityscape at night with vibrant neon lights reflecting off wet streets, tall skyscrapers with holographic advertisements"
}
]
}
```
# Ideogram V3
Source: https://docs.crazyrouter.com/en/images/ideogram/v3
Use the Ideogram V3 API for image generation, editing, blending, reframing, and background replacement
# Ideogram V3
Ideogram V3 is the latest generation text-to-image model with significant improvements in text rendering and image quality.
## Generate Image
```
POST /ideogram/v1/ideogram-v3/generate
```
### Request Parameters
| Parameter | Type | Required | Description |
| --------------------- | ------ | -------- | ------------------------------------------------------------- |
| `prompt` | string | Yes | Image description prompt |
| `aspect_ratio` | string | No | Aspect ratio, e.g. `ASPECT_1_1`, `ASPECT_16_9`, `ASPECT_9_16` |
| `model` | string | No | Model version, defaults to `V_3` |
| `magic_prompt_option` | string | No | Prompt enhancement: `AUTO`, `ON`, `OFF` |
| `rendering_speed` | string | No | Rendering speed: `DEFAULT`, `TURBO`, `QUALITY` |
| `style_type` | string | No | Style type: `AUTO`, `GENERAL`, `REALISTIC`, `DESIGN` |
| `negative_prompt` | string | No | Negative prompt |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/v1/ideogram-v3/generate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "A serene Japanese garden with cherry blossoms, text saying \"Hello World\" on a wooden sign",
"aspect_ratio": "ASPECT_16_9",
"rendering_speed": "DEFAULT",
"style_type": "REALISTIC"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/ideogram/v1/ideogram-v3/generate",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"prompt": "A serene Japanese garden with cherry blossoms",
"aspect_ratio": "ASPECT_16_9",
"style_type": "REALISTIC"
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"created": 1709123456,
"data": [
{
"url": "https://ideogram.ai/assets/image/...",
"prompt": "A serene Japanese garden with cherry blossoms",
"resolution": "1344x768",
"is_image_safe": true,
"seed": 12345
}
]
}
```
***
## Edit Image
```
POST /ideogram/v1/ideogram-v3/edit
```
Edit and modify an existing image.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------------------------------- |
| `prompt` | string | Yes | Edit description |
| `image` | string | Yes | Original image URL or Base64 |
| `mask` | string | No | Mask image, marking the area to be edited |
| `style_type` | string | No | Style type |
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/v1/ideogram-v3/edit \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "Replace the sky with a starry night",
"image": "https://example.com/photo.jpg",
"mask": "https://example.com/mask.png"
}'
```
***
## Remix Image
```
POST /ideogram/v1/ideogram-v3/remix
```
Generate variations based on a reference image and new prompt.
| Parameter | Type | Required | Description |
| -------------- | ------ | -------- | ----------------------------- |
| `prompt` | string | Yes | New prompt |
| `image` | string | Yes | Reference image |
| `image_weight` | number | No | Reference image weight, 0-100 |
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/v1/ideogram-v3/remix \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "Same scene but in watercolor painting style",
"image": "https://example.com/photo.jpg",
"image_weight": 50
}'
```
***
## Reframe
```
POST /ideogram/v1/ideogram-v3/reframe
```
Expand the image canvas, generating content beyond the original boundaries.
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------- |
| `image` | string | Yes | Original image |
| `resolution` | string | No | Target resolution |
***
## Replace Background
```
POST /ideogram/v1/ideogram-v3/replace-background
```
Automatically detect the subject and replace the background.
| Parameter | Type | Required | Description |
| --------- | ------ | -------- | -------------------------- |
| `prompt` | string | Yes | New background description |
| `image` | string | Yes | Original image |
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/ideogram/v1/ideogram-v3/replace-background \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "A tropical beach at sunset",
"image": "https://example.com/portrait.jpg"
}'
```
Ideogram V3 excels at text rendering, making it ideal for scenarios that require text within images.
# Execute Actions
Source: https://docs.crazyrouter.com/en/images/midjourney/action
Execute Midjourney follow-up actions: upscale, variation, blend, describe, and more
# Execute Actions
## Action - Upscale / Variation
```
POST /mj/submit/action
```
Execute follow-up actions on a completed Imagine task, such as Upscale, Variation, etc.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------------------------------------------------------------------- |
| `taskId` | string | Yes | Original task ID |
| `customId` | string | Yes | The `customId` of the action button, obtained from the task's `buttons` field |
| `notifyHook` | string | No | Callback URL |
| `state` | string | No | Custom state |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/action \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"taskId": "task_1234567890",
"customId": "MJ::JOB::upsample::1::abc123"
}'
```
### Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "task_action_001",
"properties": {}
}
```
***
## Blend - Image Blending
```
POST /mj/submit/blend
```
Blend multiple images to generate a new image.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------- | ------ | -------- | ---------------------------------------------------- |
| `botType` | string | No | `MID_JOURNEY` (default) or `NIJI_JOURNEY` |
| `base64Array` | array | Yes | Array of Base64-encoded images, 2-5 images |
| `dimensions` | string | No | Output dimensions: `PORTRAIT`, `SQUARE`, `LANDSCAPE` |
| `notifyHook` | string | No | Callback URL |
| `state` | string | No | Custom state |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/blend \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"base64Array": [
"data:image/png;base64,iVBORw0KGgo...",
"data:image/png;base64,iVBORw0KGgo..."
],
"dimensions": "SQUARE"
}'
```
### Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "task_blend_001"
}
```
***
## Describe - Image Description
```
POST /mj/submit/describe
```
Upload an image and let Midjourney generate corresponding prompt descriptions.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ----------------------------------------- |
| `botType` | string | No | `MID_JOURNEY` (default) or `NIJI_JOURNEY` |
| `base64` | string | Yes | Base64-encoded image |
| `notifyHook` | string | No | Callback URL |
| `state` | string | No | Custom state |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/describe \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"base64": "data:image/png;base64,iVBORw0KGgo..."
}'
```
***
## Modal - Dialog Confirmation
```
POST /mj/submit/modal
```
Submit a Midjourney modal confirmation action (e.g. Region Vary and other operations requiring secondary confirmation).
### Request Parameters
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | -------------------------- |
| `taskId` | string | Yes | Original task ID |
| `prompt` | string | No | Prompt in the modal dialog |
| `maskBase64` | string | No | Base64-encoded mask image |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/modal \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"taskId": "task_1234567890",
"prompt": "add a rainbow in the sky"
}'
```
All actions return a new task ID after submission. Use the [Query Task Status](/en/images/midjourney/query) endpoint to get results.
# Submit Imagine Task
Source: https://docs.crazyrouter.com/en/images/midjourney/imagine
Use POST /mj/submit/imagine to submit a Midjourney image generation task
# Submit Imagine Task
```
POST /mj/submit/imagine
```
Submit a Midjourney Imagine task to generate images based on a prompt.
## Request Parameters
| Parameter | Type | Required | Description |
| ------------- | ------ | -------- | -------------------------------------------------------------------- |
| `botType` | string | No | Bot type: `MID_JOURNEY` (default) or `NIJI_JOURNEY` |
| `prompt` | string | Yes | Prompt, supports native Midjourney syntax (e.g. `--ar 16:9 --v 6`) |
| `base64Array` | array | No | Array of Base64-encoded reference images for image-guided generation |
| `notifyHook` | string | No | Callback URL for task status changes |
| `state` | string | No | Custom state information, returned as-is in callbacks |
***
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/imagine \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"botType": "MID_JOURNEY",
"prompt": "a beautiful sunset over the ocean, cinematic lighting --ar 16:9 --v 6",
"notifyHook": "",
"state": ""
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/mj/submit/imagine",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"botType": "MID_JOURNEY",
"prompt": "a beautiful sunset over the ocean, cinematic lighting --ar 16:9 --v 6"
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "task_1234567890",
"properties": {}
}
```
| Field | Description |
| ------------- | ------------------------------------------------- |
| `code` | Status code, `1` means success, `22` means queued |
| `description` | Status description |
| `result` | Task ID, used for subsequent queries |
***
## Request with Reference Images
Use `base64Array` to pass reference images:
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/submit/imagine \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"botType": "MID_JOURNEY",
"prompt": "a cat in the style of the reference image --v 6",
"base64Array": [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..."
]
}'
```
***
## Using Niji Journey
Set `botType` to `NIJI_JOURNEY` to use the Niji model for anime-style images:
```json theme={null}
{
"botType": "NIJI_JOURNEY",
"prompt": "a cute anime girl with blue hair, cherry blossoms --niji 6"
}
```
After successful submission, a task ID is returned. Use the [Query Task Status](/en/images/midjourney/query) endpoint to get the generation result.
Images in `base64Array` increase the request payload size. It is recommended to keep each image under 4MB.
# Midjourney Overview
Source: https://docs.crazyrouter.com/en/images/midjourney/overview
Midjourney image generation API overview, including task objects, status descriptions, and response fields
# Midjourney Overview
Crazyrouter provides a complete Midjourney API proxy, supporting all operations including Imagine, Blend, Describe, Upscale, Variation, and more. All requests are processed asynchronously via tasks.
## Base Path
```
https://crazyrouter.com/mj
```
## Authentication
Pass your API Key in the request header:
```
Authorization: Bearer YOUR_API_KEY
```
***
## Task Object
Each Midjourney request submission returns a task object. The task object contains the following fields:
| Field | Type | Description |
| ------------- | ------ | ----------------------------------------------------------------------- |
| `id` | string | Unique task identifier |
| `action` | string | Task type: `IMAGINE`, `UPSCALE`, `VARIATION`, `BLEND`, `DESCRIBE`, etc. |
| `status` | string | Task status |
| `prompt` | string | Submitted prompt |
| `promptEn` | string | Translated English prompt |
| `description` | string | Task description |
| `submitTime` | number | Submission time (millisecond timestamp) |
| `startTime` | number | Processing start time |
| `finishTime` | number | Completion time |
| `progress` | string | Progress percentage, e.g. `"100%"` |
| `imageUrl` | string | Generated image URL |
| `failReason` | string | Failure reason (only present on failure) |
| `properties` | object | Additional properties |
| `buttons` | array | List of available action buttons |
***
## Task Status
| Status | Description |
| ------------- | --------------------------------------- |
| `NOT_START` | Task submitted, waiting to be processed |
| `SUBMITTED` | Task submitted to Midjourney |
| `IN_PROGRESS` | Task is being processed |
| `SUCCESS` | Task completed |
| `FAILURE` | Task failed |
***
## Action Buttons
After a task completes, the `buttons` field contains available follow-up actions:
```json theme={null}
{
"buttons": [
{"customId": "MJ::JOB::upsample::1::hash", "emoji": "U1", "label": "U1", "style": 2},
{"customId": "MJ::JOB::upsample::2::hash", "emoji": "U2", "label": "U2", "style": 2},
{"customId": "MJ::JOB::upsample::3::hash", "emoji": "U3", "label": "U3", "style": 2},
{"customId": "MJ::JOB::upsample::4::hash", "emoji": "U4", "label": "U4", "style": 2},
{"customId": "MJ::JOB::variation::1::hash", "emoji": "V1", "label": "V1", "style": 2},
{"customId": "MJ::JOB::variation::2::hash", "emoji": "V2", "label": "V2", "style": 2},
{"customId": "MJ::JOB::variation::3::hash", "emoji": "V3", "label": "V3", "style": 2},
{"customId": "MJ::JOB::variation::4::hash", "emoji": "V4", "label": "V4", "style": 2}
]
}
```
Use the `customId` to call the Action endpoint to perform the corresponding operation (upscale, variation, etc.).
***
## API Endpoints Overview
| Method | Endpoint | Description |
| ------ | ---------------------------- | -------------------------------------------- |
| POST | `/mj/submit/imagine` | Submit an Imagine task |
| POST | `/mj/submit/action` | Execute an action (upscale, variation, etc.) |
| POST | `/mj/submit/blend` | Blend images |
| POST | `/mj/submit/describe` | Describe an image |
| POST | `/mj/submit/modal` | Submit modal confirmation |
| POST | `/mj/submit/shorten` | Shorten a prompt |
| GET | `/mj/task/{id}/fetch` | Query a single task |
| POST | `/mj/task/list-by-condition` | Batch query tasks |
| GET | `/mj/task/{id}/image-seed` | Get image seed |
Midjourney tasks are processed asynchronously. After submission, you need to poll the task status. It is recommended to query every 3-5 seconds until the status becomes `SUCCESS` or `FAILURE`.
# Query Task Status
Source: https://docs.crazyrouter.com/en/images/midjourney/query
Query Midjourney task status, supporting single and batch queries
# Query Task Status
## Query Single Task
```
GET /mj/task/{id}/fetch
```
Query task details and status by task ID.
### Request Examples
```bash cURL theme={null}
curl https://crazyrouter.com/mj/task/task_1234567890/fetch \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://crazyrouter.com/mj/task/task_1234567890/fetch",
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
print(response.json())
```
### Response Example (Processing)
```json theme={null}
{
"id": "task_1234567890",
"action": "IMAGINE",
"status": "IN_PROGRESS",
"prompt": "a beautiful sunset over the ocean --ar 16:9 --v 6",
"promptEn": "a beautiful sunset over the ocean --ar 16:9 --v 6",
"progress": "65%",
"submitTime": 1709123456000,
"startTime": 1709123457000,
"imageUrl": "",
"failReason": "",
"buttons": []
}
```
### Response Example (Completed)
```json theme={null}
{
"id": "task_1234567890",
"action": "IMAGINE",
"status": "SUCCESS",
"prompt": "a beautiful sunset over the ocean --ar 16:9 --v 6",
"promptEn": "a beautiful sunset over the ocean --ar 16:9 --v 6",
"progress": "100%",
"submitTime": 1709123456000,
"startTime": 1709123457000,
"finishTime": 1709123520000,
"imageUrl": "https://cdn.discordapp.com/attachments/.../image.png",
"failReason": "",
"buttons": [
{"customId": "MJ::JOB::upsample::1::abc123", "emoji": "U1", "label": "U1", "style": 2},
{"customId": "MJ::JOB::upsample::2::abc123", "emoji": "U2", "label": "U2", "style": 2},
{"customId": "MJ::JOB::upsample::3::abc123", "emoji": "U3", "label": "U3", "style": 2},
{"customId": "MJ::JOB::upsample::4::abc123", "emoji": "U4", "label": "U4", "style": 2},
{"customId": "MJ::JOB::variation::1::abc123", "emoji": "V1", "label": "V1", "style": 2},
{"customId": "MJ::JOB::variation::2::abc123", "emoji": "V2", "label": "V2", "style": 2},
{"customId": "MJ::JOB::variation::3::abc123", "emoji": "V3", "label": "V3", "style": 2},
{"customId": "MJ::JOB::variation::4::abc123", "emoji": "V4", "label": "V4", "style": 2}
],
"properties": {}
}
```
***
## Batch Query Tasks
```
POST /mj/task/list-by-condition
```
Batch query tasks by conditions.
### Request Parameters
| Parameter | Type | Required | Description |
| --------- | ----- | -------- | ---------------- |
| `ids` | array | No | List of task IDs |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/mj/task/list-by-condition \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"ids": ["task_1234567890", "task_0987654321"]
}'
```
### Response Example
```json theme={null}
[
{
"id": "task_1234567890",
"action": "IMAGINE",
"status": "SUCCESS",
"progress": "100%",
"imageUrl": "https://cdn.discordapp.com/attachments/.../image1.png"
},
{
"id": "task_0987654321",
"action": "IMAGINE",
"status": "IN_PROGRESS",
"progress": "40%",
"imageUrl": ""
}
]
```
A polling interval of 3-5 seconds is recommended. Tasks typically complete within 30-120 seconds, depending on Midjourney service load.
# Get Seed
Source: https://docs.crazyrouter.com/en/images/midjourney/seed
Get the image seed value of a Midjourney task
# Get Seed
```
GET /mj/task/{id}/image-seed
```
Get the image seed value of a completed task. The seed can be used to reproduce similar generation results.
## Request Examples
```bash cURL theme={null}
curl https://crazyrouter.com/mj/task/task_1234567890/image-seed \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://crazyrouter.com/mj/task/task_1234567890/image-seed",
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
print(response.json())
```
## Response Example
```json theme={null}
{
"code": 1,
"description": "Success",
"result": "1234567890"
}
```
| Field | Description |
| -------- | ---------------------------------------------------------------------------------------- |
| `result` | Seed value, can be used in Imagine prompts with `--seed 1234567890` to reproduce results |
***
## Using the Seed
Add the `--seed` parameter to the prompt in an Imagine request:
```json theme={null}
{
"prompt": "a beautiful sunset over the ocean --ar 16:9 --v 6 --seed 1234567890"
}
```
The seed can only be retrieved after a task has completed successfully. The same seed + same prompt will generate very similar (but not identical) images.
# Crazyrouter Docs
Source: https://docs.crazyrouter.com/en/introduction
Find Crazyrouter API guides, tool integrations, model capabilities, and AI-readable documentation by task
API routes: OpenAI-compatible clients usually use `https://crazyrouter.com/v1` or `https://cn.crazyrouter.com/v1`; Claude Code and Anthropic-native clients use the root domain without `/v1`. See [API Endpoints](/en/api-endpoint).
Crazyrouter is a unified AI model API gateway. Use one API key for text, image, video, audio, embeddings, rerank, and the model access needed by common AI tools.
## Choose Your Task
Get an API key, configure the base URL, and make your first request in five minutes.
Connect Claude Code, Codex CLI, Cursor, Cline, Cherry Studio, OpenClaw, and other AI tools.
Use OpenAI Chat, Claude Messages, Gemini Native, and the Responses API.
Call GPT Image, Qwen Image, Midjourney, Nano Banana Pro, DALL-E, and related image models.
Integrate Veo, Kling, Seedance, Runway, Luma, Sora, Wan, and other video APIs.
Review pricing, model availability, errors, service status, and console management.
## AI-Readable Docs
Documentation entry points for Codex, Claude Code, ChatGPT, Cursor, and other AI tools.
Single-file documentation context for AI tools that can read URLs or pasted text.
## Common Paths
| Goal | Read |
| ----------------------------------------- | ------------------------------------------------- |
| Confirm base URLs and regional routes | [API Endpoints](/en/api-endpoint) |
| Create and use an API key | [Authentication](/en/authentication) |
| Send your first OpenAI-compatible request | [Quick Start](/en/quickstart) |
| Connect Claude Code | [Claude Code Setup](/en/integrations/claude-code) |
| Connect Codex CLI | [Codex CLI Setup](/en/integrations/codex) |
| Use local images as reference inputs | [Image Upload](/en/upload) |
| Troubleshoot request errors | [Error Handling](/en/error-handling) |
# Making Requests
Source: https://docs.crazyrouter.com/en/making-requests
Learn how to make API requests correctly
## Request Format
All API requests use the HTTPS protocol with JSON request bodies.
### Required Headers
| Header | Value | Description |
| --------------- | --------------------- | ---------------------- |
| `Authorization` | `Bearer YOUR_API_KEY` | API authentication key |
| `Content-Type` | `application/json` | Request body format |
### Optional Headers
| Header | Value | Description |
| -------- | ------------------ | --------------- |
| `Accept` | `application/json` | Response format |
## Request Example
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxx" \
-d '{
"model": "gpt-5.4",
"messages": [{"role": "user", "content": "Hello"}],
"stream": false
}'
```
## Streaming Requests
Set `stream: true` to enable SSE streaming output:
```bash theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxx" \
-d '{
"model": "gpt-5.4",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'
```
Streaming responses use the Server-Sent Events (SSE) format. Each event starts with `data: ` and the stream ends with `data: [DONE]`.
## Online Debugging
You can debug the API online using the following methods:
1. **Crazyrouter Playground** - After signing in, visit [crazyrouter.com/console/playground](https://crazyrouter.com/console/playground) to test directly in your browser
2. **cURL** - Send requests using the command-line tool
3. **Postman / Apifox** - Use API debugging tools
# OpenClaw Deployment Guide
Source: https://docs.crazyrouter.com/en/openclaw-deploy
Deploy OpenClaw with Crazyrouter on Linux or macOS, then finish WebUI, Telegram, and day-two operations setup
Use the one-click installer to deploy [OpenClaw](https://github.com/open-claw/open-claw) on Linux or macOS with Crazyrouter as the default backend. The installer writes a ready-to-run `~/.openclaw/openclaw.json`, registers the system service, and preloads a practical model set for chat, coding, and long-context work.
## Overview
OpenClaw is a good fit when you want a self-controlled local AI entrypoint backed by Crazyrouter:
* local WebUI and gateway, default port `18789`
* reusable access to your Crazyrouter models and quota
* Telegram support out of the box, plus pre-enabled plugin entries for DingTalk, WeCom, QQ Bot, Discord, Slack, and Feishu
* a good match for persistent personal bots, internal team assistants, home servers, and light self-hosted deployments
## Best For
* connecting Crazyrouter to a local AI gateway with one command
* running a Telegram bot on your own server
* managing WebUI, chat, and IM entrypoints in one place
* keeping an always-on assistant on a dev box or home mini server
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
* the installer points the default `crazyrouter` provider at `https://crazyrouter.com/v1`
* it also writes `crazyrouter-claude` and `crazyrouter-minimax` providers for native-compatible switching
* OpenClaw itself exposes a local gateway and WebUI, authenticated with the generated `gateway.auth.token`
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter API key | Create a dedicated `sk-...` token for OpenClaw instead of reusing your IDE or CLI tokens |
| OS | Linux or macOS, x64 / arm64 |
| Network | The host needs outbound internet access; if you want remote WebUI access, allow the chosen gateway port |
| Node.js | The installer tries to install Node.js 22+ for you |
| Telegram bot token | Optional, only needed if you want Telegram |
The installer binds the gateway to LAN scope by default (`bind: lan`). If the machine is reachable from the public internet, protect it with firewall rules and keep the gateway login token private.
## Quick Start In 5 Minutes
In Crazyrouter, create a dedicated `sk-...` token for OpenClaw. Start with a small model allowlist such as `claude-sonnet-4-6`, `gpt-5.4`, and `gemini-3-pro`.
```bash theme={null}
curl -fsSL https://raw.githubusercontent.com/xujfcn/crazyrouter-openclaw/main/install.sh | bash
```
To skip the language picker and API key prompt:
```bash theme={null}
CRAZYROUTER_API_KEY=sk-xxx INSTALLER_LANG=en \
curl -fsSL https://raw.githubusercontent.com/xujfcn/crazyrouter-openclaw/main/install.sh | bash
```
* WebUI URL: `http://:18789`
* auto-login URL: `http://:18789?token=`
* config path: `~/.openclaw/openclaw.json`
Open the auto-login URL in a browser, confirm you can enter the OpenClaw control UI, and send a simple test prompt with the default model `claude-sonnet-4-6`, such as `Reply with ok`.
The installer can set up Telegram immediately. If you choose that path, paste your Bot Token and then send any message to the bot so the first owner pairing can complete.
## Recommended Model Setup
The installer sets `claude-sonnet-4-6` as the default primary model. To change the day-to-day default, edit `agents.defaults.model.primary` in `~/.openclaw/openclaw.json`.
| Use case | Recommended model | Why |
| ----------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Default daily assistant | `claude-sonnet-4-6` | Strong balance of quality, stability, and cost |
| Coding / agent work | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the main OpenAI-compatible coding and agent baseline |
| Highest answer quality | `claude-opus-4-6` | Stronger complex reasoning and writing quality |
| Gemini fallback path | `gemini-3-pro` | Useful as a second compatibility-validation path |
| Heavy reasoning | `deepseek-r1` | Useful when you want stronger reasoning behavior |
Example: switch the default model to `gpt-5.4`
```json theme={null}
{
"agents": {
"defaults": {
"model": {
"primary": "crazyrouter/gpt-5.4"
}
}
}
}
```
If you want to explicitly use the Claude-compatible provider instead:
```json theme={null}
{
"agents": {
"defaults": {
"model": {
"primary": "crazyrouter-claude/claude-sonnet-4-6"
}
}
}
}
```
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Dedicated token | Required | Do not reuse the same token across OpenClaw, Cursor, and CLI tools |
| Model allowlist | Recommended | Keep only the models OpenClaw should use |
| IP restriction | Recommended on fixed-egress servers | Restrict the token to the server IP when possible |
| Quota cap | Recommended | Give the bot its own daily or monthly budget |
| Environment split | Recommended | Use separate tokens for production bots and test bots |
| Leak response | Immediate rotation | If `openclaw.json`, logs, or shared links expose credentials, rotate both the Crazyrouter token and gateway token |
OpenClaw uses at least two credential types: the Crazyrouter `sk-...` API key for model calls, and the local gateway login token for WebUI access. Keep them separate.
## Verification Checklist
* [ ] `http://:18789?token=` opens successfully
* [ ] the WebUI signs in without looping back to login
* [ ] the default model returns the first response successfully
* [ ] after a model change, a service restart still works
* [ ] `journalctl --user -u openclaw -f` or `tail -f ~/.openclaw/openclaw.log` shows successful requests
* [ ] if Telegram is enabled, the bot can reply to a test message
* [ ] a backup of `~/.openclaw/openclaw.json` is saved
## Key Files And Config Fields
### File Locations
| Path | Purpose |
| ------------------------------------------------------- | ------------------------------------------------------------ |
| `~/.openclaw/openclaw.json` | main config file |
| `~/.openclaw/start-gateway.sh` | launcher script used by the service |
| `~/.openclaw/crash-guard.cjs` | stability patch written by the installer |
| `~/.openclaw/credentials/.telegram-owner-paired` | marker file created after the first Telegram owner is paired |
| `~/.config/systemd/user/openclaw.service` | Linux user-level systemd service |
| `~/Library/LaunchAgents/com.crazyrouter.openclaw.plist` | macOS launchd service |
| `~/.openclaw/openclaw.log` | macOS runtime log |
| `~/.openclaw/openclaw.err` | macOS error log |
### Most Common Config Fields
| JSON path | Purpose | Typical change |
| -------------------------------------- | -------------------------------------------- | ------------------------------------------------- |
| `models.providers.crazyrouter.apiKey` | Crazyrouter OpenAI-compatible key | rotate API key |
| `models.providers.crazyrouter.baseUrl` | OpenAI-compatible base URL | usually keep `https://crazyrouter.com/v1` |
| `agents.defaults.model.primary` | default primary model | switch to `gpt-5.4`, `claude-opus-4-7`, and so on |
| `gateway.port` | WebUI / gateway port | move to a different port |
| `gateway.auth.token` | WebUI login token | rotate immediately if exposed |
| `gateway.bind` | listener scope | default is `lan` |
| `channels.telegram.botToken` | Telegram Bot Token | fill this when enabling Telegram |
| `plugins.entries.*.enabled` | whether each IM plugin is enabled | disable unused plugins |
| `env.vars.OPENAI_API_KEY` | API key reused by some internal capabilities | usually keep it aligned with the main key |
## IM Integrations
### Telegram
Telegram is the most complete path supported by the installer and should be your first integration:
1. Open Telegram and search for `@BotFather`
2. Send `/newbot` and create your bot
3. When the installer asks `Set up Telegram Bot now?`, choose `Y`
4. Paste the Bot Token so the installer can write it into `~/.openclaw/openclaw.json`
5. After the installer restarts the gateway, send any message to the bot
6. The first sender is auto-paired as the owner
7. If auto-pairing fails, run:
```bash theme={null}
openclaw pairing list
openclaw pairing approve
```
If you need to add Telegram manually later, this is the structure the installer writes:
```json theme={null}
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "123456789:ABCdef...",
"dmPolicy": "pairing",
"groupPolicy": "allowlist",
"streaming": "off"
}
},
"plugins": {
"entries": {
"telegram": { "enabled": true }
}
}
}
```
### Other IM Platforms
The installer pre-enables plugin entries for:
* `dingtalk`
* `openclaw-wecom`
* `qqbot`
* `discord`
* `slack`
* `feishu`
Those channels usually still require you to add your own platform credentials and the matching `channels.` config. A safe rollout pattern is:
1. create the bot or app in the target platform
2. write the platform credentials into `~/.openclaw/openclaw.json`
3. confirm `plugins.entries..enabled` is `true`
4. restart the OpenClaw service
5. validate the channel by checking logs and sending a test message
| Platform | Installer state | What you still need to do |
| ------------------------ | ------------------------------ | ------------------------------------------------- |
| Telegram | interactive setup supported | provide Bot Token and complete owner pairing |
| DingTalk | plugin installs and is enabled | add robot credentials and channel config |
| WeCom | plugin installs and is enabled | add enterprise app credentials and channel config |
| QQ Bot | plugin installs and is enabled | add bot credentials and channel config |
| Discord / Slack / Feishu | plugin entry is enabled | add the platform-specific channel credentials |
If OpenClaw will be connected to a team IM workspace, create a separate Crazyrouter token for that bot and enforce a tighter model allowlist and quota cap.
## Service Management And Logs
```bash theme={null}
systemctl --user status openclaw
systemctl --user start openclaw
systemctl --user restart openclaw
systemctl --user stop openclaw
journalctl --user -u openclaw -f
```
The installer also attempts `loginctl enable-linger $(whoami)` so the user-level service can keep running after you disconnect your SSH session.
```bash theme={null}
launchctl list | grep openclaw
launchctl start com.crazyrouter.openclaw
launchctl stop com.crazyrouter.openclaw
launchctl stop com.crazyrouter.openclaw && launchctl start com.crazyrouter.openclaw
tail -f ~/.openclaw/openclaw.log
cat ~/.openclaw/openclaw.err
```
On macOS, `openclaw.log` is usually enough for runtime activity, while `openclaw.err` is the first place to look when startup fails.
## Performance And Cost Tips
* start with `claude-sonnet-4-6` until the whole flow is stable
* keep routine bot traffic on `claude-sonnet-4-6` or move selected tasks to `gemini-3-pro`
* use `gpt-5.4` for coding-heavy agent workflows
* split WebUI, Telegram, and team IM usage across different tokens for better cost tracking
* keep only the models and plugins you actually need
## Upgrade Guide
The safest upgrade path is to rerun the installer, because it refreshes the OpenClaw package, patches, and service script together:
```bash theme={null}
cp ~/.openclaw/openclaw.json ~/.openclaw/openclaw.json.bak
```
```bash theme={null}
curl -fsSL https://raw.githubusercontent.com/xujfcn/crazyrouter-openclaw/main/install.sh | bash
```
If you manually added non-Telegram channels or changed the default model, compare the updated `openclaw.json` with your backup and re-apply the custom sections if needed.
Open the WebUI again and confirm your models, logs, and IM channels still work.
If you intentionally want to upgrade only the OpenClaw npm package, you can run `npm install -g openclaw@latest` and then restart the service, but that path will not re-apply installer-managed patches and script updates.
## Uninstall Guide
```bash theme={null}
systemctl --user disable --now openclaw
rm -f ~/.config/systemd/user/openclaw.service
systemctl --user daemon-reload
rm -rf ~/.openclaw
npm uninstall -g openclaw
```
```bash theme={null}
launchctl stop com.crazyrouter.openclaw
launchctl unload ~/Library/LaunchAgents/com.crazyrouter.openclaw.plist
rm -f ~/Library/LaunchAgents/com.crazyrouter.openclaw.plist
rm -rf ~/.openclaw
npm uninstall -g openclaw
```
If Node.js was installed only for OpenClaw, you can remove Node.js afterward once you confirm nothing else on the machine depends on it.
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| --------------------------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| WebUI does not open | service is down, port is busy, or firewall is blocking access | check service state first, then verify port `18789` and firewall rules |
| The page opens but keeps asking for login | wrong `gateway.auth.token` or not using the auto-login URL | re-check the `?token=...` link printed by the installer and confirm `openclaw.json` |
| `401 unauthorized` | invalid or expired Crazyrouter API key in `models.providers.*.apiKey` | update the API key and restart the service |
| `403` or `model not allowed` | the requested model is not allowed by the Crazyrouter token | add that model to the token allowlist |
| `429` or quota exhaustion | budget or rate limit reached | raise the budget, switch to a cheaper model, or split traffic across tokens |
| The old model is still used after editing config | service was not restarted or the provider path is wrong | check `agents.defaults.model.primary`, then restart |
| Telegram bot does not reply | missing `botToken`, owner pairing never completed, or service was not restarted | check `channels.telegram`, restart, and trigger pairing again |
| Linux install says the service may not have started | user-level systemd service failed | inspect `journalctl --user -u openclaw -f` |
| macOS install says the service may not have started | launchd startup failed | inspect `~/.openclaw/openclaw.err` |
## FAQ
### Which Crazyrouter base URL should I keep?
Leave the installer defaults unless you are intentionally changing provider modes: `https://crazyrouter.com/v1` for the OpenAI-compatible provider, and `https://crazyrouter.com` for Claude / MiniMax native-compatible providers.
### Which default model should I keep first?
For most users, keep `claude-sonnet-4-6` first. If OpenClaw is mainly a coding assistant, switch to `gpt-5.4`.
### Why is my expected model missing?
Usually the model is not allowed by the Crazyrouter token, or the config is pointing at the wrong provider prefix.
### Why does Telegram work in DM but not in groups?
The installer sets Telegram group policy to `allowlist` by default. Adjust the Telegram channel config if your rollout needs broader group behavior.
### What is the safest way to expose OpenClaw externally?
At minimum: restrict inbound access, protect `gateway.auth.token`, and use a dedicated Crazyrouter token for OpenClaw. If the host is public, add a reverse proxy and extra access control.
Review the installer source, file issues, or audit the one-click setup yourself.
# Hermes Agent Setup
Source: https://docs.crazyrouter.com/en/openclaw-hermes
Configure Hermes Agent with Crazyrouter and use 627+ AI models through the OpenAI-compatible endpoint
Use [crazyrouter-hermes](https://github.com/xujfcn/crazyrouter-hermes) to point [Hermes Agent](https://github.com/NousResearch/Hermes-Agent) at Crazyrouter. After setup, Hermes uses `https://crazyrouter.com/v1` as its OpenAI-compatible endpoint and calls Claude, GPT, DeepSeek, Gemini, Qwen, and 627+ other models through a single Crazyrouter API key.
## Best For
* Hermes Agent users who want to use Crazyrouter as the model provider
* local agent workflows that should share Crazyrouter models and quota
* users who want a one-command setup for `OPENAI_API_KEY`, `OPENAI_BASE_URL`, and the default model
## Prerequisites
| Item | Notes |
| ------------------- | -------------------------------------------------------- |
| Hermes Agent | Install Hermes locally and confirm it can start |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter API key | Create a dedicated `sk-...` token for Hermes |
| Model access | Allow the models you plan to use in that token |
Hermes connects to Crazyrouter through OpenAI-compatible settings. Keep the base URL as `https://crazyrouter.com/v1`.
## One-Click Setup
```bash theme={null}
curl -fsSL https://raw.githubusercontent.com/xujfcn/crazyrouter-hermes/main/setup.sh | bash
```
```powershell theme={null}
irm https://raw.githubusercontent.com/xujfcn/crazyrouter-hermes/main/setup.ps1 | iex
```
```bat theme={null}
curl -o setup.bat https://raw.githubusercontent.com/xujfcn/crazyrouter-hermes/main/setup.bat
setup.bat
```
The script prompts for your Crazyrouter API key, lets you choose a default model, and can optionally test the connection.
The setup script writes local Hermes config. Back up `~/.hermes/.env` and `~/.hermes/config.yaml` first if you already have custom settings.
## Manual Setup
If you prefer not to run the script, write the Hermes config manually.
### Environment Variables
Edit `~/.hermes/.env`:
```bash theme={null}
OPENAI_API_KEY=sk-your-crazyrouter-key
OPENAI_BASE_URL=https://crazyrouter.com/v1
```
### Default Model
Edit `~/.hermes/config.yaml`:
```yaml theme={null}
model:
provider: "custom"
default: "claude-opus-4-7"
base_url: "https://crazyrouter.com/v1"
```
Change `default` to any model allowed by your Crazyrouter token.
## Switch Models
After setup, switch models inside Hermes with `/model`:
```text theme={null}
/model claude-opus-4-7
/model gpt-5.4
/model claude-sonnet-4.6
/model gemini-3-pro
/model deepseek-chat
/model qwen-max
/model gpt-4o
```
If switching returns `model not allowed` or `403`, the current Crazyrouter token usually does not allow that model.
## Verification Checklist
* [ ] `OPENAI_API_KEY` in `~/.hermes/.env` is a valid Crazyrouter token
* [ ] `OPENAI_BASE_URL` is `https://crazyrouter.com/v1`
* [ ] `provider` in `~/.hermes/config.yaml` is `custom`
* [ ] the default model is allowed by the Crazyrouter token
* [ ] Hermes can return a test response
* [ ] `/model gpt-5.4` or another allowed model switches successfully
## Common Issues
| Symptom | Likely cause | Fix |
| ---------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `401 unauthorized` | API key is wrong, expired, or rotated | create a new Crazyrouter token and update `~/.hermes/.env` |
| `403` or `model not allowed` | the token does not allow the selected model | allow that model in the Crazyrouter token settings |
| Hermes still uses the old provider | Hermes did not reload config, or the wrong config path was edited | restart Hermes and check `~/.hermes/.env` plus `~/.hermes/config.yaml` |
| Connection timeout | local network cannot reach Crazyrouter | check proxy, firewall, and DNS settings |
Review the setup scripts, manual config example, and latest notes.
# Quick Start Guide
Source: https://docs.crazyrouter.com/en/quickstart
Make your first API call in 5 minutes
## Step 1: Get Your API Key
1. Visit [Crazyrouter](https://crazyrouter.com) and create an account
2. After signing in, go to the [Token Management](https://crazyrouter.com/console/token) page
3. Click "Create Token" to generate an API Key
## Step 2: Make a Request
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "Hello"}
]
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
```
```javascript Node.js theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'YOUR_API_KEY',
baseURL: 'https://crazyrouter.com/v1'
});
const response = await client.chat.completions.create({
model: 'gpt-5.4',
messages: [{ role: 'user', content: 'Hello' }]
});
console.log(response.choices[0].message.content);
```
## Step 3: View the Response
Example of a successful response:
```json theme={null}
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1677652288,
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello! How can I help you today?"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 9,
"completion_tokens": 12,
"total_tokens": 21
}
}
```
The `gpt-5.4` example on this quickstart page was revalidated successfully against Crazyrouter production on 2026-03-23.
All OpenAI-compatible clients and frameworks (such as LangChain, LlamaIndex, Cursor, etc.) can be integrated by simply changing the `base_url` and `api_key`.
# Official Model Pricing Methods
Source: https://docs.crazyrouter.com/en/reference/official-pricing-methods
Explain how each Crazyrouter model name maps to upstream official pricing rules
# Official Model Pricing Methods
This page explains upstream vendor pricing rules only. It does not describe Crazyrouter resale prices.
* Upstream pricing: the vendor's own `input`, `output`, `cached input`, `tool call`, `search grounding`, `prompt caching`, and similar billing rules
* Crazyrouter pricing: Crazyrouter's own sell price, multiplier, discount, channel variation, and settlement logic
This page reflects vendor documentation checked on `2026-04-27`. Vendors can change prices, preview-model policies, long-context rules, search-tool fees, and caching behavior. Recheck the official source links before relying on any number in production.
## Official Example Price Table
The examples below intentionally use the most common pricing tier that is easiest to map to budget planning:
* Anthropic: standard API price, excluding `Fast mode`, `US-only inference`, and Batch discounts
* OpenAI: `Standard` price, excluding Batch, Priority, and Regional Processing surcharges
* Gemini: `Standard` price, usually the text/image/video default path, and for `Gemini 3*` models the `<= 200K prompt` tier
* xAI: if the public static docs do not list a standalone price for the exact routed name, this page says so explicitly
* Z.AI: the official `Text Models` price
* MiniMax: the main table uses `Pay as You Go`; subscription-style pricing is listed separately under `Token Plan`
Unless otherwise noted, prices below are `USD / 1M tokens`.
### Anthropic Example Prices
| Crazyrouter Name | Official Model | Base Input | Cache 5m / 1h / Hit | Output | Notes |
| ---------------------------- | ---------------------------- | ---------- | --------------------- | ------ | ------------------------------------------------------------------------------------- |
| `claude-sonnet-4-6` | `claude-sonnet-4-6` | `$3` | `$3.75 / $6 / $0.30` | `$15` | `1M context` uses the standard rate; Batch is roughly `50% off` |
| `claude-opus-4-6` | `claude-opus-4-6` | `$5` | `$6.25 / $10 / $0.50` | `$25` | `Fast mode` is billed at `6x` the standard price |
| `claude-opus-4-7` | `claude-opus-4-7` | `$5` | `$6.25 / $10 / $0.50` | `$25` | `US-only inference` has an extra regional multiplier in the official docs |
| `claude-sonnet-4-5-20250929` | `claude-sonnet-4-5` snapshot | `$3` | `$3.75 / $6 / $0.30` | `$15` | Snapshot IDs keep the `Sonnet 4.5` price; they do not define a separate pricing table |
### OpenAI Example Prices
| Crazyrouter Name | Official Model | Input | Cached input | Output | Notes |
| ------------------ | ------------------- | ------- | ------------ | -------- | ------------------------------------------------------------------------------------------------------------ |
| `gpt-54` | `gpt-5.4` | `$2.50` | `$0.25` | `$15.00` | Standard price applies below `270K` context; long-context multipliers apply above that |
| `gpt-4o` | `gpt-4o` | `$2.50` | `$1.25` | `$10.00` | Classic three-part token pricing |
| `gpt-5` | `gpt-5` | `$1.25` | `$0.125` | `$10.00` | Tool charges are separate |
| `gpt-51-codex-max` | `gpt-5.1-codex-max` | `$1.25` | `$0.125` | `$10.00` | Commonly used in Codex and agentic coding workflows, but still billed with the standard three-part structure |
| `gpt-5-mini` | `gpt-5-mini` | `$0.25` | `$0.025` | `$2.00` | Lower-cost GPT-5 variant |
| `gpt-5-nano` | `gpt-5-nano` | `$0.05` | `$0.005` | `$0.40` | Lowest-cost GPT-5 route |
| `gpt-5.2` | `gpt-5.2` | `$1.75` | `$0.175` | `$14.00` | Earlier flagship tier, still standard three-part token pricing |
| `gpt-5.5` | `gpt-5.5` | `$5.00` | `$0.50` | `$30.00` | Current flagship tier; the official standard-price note applies below `270K` context |
### Gemini Example Prices
| Crazyrouter Name | Official Model | Standard Input | Standard Cache | Standard Output | Notes |
| ----------------------- | ----------------------- | -------------------------------- | ---------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `gemini-3-pro` | `gemini-3-pro` | `$2.00` | `$0.20` + `$4.50 / 1M tok / hr` storage | `$12.00` | `<= 200K` prompt tier; `> 200K` becomes `$4 / $0.40 / $18`; Google also lists Search and Maps free quotas plus `$14 / 1,000 search queries` |
| `gemini-2.5-flash-lite` | `gemini-2.5-flash-lite` | `$0.10` for text / image / video | `$0.01` for text / image / video + `$1.00 / 1M tok / hr` storage | `$0.40` | Audio input is `$0.30`, audio cache is `$0.03`; Search is `1,500 RPD` free then `$35 / 1,000 grounded prompts` |
### xAI Example Prices
| Crazyrouter Name | Official Mapping | Prompt / Cached / Output | Tool Fees | Notes |
| ------------------- | ------------------------ | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `grok-4.1-thinking` | Internal reasoning route | The public static docs do not list a standalone `grok-4.1-thinking` token price | `web_search $5 / 1k`, `x_search $5 / 1k`, `code_execution $5 / 1k`, `attachment_search $10 / 1k`, `collections_search $2.50 / 1k` | `reasoning tokens` are billed at the `completion token price` |
| `grok-4.1` | Internal Grok 4.1 route | The public static docs do not list a standalone `grok-4.1` token price | same as above | The Crazyrouter route name should not be treated as a public xAI static SKU |
What the current xAI static docs reliably expose is the token-category structure, tool-invocation pricing, Batch `50% off`, and the instruction to check model details or the console for model-specific token prices. Since `grok-4.1` and `grok-4.1-thinking` are not individually priced in the static public docs, this page does not assign another SKU's numbers to them.
### Z.AI / GLM Example Prices
| Crazyrouter Name | Official Model | Input | Cached input | Cached input storage | Output | Notes |
| ---------------- | -------------- | ------ | ------------ | -------------------- | ------ | -------------------------------------------------- |
| `glm-5` | `GLM-5` | `$1.0` | `$0.2` | `Limited-time Free` | `$3.2` | `Web Search` is billed separately at `$0.01 / use` |
### MiniMax Example Prices
#### Pay as You Go
| Crazyrouter Name | Official Model | Input | Prompt caching read | Prompt caching write | Output | Notes |
| ---------------- | -------------- | ------ | ------------------- | -------------------- | ------ | --------------------------------------------------------- |
| `MiniMax-M27` | `MiniMax-M2.7` | `$0.3` | `$0.06` | `$0.375` | `$1.2` | This is the clearest tier to use for direct API budgeting |
#### Token Plan
| Plan | Monthly Price | `M2.7` Quota |
| ------- | ------------- | ------------------------ |
| Starter | `$10 / month` | `1,500 requests / 5hrs` |
| Plus | `$20 / month` | `4,500 requests / 5hrs` |
| Max | `$50 / month` | `15,000 requests / 5hrs` |
## Anthropic
Anthropic pricing is not just a simple `input / output` split. The official structure breaks out:
* `Base Input Tokens`
* `5m Cache Writes`
* `1h Cache Writes`
* `Cache Hits & Refreshes`
* `Output Tokens`
Two common rules also matter:
* `Batch API` usually bills input and output at roughly `50% off`
* Prompt caching follows the public multiplier rules: `5-minute cache write = 1.25x input`, `1-hour cache write = 2x input`, and `cache hit = 0.1x input`
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ---------------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `claude-sonnet-4-6` | Anthropic `claude-sonnet-4-6` | billed as `base input / 5m cache write / 1h cache write / cache hit / output` | Anthropic explicitly documents `Sonnet 4.6` with `1M context`, still using standard pricing |
| `claude-opus-4-6` | Anthropic `claude-opus-4-6` | billed as `base input / 5m cache write / 1h cache write / cache hit / output` | `Opus 4.6` also supports `1M context`; `Fast mode` uses a separate multiplier |
| `claude-opus-4-7` | Anthropic `claude-opus-4-7` | billed as `base input / 5m cache write / 1h cache write / cache hit / output` | `Opus 4.7` is a distinct model on the official Anthropic pricing surface |
| `claude-sonnet-4-5-20250929` | Anthropic snapshot ID `claude-sonnet-4-5-20250929`, usually displayed publicly as `claude-sonnet-4-5` | still billed under the `Sonnet 4.5` `base input / cache write / cache hit / output` structure | Snapshot IDs are dated API names, not separate product prices |
Official links:
* Anthropic Pricing: [platform.claude.com/docs/en/about-claude/pricing](https://platform.claude.com/docs/en/about-claude/pricing)
* Anthropic Models Overview: [platform.claude.com/docs/en/about-claude/models/overview](https://platform.claude.com/docs/en/about-claude/models/overview)
## OpenAI
OpenAI pricing is the most uniform of the set. The public structure is usually:
* `Input`
* `Cached input`
* `Output`
Common extra rules:
* `Responses API` itself does not add a separate model fee; billing still follows the selected model's token rates
* `Web search`, containers/code execution, Computer Use, and other tools are billed separately
* `Batch API` usually discounts token pricing by about `50%`
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ------------------ | ------------------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `gpt-54` | internal alias, usually meaning OpenAI `gpt-5.4` | billed as `input / cached input / output` | the public standard price applies below `270K` context; regional processing endpoints add another surcharge |
| `gpt-4o` | OpenAI `gpt-4o` | billed as `input / cached input / output` | classic unified OpenAI pricing structure |
| `gpt-5` | OpenAI `gpt-5` | billed as `input / cached input / output` | tool usage is billed separately; there is no separate public "thinking token price" line item |
| `gpt-51-codex-max` | should map to OpenAI `gpt-5.1-codex-max` | billed as `input / cached input / output` | Codex-oriented naming, but the public price structure still matches the regular GPT-5.1 token format |
| `gpt-5-mini` | OpenAI `gpt-5-mini` | billed as `input / cached input / output` | smaller lower-cost tier |
| `gpt-5-nano` | OpenAI `gpt-5-nano` | billed as `input / cached input / output` | nano tier, same billing structure |
| `gpt-5.2` | OpenAI `gpt-5.2` | billed as `input / cached input / output` | still part of the GPT-5 pricing pattern |
| `gpt-5.5` | OpenAI `gpt-5.5` | billed as `input / cached input / output` | current flagship tier; use the latest long-context notes from OpenAI before production rollout |
Official links:
* OpenAI Pricing: [openai.com/api/pricing](https://openai.com/api/pricing/)
* OpenAI Docs Pricing: [platform.openai.com/docs/pricing](https://platform.openai.com/docs/pricing/)
* OpenAI Models: [developers.openai.com/api/docs/models](https://developers.openai.com/api/docs/models)
## Google Gemini
Gemini pricing differs the most from OpenAI and Anthropic because Google often publishes multiple processing modes:
* `Standard`
* `Batch`
* `Flex`
* `Priority`
And it often breaks out:
* `Input`
* `Output (including thinking tokens)`
* `Context caching price`
* `Context caching storage`
* `Grounding with Google Search`
* `Grounding with Google Maps`
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ----------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `gemini-3-pro` | Google `gemini-3-pro`, often displayed internally as `gemini-3-pro` | officially split by `Standard / Batch / Flex / Priority`, and then by `input / output / caching / search grounding / maps grounding` | preview model, with separate `<= 200K` and `> 200K` prompt pricing tiers |
| `gemini-2.5-flash-lite` | Google `gemini-2.5-flash-lite` | priced by `Standard / Batch / Flex / Priority`, with separate `input / output / context caching / storage / Google Search / Google Maps` | stable model rather than preview; official output pricing explicitly includes thinking tokens |
Official links:
* Gemini Pricing: [ai.google.dev/gemini-api/docs/pricing](https://ai.google.dev/gemini-api/docs/pricing)
* Gemini Models: [ai.google.dev/models/gemini](https://ai.google.dev/models/gemini)
## xAI Grok
xAI pricing is best understood as token categories plus tool billing, rather than a separate pricing table for every visible route name:
* `Prompt tokens`
* `Cached prompt tokens`
* `Completion tokens`
* `Reasoning tokens`
xAI also explicitly states:
* `Reasoning tokens` are billed at the `completion token price`
* `Web Search`, `X Search`, `Code Execution`, and similar server-side tools are billed separately per `1,000` calls
* `Batch API` usually applies a `50%` token discount
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `grok-4.1-thinking` | internal reasoning route; conceptually closest to a Grok 4.1 reasoning configuration | billed using the xAI token-category model: `prompt / cached prompt / completion / reasoning`, plus tool invocation fees when relevant | the public xAI pricing docs emphasize SKU-style names such as `grok-4-1-fast-reasoning`; this route name should not be treated as an official standalone public SKU |
| `grok-4.1` | internal Grok 4.1 route; conceptually closer to a non-thinking Grok 4.1 configuration | still follows the same xAI token-category billing logic, with tools billed separately | for production budgeting, rely on the current xAI public token and tool rules, not on the internal route name alone |
Official links:
* xAI Models and Pricing: [docs.x.ai/developers/models](https://docs.x.ai/developers/models)
* xAI Consumption and Rate Limits: [docs.x.ai/developers/rate-limits](https://docs.x.ai/developers/rate-limits)
* xAI Prompt Caching Pricing: [docs.x.ai/developers/advanced-api-usage/prompt-caching/usage-and-pricing](https://docs.x.ai/developers/advanced-api-usage/prompt-caching/usage-and-pricing)
## Z.AI / GLM
Z.AI `GLM-5` pricing is close to the OpenAI pattern, but it adds cache storage as its own line item:
* `Input`
* `Cached Input`
* `Cached Input Storage`
* `Output`
Built-in tools such as `Web Search` are priced separately per use.
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ---------------- | ---------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `glm-5` | Z.AI `GLM-5` | billed as `input / cached input / cached input storage / output` | official `Web Search` is charged separately, so token price alone is not the full cost picture |
Official links:
* Z.AI Pricing: [docs.z.ai/guides/overview/pricing](https://docs.z.ai/guides/overview/pricing)
* GLM-5 Overview: [docs.z.ai/guides/llm/glm-5](https://docs.z.ai/guides/llm/glm-5)
## MiniMax
MiniMax is the one vendor here where two official commercial modes matter:
* `Pay as You Go`
* `Token Plan`
That means:
* `Pay as You Go` is the normal token-priced API path
* `Token Plan` is subscription-style and, for `M2.7`, often described as a `requests per 5-hour rolling window` capacity product rather than plain token billing
| Crazyrouter Name | Official Mapping | Official Billing Method | Notes |
| ---------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `MiniMax-M27` | should map to `MiniMax-M2.7` | under `Pay as You Go`, billed as `input / output / prompt caching read / prompt caching write`; under `Token Plan`, billed as `requests / 5hrs` capacity | for production API budgeting, start with `Pay as You Go`; evaluate `Token Plan` separately for heavy coding or interactive usage |
Official links:
* MiniMax Pricing Overview: [platform.minimax.io/docs/pricing/overview](https://platform.minimax.io/docs/pricing/overview)
* MiniMax Pay as You Go: [platform.minimax.io/docs/guides/pricing-paygo](https://platform.minimax.io/docs/guides/pricing-paygo)
* MiniMax Token Plan: [platform.minimax.io/docs/guides/pricing-token-plan](https://platform.minimax.io/docs/guides/pricing-token-plan)
## Summary
If you only need a quick mental model of how each vendor bills, the shortest version is:
* Anthropic: `base input + cache write/read + output`
* OpenAI: `input + cached input + output`, with tools billed separately
* Gemini: `multiple processing modes + input/output + caching + search/maps grounding`
* xAI: `prompt/cached/completion/reasoning`, with server-side tools billed separately
* Z.AI: `input + cached input + cached storage + output`
* MiniMax: `token pay-as-you-go` or `subscription-style capacity plan`
This page explains upstream official pricing rules, not Crazyrouter selling prices. For actual recharge, billing, multiplier, and discount behavior, use Crazyrouter pricing pages, the console, and `/api/pricing`.
## Related Internal Pages
* [OpenAI Model List](/en/chat/openai/models)
* [Gemini-Compatible OpenAI Model List](/en/chat/gemini/openai-models)
* [Claude Native Format](/en/chat/anthropic/messages)
* [Gemini Native Format](/en/chat/gemini/native)
* [Grok Models](/en/chat/openai/grok)
* [Get Token Models](/en/token-management/models)
# AI Thinking Fields
Source: https://docs.crazyrouter.com/en/reference/thinking
Production-revalidated guide to the thinking and reasoning fields exposed by different Crazyrouter protocols
# AI Thinking Fields
This page only lists thinking and reasoning surfaces that were revalidated against Crazyrouter production on `2026-03-22`.
The key point is that different protocols expose "thinking" differently:
* OpenAI Responses returns a standalone `reasoning` item
* Claude native Messages returns a `thinking` block
* Gemini Native is most reliably observed through `usageMetadata.thoughtsTokenCount`
## Currently verified fields
| Model | Protocol | Verified field or marker | Notes |
| ----------------- | ------------------ | ---------------------------------- | ------------------------------------------------------------ |
| `gpt-5.4` | Responses | `output[].type = "reasoning"` | Can return displayable summaries when `summary` is requested |
| `claude-opus-4-7` | Anthropic Messages | `content[].type = "thinking"` | Returned alongside a `text` block |
| `gemini-3-pro` | Gemini Native | `usageMetadata.thoughtsTokenCount` | Confirms thinking tokens were actually used |
In the current recheck, `gpt-5.4` Chat Completions did not reliably return usable `message.reasoning_content`, so it is not treated as the primary observable field here.
***
## GPT: Responses `reasoning` item
```json theme={null}
{
"output": [
{
"id": "rs_xxx",
"type": "reasoning",
"encrypted_content": "...",
"summary": [
{
"type": "summary_text",
"text": "..."
}
]
},
{
"type": "message",
"content": [
{
"type": "output_text",
"text": "Final answer"
}
]
}
]
}
```
Extraction example:
```python theme={null}
response = client.responses.create(
model="gpt-5.4",
input="Which is larger, 9.11 or 9.9?",
reasoning={"effort": "high", "summary": "detailed"}
)
for item in response.output:
if item.type == "reasoning":
for part in item.summary:
if part.type == "summary_text":
print("Thinking summary:", part.text)
```
***
## Claude: `thinking` block
```json theme={null}
{
"content": [
{
"type": "thinking",
"thinking": "..."
},
{
"type": "text",
"text": "Final answer"
}
]
}
```
Extraction example:
```python theme={null}
message = client.messages.create(
model="claude-opus-4-7",
max_tokens=320,
thinking={
"type": "enabled",
"budget_tokens": 128
},
messages=[
{"role": "user", "content": "Which is larger, 9.11 or 9.9?"}
]
)
for block in message.content:
if block.type == "thinking":
print("Thinking:", block.thinking)
elif block.type == "text":
print("Answer:", block.text)
```
***
## Gemini: `thoughtsTokenCount`
In the current production recheck, the most reliable observable signal was not a visible reasoning paragraph in the body, but a usage field:
```json theme={null}
{
"usageMetadata": {
"thoughtsTokenCount": 120
}
}
```
This indicates that:
* the thinking budget was actually used
* the request consumed thinking tokens during generation
Extraction example:
```python theme={null}
data = response.json()
thoughts = data.get("usageMetadata", {}).get("thoughtsTokenCount", 0)
print("Thinking tokens:", thoughts)
```
***
## Usage notes
* Do not assume every model returns raw chain-of-thought text
* Do not mix thinking fields across protocols
* For logging, auditing, or UI display, decide per protocol whether to read `reasoning`, `thinking`, or `thoughtsTokenCount`
Related pages:
* [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
* [Claude Native Messages](/en/chat/anthropic/messages)
* [Gemini Native API](/en/chat/gemini/native)
# GPT-4o Audio
Source: https://docs.crazyrouter.com/en/audio/gpt4o-audio
Use GPT-4o audio input/output capabilities
# GPT-4o Audio
GPT-4o supports direct audio input processing and audio output generation for voice conversations.
## Audio Input
Send audio via the Chat Completions API:
```
POST /v1/chat/completions
```
### Request Example
```python Python theme={null}
import base64
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
# Read audio file and encode to Base64
with open("question.wav", "rb") as f:
audio_base64 = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-4o-audio-preview",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Please listen to this audio and answer the question"},
{
"type": "input_audio",
"input_audio": {
"data": audio_base64,
"format": "wav"
}
}
]
}
]
)
print(response.choices[0].message.content)
```
***
## Audio Output
Request the model to respond in audio format:
```python Python theme={null}
response = client.chat.completions.create(
model="gpt-4o-audio-preview",
modalities=["text", "audio"],
audio={"voice": "nova", "format": "wav"},
messages=[
{"role": "user", "content": "Tell me a short joke"}
]
)
# Get text response
print(response.choices[0].message.content)
# Get audio response
if response.choices[0].message.audio:
audio_data = base64.b64decode(response.choices[0].message.audio.data)
with open("response.wav", "wb") as f:
f.write(audio_data)
```
***
## Supported Models
| Model | Description |
| ---------------------- | -------------------- |
| `gpt-4o-audio-preview` | GPT-4o Audio Preview |
## Audio Formats
Input supported: `wav`, `mp3`
Output supported: `wav`, `mp3`, `opus`, `flac`, `pcm16`
GPT-4o Audio can understand tone, emotion, and ambient sounds in audio -- it goes beyond simple speech-to-text.
# GPT Realtime
Source: https://docs.crazyrouter.com/en/audio/realtime
Use the GPT Realtime API for real-time voice conversations
# GPT Realtime
```
GET /v1/realtime
```
The GPT Realtime API enables low-latency real-time voice conversations via WebSocket connections.
## Connection
Connect to the Realtime endpoint via WebSocket:
```
wss://crazyrouter.com/v1/realtime?model=gpt-4o-realtime-preview
```
### Authentication
The currently supported and recommended authentication methods are:
#### Method 1: pass the API key in request headers
```
Authorization: Bearer YOUR_API_KEY
```
#### Method 2: pass the key in `Sec-WebSocket-Protocol`
Useful for some OpenAI Realtime-compatible clients:
```
Sec-WebSocket-Protocol: realtime, openai-insecure-api-key.YOUR_API_KEY
```
Do not rely on the `?api_key=` URL query style.
***
## Supported Models
| Model | Description |
| ------------------------------ | ---------------------------- |
| `gpt-4o-realtime-preview` | GPT-4o Realtime Preview |
| `gpt-4o-mini-realtime-preview` | GPT-4o Mini Realtime Preview |
***
## Usage Example
```python Python theme={null}
import asyncio
import websockets
import json
async def realtime_chat():
uri = "wss://crazyrouter.com/v1/realtime?model=gpt-4o-realtime-preview"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
async with websockets.connect(uri, extra_headers=headers) as ws:
# Configure session
await ws.send(json.dumps({
"type": "session.update",
"session": {
"modalities": ["text", "audio"],
"voice": "nova",
"input_audio_format": "pcm16",
"output_audio_format": "pcm16",
"turn_detection": {
"type": "server_vad"
}
}
}))
# Send text message
await ws.send(json.dumps({
"type": "conversation.item.create",
"item": {
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "Hello, please introduce yourself"}
]
}
}))
# Trigger response
await ws.send(json.dumps({"type": "response.create"}))
# Receive response
async for message in ws:
event = json.loads(message)
if event["type"] == "response.text.delta":
print(event["delta"], end="")
elif event["type"] == "response.done":
break
asyncio.run(realtime_chat())
```
***
## Event Types
### Client Events
| Event | Description |
| --------------------------- | ---------------------------- |
| `session.update` | Update session configuration |
| `conversation.item.create` | Create a conversation item |
| `input_audio_buffer.append` | Append audio data |
| `input_audio_buffer.commit` | Commit audio buffer |
| `response.create` | Trigger model response |
### Server Events
| Event | Description |
| ---------------------- | ----------------- |
| `session.created` | Session created |
| `response.text.delta` | Text delta |
| `response.audio.delta` | Audio delta |
| `response.done` | Response complete |
The Realtime API uses persistent WebSocket connections. Prefer header-based authentication and do not rely on the `?api_key=` query parameter.
# Speech-to-Text (STT)
Source: https://docs.crazyrouter.com/en/audio/stt
Use POST /v1/audio/transcriptions to convert speech to text
# Speech-to-Text (STT)
```
POST /v1/audio/transcriptions
```
Transcribe audio files to text, compatible with the OpenAI Whisper API format.
## Request Parameters
| Parameter | Type | Required | Description |
| ----------------- | ------ | -------- | --------------------------------------------------------------------- |
| `file` | file | Yes | Audio file (multipart/form-data) |
| `model` | string | Yes | Model name: `whisper-1`, `gpt-4o-transcribe` |
| `language` | string | No | Audio language (ISO-639-1 format), e.g. `zh`, `en`, `ja` |
| `response_format` | string | No | Output format: `json` (default), `text`, `srt`, `verbose_json`, `vtt` |
| `temperature` | number | No | Sampling temperature, 0-1 |
| `prompt` | string | No | Prompt to help the model understand context |
### Supported Audio Formats
`mp3`, `mp4`, `mpeg`, `mpga`, `m4a`, `wav`, `webm`
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-F file=@audio.mp3 \
-F model=whisper-1 \
-F language=en \
-F response_format=json
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
with open("audio.mp3", "rb") as audio_file:
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
language="en",
response_format="json"
)
print(transcript.text)
```
```javascript Node.js theme={null}
import OpenAI from "openai";
import fs from "fs";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const transcript = await client.audio.transcriptions.create({
model: "whisper-1",
file: fs.createReadStream("audio.mp3"),
language: "en",
});
console.log(transcript.text);
```
## Response Examples
### JSON Format
```json theme={null}
{
"text": "Hello, welcome to the Crazyrouter API. Today we'll introduce the speech-to-text feature."
}
```
### verbose\_json Format
```json theme={null}
{
"task": "transcribe",
"language": "english",
"duration": 5.2,
"text": "Hello, welcome to the Crazyrouter API.",
"segments": [
{
"id": 0,
"start": 0.0,
"end": 2.5,
"text": "Hello, welcome to the Crazyrouter API."
}
]
}
```
### SRT Format
```
1
00:00:00,000 --> 00:00:02,500
Hello, welcome to the Crazyrouter API.
```
***
## Audio Translation
```
POST /v1/audio/translations
```
Translate non-English audio to English text. Parameters are the same as the transcription endpoint.
```python Python theme={null}
with open("chinese_audio.mp3", "rb") as audio_file:
translation = client.audio.translations.create(
model="whisper-1",
file=audio_file
)
print(translation.text) # Outputs English translation
```
Specifying the `language` parameter can improve transcription accuracy. Audio file size limit is 25MB.
# Suno Song Concatenation
Source: https://docs.crazyrouter.com/en/audio/suno/concat
Use the Suno API to concatenate multiple song segments
# Suno Song Concatenation
```
POST /suno/submit/concat
```
Concatenate multiple song clips into a complete song.
## Request Parameters
| Parameter | Type | Required | Description |
| ----------- | ------- | -------- | ------------------------------------------------------------------ |
| `clip_id` | string | Yes | Clip ID of the song to concatenate |
| `is_infill` | boolean | No | Whether to use infill mode (generate transitions between segments) |
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/suno/submit/concat \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"clip_id": "clip_abc123",
"is_infill": false
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/suno/submit/concat",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"clip_id": "clip_abc123",
"is_infill": False
}
)
print(response.json())
```
## Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "concat_task_abc123"
}
```
***
## Infill Mode
When `is_infill: true` is set, Suno will automatically generate transition passages between song segments:
```json theme={null}
{
"clip_id": "clip_abc123",
"is_infill": true
}
```
After submitting a concatenation task, use the [Task Query](/en/audio/suno/query) endpoint to get results. The concatenated song will generate a new clip ID.
# Suno Generate Song
Source: https://docs.crazyrouter.com/en/audio/suno/generate
Use the Suno API to generate songs, supporting inspiration mode, custom mode, continuation, and singer style
# Suno Generate Song
```
POST /suno/submit/music
```
Generate songs with Suno, supporting multiple creation modes.
## Inspiration Mode
Automatically generate songs from a simple description.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------------ | ------- | -------- | -------------------------------------------------------- |
| `gpt_description_prompt` | string | Yes | Song description, e.g. "An upbeat pop song about summer" |
| `mv` | string | No | Model version, e.g. `chirp-v3-5`, `chirp-v4` |
| `make_instrumental` | boolean | No | Whether to create instrumental only (no vocals) |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/suno/submit/music \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"gpt_description_prompt": "An upbeat summer pop song about the beach, with guitar and drums",
"mv": "chirp-v4",
"make_instrumental": false
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/suno/submit/music",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"gpt_description_prompt": "An upbeat summer pop song about the beach",
"mv": "chirp-v4",
"make_instrumental": False
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "suno_task_abc123"
}
```
***
## Custom Mode
Write your own lyrics and set style tags.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------- | ------- | -------- | -------------------------------------- |
| `prompt` | string | Yes | Lyrics content |
| `title` | string | Yes | Song title |
| `tags` | string | Yes | Style tags, e.g. `pop, upbeat, summer` |
| `mv` | string | No | Model version |
| `make_instrumental` | boolean | No | Whether instrumental only |
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/suno/submit/music \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "[Verse]\nSunshine on the ocean waves\nGentle breeze across my face\n\n[Chorus]\nThis summer we are together\nSinging and dancing by the sea",
"title": "Summer Beach",
"tags": "pop, english, upbeat, summer",
"mv": "chirp-v4"
}'
```
***
## Continuation Mode
Continue creating from a specific point in an existing song.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------ | ------ | -------- | --------------------------------- |
| `prompt` | string | Yes | Continuation lyrics |
| `continue_clip_id` | string | Yes | Clip ID of the song to continue |
| `continue_at` | number | Yes | Continuation start time (seconds) |
| `tags` | string | No | Style tags |
| `mv` | string | No | Model version |
```json theme={null}
{
"prompt": "[Bridge]\nMemories like ocean waves\nCrashing one after another\n\n[Outro]\nGoodbye to this summer",
"continue_clip_id": "clip_abc123",
"continue_at": 60,
"tags": "pop, english, emotional"
}
```
***
## Singer Style
Specify a singer style for creation:
```json theme={null}
{
"gpt_description_prompt": "A soulful R&B love ballad",
"mv": "chirp-v4",
"singer_style": "smooth male vocal, R&B"
}
```
***
## Upload Audio for Re-creation
Re-create based on uploaded audio:
```json theme={null}
{
"prompt": "Add lyrics to this melody",
"audio_url": "https://example.com/melody.mp3",
"tags": "pop, english"
}
```
Each submission generates 2 song variants. After submission, use the [Task Query](/en/audio/suno/query) endpoint to get results.
# Suno Generate Lyrics
Source: https://docs.crazyrouter.com/en/audio/suno/lyrics
Use the Suno API to automatically generate lyrics
# Suno Generate Lyrics
```
POST /suno/submit/lyrics
```
Automatically generate lyrics based on a description, which can be used for subsequent custom mode song creation.
## Request Parameters
| Parameter | Type | Required | Description |
| --------- | ------ | -------- | ------------------------ |
| `prompt` | string | Yes | Lyrics theme description |
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/suno/submit/lyrics \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "A song about missing a faraway friend on a rainy day"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/suno/submit/lyrics",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"prompt": "A song about missing a faraway friend on a rainy day"
}
)
print(response.json())
```
## Response Example
```json theme={null}
{
"code": 1,
"description": "Submitted successfully",
"result": "lyrics_task_abc123"
}
```
***
## Query Lyrics Result
Use the [Task Query](/en/audio/suno/query) endpoint to get the generated lyrics:
```bash cURL theme={null}
curl https://crazyrouter.com/suno/fetch/lyrics_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Lyrics Result Example
```json theme={null}
{
"id": "lyrics_task_abc123",
"status": "complete",
"data": {
"title": "Rainy Day Memories",
"text": "[Verse 1]\nRaindrops falling softly on the glass\nBlurring distant city lights\nScrolling through your photos on my phone\nMissing you like rain that never ends\n\n[Chorus]\nYou're so far away, I'm still here\nSeparated by a thousand miles\nBut every raindrop seems to whisper\nHow deeply I miss you tonight\n\n[Verse 2]\nRemember when we danced in the rain\nLaughing through the streets together\nNow you're in another city\nDo you also fall asleep to the sound of rain"
}
}
```
Generated lyrics include section markers (e.g. `[Verse]`, `[Chorus]`) and can be used directly for custom mode song creation.
# Suno Task Query
Source: https://docs.crazyrouter.com/en/audio/suno/query
Query the status and results of Suno song generation tasks
# Suno Task Query
## Query Single Task
```
GET /suno/fetch/{id}
```
### Request Examples
```bash cURL theme={null}
curl https://crazyrouter.com/suno/fetch/suno_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
```python Python theme={null}
import requests
response = requests.get(
"https://crazyrouter.com/suno/fetch/suno_task_abc123",
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
print(response.json())
```
### Response Example (Processing)
```json theme={null}
{
"code": 1,
"data": {
"task_id": "suno_task_abc123",
"status": "processing",
"data": []
}
}
```
### Response Example (Completed)
```json theme={null}
{
"code": 1,
"data": {
"task_id": "suno_task_abc123",
"status": "complete",
"data": [
{
"id": "clip_001",
"title": "Summer Beach",
"audio_url": "https://cdn.suno.ai/audio/clip_001.mp3",
"image_url": "https://cdn.suno.ai/image/clip_001.png",
"duration": 120.5,
"tags": "pop, english, upbeat",
"prompt": "[Verse]\nSunshine on the ocean waves...",
"status": "complete"
},
{
"id": "clip_002",
"title": "Summer Beach",
"audio_url": "https://cdn.suno.ai/audio/clip_002.mp3",
"image_url": "https://cdn.suno.ai/image/clip_002.png",
"duration": 118.3,
"tags": "pop, english, upbeat",
"prompt": "[Verse]\nSunshine on the ocean waves...",
"status": "complete"
}
]
}
}
```
***
## Batch Query
```
POST /suno/fetch
```
Query multiple tasks at once.
### Request Parameters
| Parameter | Type | Required | Description |
| --------- | ----- | -------- | ---------------- |
| `ids` | array | Yes | List of task IDs |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/suno/fetch \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"ids": ["suno_task_abc123", "suno_task_def456"]
}'
```
***
## Get WAV Format
Some completed tasks provide lossless WAV format audio. Replace the file extension in the `audio_url`:
```
https://cdn.suno.ai/audio/clip_001.wav
```
***
## Task Status
| Status | Description |
| ------------ | ----------- |
| `submitted` | Submitted |
| `processing` | Generating |
| `complete` | Completed |
| `error` | Failed |
***
## Complete Workflow Example
```python Python theme={null}
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://crazyrouter.com"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
# 1. Submit song generation task
resp = requests.post(f"{BASE_URL}/suno/submit/music", headers=headers, json={
"gpt_description_prompt": "An upbeat summer pop song in English",
"mv": "chirp-v4"
})
task_id = resp.json()["result"]
print(f"Task created: {task_id}")
# 2. Poll for results
while True:
resp = requests.get(f"{BASE_URL}/suno/fetch/{task_id}", headers=headers)
result = resp.json()["data"]
if result["status"] == "complete":
for clip in result["data"]:
print(f"Song: {clip['title']}")
print(f"Audio: {clip['audio_url']}")
print(f"Duration: {clip['duration']}s")
print("---")
break
elif result["status"] == "error":
print("Generation failed")
break
time.sleep(10)
```
Each song generation task typically returns 2 variants. Song generation usually takes 1-3 minutes. A polling interval of 10 seconds is recommended.
# Text-to-Speech (TTS)
Source: https://docs.crazyrouter.com/en/audio/tts
Use POST /v1/audio/speech to convert text to speech
# Text-to-Speech (TTS)
```
POST /v1/audio/speech
```
Convert text to natural speech, compatible with the OpenAI TTS API format.
## Request Parameters
| Parameter | Type | Required | Description |
| ----------------- | ------ | -------- | ------------------------------------------------------------------- |
| `model` | string | Yes | Model name: `tts-1`, `tts-1`, `tts-1-hd-1106` |
| `input` | string | Yes | Text to convert, max 4096 characters |
| `voice` | string | Yes | Voice character |
| `response_format` | string | No | Output format: `mp3` (default), `opus`, `aac`, `flac`, `wav`, `pcm` |
| `speed` | number | No | Speed, 0.25-4.0, default 1.0 |
### Available Voices
| Voice | Characteristics |
| --------- | ----------------- |
| `alloy` | Neutral, balanced |
| `echo` | Male, steady |
| `fable` | Male, warm |
| `onyx` | Male, deep |
| `nova` | Female, lively |
| `shimmer` | Female, soft |
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/audio/speech \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "tts-1",
"input": "Hello, welcome to the Crazyrouter API. What a beautiful day!",
"voice": "nova",
"response_format": "mp3",
"speed": 1.0
}' \
--output speech.mp3
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.audio.speech.create(
model="tts-1",
input="Hello, welcome to the Crazyrouter API. What a beautiful day!",
voice="nova",
response_format="mp3",
speed=1.0
)
response.stream_to_file("speech.mp3")
```
```javascript Node.js theme={null}
import OpenAI from "openai";
import fs from "fs";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://crazyrouter.com/v1",
});
const response = await client.audio.speech.create({
model: "tts-1",
input: "Hello, welcome to the Crazyrouter API.",
voice: "nova",
});
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync("speech.mp3", buffer);
```
The response is a binary audio stream. Save it directly to a file.
***
## Model Comparison
| Model | Quality | Latency | Description |
| --------------- | -------- | ------- | -------------------------------------------------- |
| `tts-1` | Standard | Low | Suitable for real-time scenarios |
| `tts-1-hd-1106` | HD | Medium | More natural speech |
| `tts-1` | Highest | Medium | Latest model, supports more languages and emotions |
`tts-1` supports multiple languages and automatically detects the input text language to use the corresponding pronunciation.
The response is a binary audio stream, not JSON. Use `--output` or stream-write to a file.
# Create Embeddings
Source: https://docs.crazyrouter.com/en/embeddings/create
POST /v1/embeddings
Convert text into vector representations
## Overview
Convert input text into high-dimensional vectors for use in semantic search, clustering, recommendations, and more. Fully compatible with the OpenAI Embeddings API format.
## Supported Models
| Model | Dimensions | Description |
| ------------------------ | ---------- | ----------------------------------------- |
| `text-embedding-3-large` | 3072 | High accuracy, recommended for production |
| `text-embedding-3-small` | 1536 | Cost-effective |
| `text-embedding-ada-002` | 1536 | Classic model |
## Request Parameters
Embedding model name, e.g. `text-embedding-3-large`
Text to embed. Supports a single string or an array of strings
Return format: `float` or `base64`
Output vector dimensions (only supported by `text-embedding-3-*` models)
## Response Format
```json theme={null}
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.0023064255, -0.009327292, ...]
}
],
"model": "text-embedding-3-large",
"usage": {
"prompt_tokens": 8,
"total_tokens": 8
}
}
```
## Code Examples
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
response = client.embeddings.create(
model="text-embedding-3-large",
input="Crazyrouter is an AI model gateway"
)
embedding = response.data[0].embedding
print(f"Vector dimensions: {len(embedding)}")
print(f"First 5 values: {embedding[:5]}")
```
```python Python (Batch) theme={null}
response = client.embeddings.create(
model="text-embedding-3-large",
input=[
"First text",
"Second text",
"Third text"
]
)
for item in response.data:
print(f"Index {item.index}: dimensions {len(item.embedding)}")
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/embeddings \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-3-large",
"input": "Crazyrouter is an AI model gateway"
}'
```
Batch requests support up to 2048 texts per call. Each text should not exceed 8191 tokens.
# Rerank
Source: https://docs.crazyrouter.com/en/embeddings/rerank
POST /v1/rerank
Semantically rerank search results
## Overview
Reorder a set of documents by semantic relevance to a query. Commonly used as the second-stage reranking step in RAG (Retrieval-Augmented Generation) pipelines.
Implemented following the [SiliconFlow Rerank API](https://docs.siliconflow.cn/cn/api-reference/rerank/create-rerank) format.
## Supported Models
| Model | Description |
| --------------- | ----------------------------------------- |
| `gte-rerank-v2` | Multilingual reranking model, recommended |
| `gte-rerank-v2` | Primarily English |
## Request Parameters
Reranking model name, e.g. `gte-rerank-v2`
Query text
List of documents to rerank
Return the top N results. Defaults to returning all
Whether to include the original document text in the response
## Response Format
```json theme={null}
{
"model": "gte-rerank-v2",
"results": [
{
"index": 2,
"relevance_score": 0.9875,
"document": { "text": "Most relevant document content" }
},
{
"index": 0,
"relevance_score": 0.7432,
"document": { "text": "Second most relevant document content" }
},
{
"index": 1,
"relevance_score": 0.1205,
"document": { "text": "Less relevant document content" }
}
],
"usage": {
"total_tokens": 128
}
}
```
## Code Examples
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/rerank",
headers={
"Authorization": "Bearer sk-xxx",
"Content-Type": "application/json"
},
json={
"model": "gte-rerank-v2",
"query": "What is a vector database",
"documents": [
"A vector database is a database system specialized for storing and retrieving high-dimensional vectors",
"Relational databases use tables to store structured data",
"Vector databases support approximate nearest neighbor search, suitable for semantic retrieval scenarios",
"Redis is an in-memory key-value store"
],
"top_n": 2,
"return_documents": True
}
)
data = response.json()
for result in data["results"]:
print(f"[{result['relevance_score']:.4f}] {result['document']['text']}")
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/rerank \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "gte-rerank-v2",
"query": "What is a vector database",
"documents": [
"A vector database is a database system specialized for storing and retrieving high-dimensional vectors",
"Relational databases use tables to store structured data"
],
"top_n": 2
}'
```
## Typical RAG Pipeline
```
User Query → Embedding Retrieval Top-K → Rerank → LLM Generates Answer
```
The number of input documents for reranking should not exceed 100. Too many documents will increase latency and cost.
# GPTs Conversations
Source: https://docs.crazyrouter.com/en/gpts
Call OpenAI GPTs applications via API
## Overview
Crazyrouter supports calling OpenAI GPTs (custom GPT applications) through the standard Chat Completions API. Simply set the model name to the GPTs-specific format.
## Model Name Format
```
gpt-4-gizmo-{gizmo_id}
```
The `gizmo_id` is the unique identifier for the GPT, which can be extracted from the GPTs URL.
## Getting the Gizmo ID
1. Visit the [ChatGPT GPTs Store](https://chatgpt.com/gpts)
2. Open the target GPT application
3. Extract the ID from the URL: `https://chatgpt.com/g/g-B3hgivKK9-xxx` → ID is `g-B3hgivKK9`
## Code Examples
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
# Chat with a GPT
response = client.chat.completions.create(
model="gpt-4-gizmo-g-B3hgivKK9",
messages=[
{"role": "user", "content": "Hello, please introduce yourself"}
]
)
print(response.choices[0].message.content)
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/chat/completions \
-H "Authorization: Bearer sk-xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4-gizmo-g-B3hgivKK9",
"messages": [
{"role": "user", "content": "Hello, please introduce yourself"}
]
}'
```
GPTs calls require upstream channel support. Not all GPTs are available - availability depends on channel configuration.
GPTs conversations support streaming output by setting `stream: true`. Billing is calculated based on GPT-4 model pricing.
# DALL-E
Source: https://docs.crazyrouter.com/en/images/dalle
Use the DALL-E 3 model to generate and edit images
# DALL-E
```
POST /v1/images/generations
```
Use the DALL-E 3 model to generate images, compatible with the OpenAI Images API format.
## Generate Image
### Request Parameters
| Parameter | Type | Required | Description |
| ----------------- | ------- | -------- | -------------------------------------------- |
| `model` | string | Yes | `dall-e-3` or `dall-e-3` |
| `prompt` | string | Yes | Image description prompt |
| `n` | integer | No | Number of images, DALL-E 3 only supports 1 |
| `size` | string | No | Image size |
| `quality` | string | No | Quality: `standard` (default), `hd` |
| `style` | string | No | Style: `vivid` (default), `natural` |
| `response_format` | string | No | Response format: `url` (default), `b64_json` |
### Size Options
| Model | Supported Sizes |
| ---------- | ------------------------------------- |
| `dall-e-3` | `1024x1024`, `1792x1024`, `1024x1792` |
| `dall-e-3` | `256x256`, `512x512`, `1024x1024` |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "dall-e-3",
"prompt": "A traditional Chinese ink wash painting of mountains and waterfalls shrouded in mist",
"n": 1,
"size": "1792x1024",
"quality": "hd",
"style": "natural"
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.images.generate(
model="dall-e-3",
prompt="A traditional Chinese ink wash painting of mountains and waterfalls shrouded in mist",
n=1,
size="1792x1024",
quality="hd",
style="natural"
)
print(response.data[0].url)
print(response.data[0].revised_prompt)
```
### Response Example
```json theme={null}
{
"created": 1709123456,
"data": [
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/...",
"revised_prompt": "A traditional Chinese ink wash painting depicting a mountainous landscape with a waterfall cascading down rocky cliffs, surrounded by misty clouds..."
}
]
}
```
***
## Edit Image
```
POST /v1/images/edits
```
Use DALL-E 2 for localized image editing.
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.images.edit(
model="dall-e-3",
image=open("image.png", "rb"),
mask=open("mask.png", "rb"),
prompt="Add a kitten in the blank area",
n=1,
size="1024x1024"
)
print(response.data[0].url)
```
DALL-E 3 automatically optimizes your prompt (`revised_prompt`), generating a more detailed description to improve image quality.
DALL-E 3 can only generate 1 image per request (`n=1`). For multiple images, send multiple requests.
# Doubao Seedream
Source: https://docs.crazyrouter.com/en/images/doubao
Use the Doubao Seedream family through the OpenAI Images-compatible public contract
# Doubao Seedream
```
POST /v1/images/generations
```
Crazyrouter exposes the `Seedream` image family through the OpenAI Images-compatible public contract. Clients keep using `/v1/images/generations`; ByteDance official and other third-party channels stay internal as providers only.
## Public Models
| Model | Official counterpart | Customer-facing capability | Doc state |
| --------------------- | -------------------- | -------------------------------------------------------------- | --------- |
| `doubao-seedream-4-0` | Seedream 4.0 | text-to-image, image-to-image, multi-reference, grouped output | Beta |
| `doubao-seedream-4-5` | Seedream 4.5 | text-to-image, image-to-image, multi-reference, grouped output | Beta |
| `doubao-seedream-5-0` | Seedream 5.0 lite | text-to-image, image-to-image, multi-reference, grouped output | Beta |
| `doubao-seedream-3-0` | Seedream 3.0 | compatibility only | Legacy |
“Beta” here means the customer-facing contract and official capability definition are aligned first, while production carrier closure and live artifact evidence are still being completed.
## Public Contract
### Request Parameters
| Parameter | Type | Required | Description |
| ----------------------------- | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `model` | string | Yes | `doubao-seedream-4-0`, `doubao-seedream-4-5`, or `doubao-seedream-5-0` |
| `prompt` | string | Yes | generation prompt |
| `image_input` | string or string\[] | No | reference image URL(s); official 4.0 / 4.5 / 5.0 lite currently document up to `14` images |
| `size` | string | No | output size. `Seedream 4.5` officially supports `2K`, `4K`, and explicit width×height inside the official range |
| `n` | integer | No | output image count, default `1` |
| `response_format` | string | No | `url` or `b64_json` |
| `watermark` | boolean | No | whether to enable watermark |
| `sequential_image_generation` | string | No | `auto` or `disabled`; used for grouped-output semantics |
| `optimize_prompt_options` | object | No | official prompt optimization options; `Seedream 4.5` and `5.0 lite` are currently aligned only with `mode: "standard"` |
### Reference Image Limits
* `Seedream 4.0`, `4.5`, and `5.0 lite` officially support up to `14` reference images
* maximum single reference image size is `10MB`
* officially supported input formats now include `jpeg`, `png`, `webp`, `bmp`, `tiff`, and `gif`
* officially supported input aspect-ratio range is `1/16` to `16`
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-seedream-4-5",
"prompt": "A premium product poster featuring a transparent glass perfume bottle with soft morning haze lighting and a minimal Chinese title",
"size": "2K",
"n": 1,
"response_format": "url",
"watermark": false,
"optimize_prompt_options": {
"mode": "standard"
}
}'
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-seedream-4-5",
"prompt": "Generate a group of product posters for the same character while keeping the subject consistent and varying the camera angle and composition",
"image_input": [
"https://example.com/ref-1.png",
"https://example.com/ref-2.png"
],
"size": "2K",
"sequential_image_generation": "auto",
"response_format": "url",
"optimize_prompt_options": {
"mode": "standard"
}
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.images.generate(
model="doubao-seedream-4-5",
prompt="A premium product poster featuring a transparent glass perfume bottle with soft morning haze lighting and a minimal Chinese title",
size="2K",
n=1
)
print(response.data[0].url)
```
### Response Example
```json theme={null}
{
"created": 1709123456,
"data": [
{
"url": "https://crazyrouter.com/files/seedream_image_abc123.png"
}
]
}
```
## Official Billing Truth
The currently confirmed official truth is billing per successfully generated image, not token-display pricing.
| Model | Official billing | Official price | Current doc state |
| --------------------- | ---------------- | ----------------------------------------- | ------------------ |
| `doubao-seedream-4-0` | per image | `$0.03 / image` | officially aligned |
| `doubao-seedream-4-5` | per image | `$0.04 / image` | officially aligned |
| `doubao-seedream-5-0` | per image | official price still pending confirmation | Beta |
## Alignment Notes
* The customer-facing contract has been narrowed to `/v1/images/generations`
* `Seedream 4.5` currently centers on official `2K` and `4K` sizing, with default `2048x2048`
* `optimize_prompt_options.mode` is currently aligned only as `standard` for `Seedream 4.5` and `5.0 lite`; `fast` is not a public commitment yet
* `Seedream 3.0` stays as a compatibility alias, but the official-alignment focus of this page is now `4.0 / 4.5 / 5.0 lite`
# Fal.ai Images
Source: https://docs.crazyrouter.com/en/images/fal
Text-to-image generation and image editing via Fal.ai endpoints
# Fal.ai Images
Crazyrouter proxies Fal.ai image generation endpoints, supporting text-to-image and image editing.
## Text-to-Image
```
POST /fal-ai/nano-banana
```
### Request Parameters
| Parameter | Type | Required | Description |
| --------------------- | ------- | -------- | ------------------------------------------------------------------------------------------- |
| `prompt` | string | Yes | Image description prompt |
| `negative_prompt` | string | No | Negative prompt |
| `image_size` | string | No | Image size: `square_hd`, `landscape_4_3`, `portrait_4_3`, `landscape_16_9`, `portrait_16_9` |
| `num_images` | integer | No | Number of images, default 1 |
| `seed` | integer | No | Random seed |
| `guidance_scale` | number | No | Guidance strength |
| `num_inference_steps` | integer | No | Number of inference steps |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/fal-ai/nano-banana \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "A majestic eagle soaring over snow-capped mountains at sunrise",
"image_size": "landscape_16_9",
"num_images": 1
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/fal-ai/nano-banana",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"prompt": "A majestic eagle soaring over snow-capped mountains at sunrise",
"image_size": "landscape_16_9",
"num_images": 1
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"images": [
{
"url": "https://fal.media/files/...",
"width": 1344,
"height": 768,
"content_type": "image/jpeg"
}
],
"seed": 42,
"prompt": "A majestic eagle soaring over snow-capped mountains at sunrise"
}
```
***
## Image Editing
```
POST /fal-ai/nano-banana/edit
```
Edit an existing image.
### Request Parameters
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | ------------------ |
| `prompt` | string | Yes | Edit description |
| `image_url` | string | Yes | Original image URL |
| `mask_url` | string | No | Mask image URL |
| `strength` | number | No | Edit strength, 0-1 |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/fal-ai/nano-banana/edit \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"prompt": "Add a rainbow in the sky",
"image_url": "https://example.com/landscape.jpg",
"strength": 0.6
}'
```
### Response Example
```json theme={null}
{
"images": [
{
"url": "https://fal.media/files/...",
"width": 1024,
"height": 1024,
"content_type": "image/jpeg"
}
]
}
```
Fal.ai endpoints support multiple underlying models. For available models, refer to the [Model Pricing](https://crazyrouter.com/pricing) page.
# Nano Banana
Source: https://docs.crazyrouter.com/en/images/nano-banana
As of 2026-04-14, nano-banana is no longer recommended through /v1/images/generations; this page keeps only the native Gemini controlled-test path
# Nano Banana
```
Controlled testing only
POST /v1beta/models/nano-banana:generateContent
```
As of `2026-04-14`, the latest Crazyrouter production retest for `nano-banana` showed:
* `nano-banana` currently maps to `nano-banana`
* `POST /v1/images/generations` is no longer recommended for `nano-banana`
* `nano-banana:generateContent` can currently return image output
* but billing consistency on that native path is still under review, so it should be documented only as a controlled-test path, not as a stable production integration
Do not keep documenting `nano-banana` as a recommended `/v1/images/generations` model. Even though the native Gemini path can return image output, it should not be presented as a stable production capability until billing consistency is revalidated.
## Current Status
| Item | Status | Notes |
| ------------------------------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------- |
| Alias mapping | confirmed | `nano-banana -> nano-banana` |
| Native Gemini `generateContent` | returns output | controlled testing only |
| Native-path billing | risky | the `2026-04-14` production retest showed a mismatch between request success and the observed `used_quota` delta |
| OpenAI Images `POST /v1/images/generations` | not recommended | failed in both production and local `4000` retests |
## Current Risks
### 1. `/v1/images/generations` is no longer recommended
On `2026-04-14`, both production and local `4000` retests of `nano-banana` through the public Images-compatible route hit the same failure class:
* `Unknown name "imageOutputOptions" at 'generation_config.image_config'`
* an abnormal billing sample on a failed request
That makes the public Images-compatible route unsuitable as the documented customer entry point for `nano-banana`.
### 2. The native path still has billing-consistency risk
In the current production retest:
* `POST /v1beta/models/nano-banana:generateContent` returned an image successfully
* but the consumption log `quota` and the token-side `used_quota` delta did not line up
So this path should currently be documented as "controlled testing only", not as "stable production integration".
## Current Recommendation
1. If you need a usable image-generation or image-editing route right now, start with [Nano Banana 2](/en/images/nano-banana-2)
2. If you must evaluate `nano-banana`, use only the native Gemini `generateContent` route
3. Do not put `nano-banana` into formal production traffic until billing consistency is cleared
4. Do not use `POST /v1/images/generations` with `model: "nano-banana"`
## Controlled-Test Template
The request below is for same-day controlled testing only. It does not imply stable production readiness:
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/nano-banana:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Generate an IMAGE of a clean banana icon on a white background. Return image output."
}
]
}
],
"generationConfig": {
"responseModalities": ["TEXT", "IMAGE"]
}
}'
```
## Legacy Route
The following legacy pattern is no longer recommended:
```bash theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "nano-banana",
"prompt": "..."
}'
```
This is not just a documentation cleanup. The route is currently unhealthy in both production and local retests.
If you need the currently healthier Gemini image path on Crazyrouter, see [Gemini Image Generation](/en/chat/gemini/image-gen). If you need the more usable Nano Banana-family route right now, start with [Nano Banana 2](/en/images/nano-banana-2).
# Nano Banana 2
Source: https://docs.crazyrouter.com/en/images/nano-banana-2
As of 2026-04-14, nano-banana-2 should use native Gemini generateContent; /v1/images/generations is no longer recommended
# Nano Banana 2
```
Recommended path
POST /v1beta/models/nano-banana-2:generateContent
```
As of `2026-04-14`, the latest Crazyrouter production retest for `nano-banana-2` showed:
* `nano-banana-2` currently maps to `nano-banana-2`
* the recommended route is now native Gemini `generateContent`
* `POST /v1/images/generations` is no longer recommended for `nano-banana-2`
* the same-day production retest on the native path succeeded and billing looked normal
Do not keep documenting `nano-banana-2` as a stable `/v1/images/generations` model. The recommended entry point is now native Gemini `POST /v1beta/models/nano-banana-2:generateContent`.
## Current Status
| Item | Status | Notes |
| ------------------------------------------- | ---------------- | ------------------------------------------------------------ |
| Alias mapping | confirmed | `nano-banana-2 -> nano-banana-2` |
| Native Gemini `generateContent` | recommended | succeeded in the `2026-04-14` production retest |
| Native-path billing | currently normal | billing and consumption looked aligned in the same-day probe |
| OpenAI Images `POST /v1/images/generations` | not recommended | failed in both production and local `4000` retests |
## Current Risks
### 1. The public Images-compatible route is currently unhealthy
When `nano-banana-2` is sent through `POST /v1/images/generations`, the `2026-04-14` production and local `4000` retests both reproduced these failures:
* `Unknown name "imageOutputOptions" at 'generation_config.image_config'`
* `not supported model for image generation`
* `get_channel_failed`
That is why `/v1/images/generations` should no longer be documented as the stable public path for this model alias.
### 2. The native response must still be parsed as Gemini-native output
Even on the recommended route, the client should parse Gemini-native output:
1. Read `candidates[].content.parts[].inlineData` first
2. Do not assume an OpenAI Images-style `data[].url` payload
3. If you later expand to other Gemini image models, also handle `text`-wrapped `data:image/...` payloads or hosted URLs
## Current Recommendation
1. For production use of `nano-banana-2`, switch directly to `nano-banana-2:generateContent`
2. Do not use `POST /v1/images/generations` with `model: "nano-banana-2"`
3. For automation, parse `inlineData` first
## Recommended Request Template
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/nano-banana-2:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Generate an IMAGE of a clean ecommerce hero shot on a white background. Return image output."
}
]
}
],
"generationConfig": {
"responseModalities": ["IMAGE"]
}
}'
```
## Legacy Route
The following legacy pattern is no longer recommended:
```bash theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "nano-banana-2",
"prompt": "..."
}'
```
This is not a one-off outage. The same failure pattern reproduced in both production and local `4000` retests.
For more details on native Gemini image requests, see [Gemini Image Generation](/en/chat/gemini/image-gen). If you still have older code using the Nano Banana-family Images API, migrate `nano-banana-2` to the native Gemini path documented here.
# Nano Banana Pro
Source: https://docs.crazyrouter.com/en/images/nano-banana-pro
Use nano-banana-pro for reference-image generation and editing through the OpenAI Images API
# Nano Banana Pro
```
POST /v1/images/generations
```
Use `nano-banana-pro` for image generation and reference-image editing through one public `OpenAI Images API` style contract.
## What This Page Covers
* This page only covers `nano-banana-pro`
* The customer-facing entry point is `POST /v1/images/generations`
* The input image field is `image_input`
* The current public contract is limited to URL references in `image_input`; `image` and `data:` inputs are not exposed publicly
* Gemini / Vertex and other providers may sit behind this route, but those provider details are not part of the customer contract
## Capability Status
| Capability / Spec | Status | Notes |
| ------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
| `T2I` | `Beta` | Historical coverage exists, but the current public artifact bundle is still centered on edit/reference flows |
| `I2I + 1K` | `Verified` | The single-image edit live path is closed |
| `I2I + 4K` | `Verified` | `4K + 21:9 + png/jpg` has a live artifact |
| `Reference + 1..2 refs` | `Verified` | `2`-reference live verification is closed |
| `2K` | `Beta` | The current public artifact is still pending |
| higher multi-reference limits / exact `30 MiB` boundary | `Beta` | Not committed in the current public contract |
The Pricing page and this doc use the same status language: `Verified` means there is a current minimal live artifact, while `Beta` means the official capability exists but the public validation set or edge coverage is still being completed.
## Currently Validated Capabilities
The following conclusions come from live validation on March 31, 2026:
* official Vertex `channel 318 (vertexsophie)` direct truth:
* `2` reference images work
* local relay on `localhost:4000`, pinned to `channel 318`, verified:
* single `WEBP` URL reference works
* single `JPEG` URL reference works
* `2` `PNG` URL references work
* `resolution: "1K"` works
* `resolution: "4K"` works
* `aspect_ratio: "1:1"` works
* `aspect_ratio: "21:9"` works
* `output_format: "png"` works
* `output_format: "jpg"` works
* the response returns `data[].url`
Do not present the following as fully promised customer-facing capability yet:
* whether the exact multi-image limit is `8` or higher
* `2K`
* exact large-file URL limit
* exact `30 MiB` boundary
* additional `aspect_ratio` combinations
* exact `output_compression` semantics
`nano-banana-pro` currently exposes only `image_input` URL input publicly. The `image` field is rejected by the service, and `data:` / Base64 is not part of the current public contract.
***
## Request Parameters
| Parameter | Type | Required | Description |
| --------------- | ------------------- | -------- | ------------------------------------------------------------------------------ |
| `model` | string | Yes | Fixed as `nano-banana-pro` |
| `prompt` | string | Yes | Generation or edit instruction |
| `image_input` | string or string\[] | No | Reference image URL(s); current public-safe range is conservatively `1` to `2` |
| `resolution` | string | No | Current public promise is `1K` and `4K` |
| `aspect_ratio` | string | No | Current public promise is `1:1` and `21:9` |
| `output_format` | string | No | Current public promise is `png` and `jpg` |
| `n` | integer | No | Number of images, default `1` |
### Current Multi-Image Status
* `2` references: verified
* higher counts: exact upstream max is still pending, so do not promise it publicly yet
### Routing Note
* single-image requests can use normal available carriers
* multi-image requests are currently routed only to official `Gemini / Vertex` carriers
* that is a server-side routing rule; the customer contract stays the same
***
## Request Examples
### Single-Image Edit
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "nano-banana-pro",
"prompt": "Turn this product image into an ultra-wide hero KV with a cleaner background while preserving the subject",
"image_input": [
"https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/fpakfo/image36.webp"
],
"resolution": "4K",
"aspect_ratio": "21:9",
"output_format": "png"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/images/generations",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "nano-banana-pro",
"prompt": "Turn this product image into an ultra-wide hero KV with a cleaner background while preserving the subject",
"image_input": [
"https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250925/fpakfo/image36.webp"
],
"resolution": "4K",
"aspect_ratio": "21:9",
"output_format": "png"
}
)
data = response.json()
print(data["data"][0]["url"])
```
### Two-Reference Input
```json theme={null}
{
"model": "nano-banana-pro",
"prompt": "Blend the subject and composition from these two references into one high-quality hero visual",
"image_input": [
"https://example.com/ref-1.png",
"https://example.com/ref-2.png"
],
"resolution": "1K",
"aspect_ratio": "1:1"
}
```
***
## Response Example
The recommended automation path is to consume `data[].url`:
```json theme={null}
{
"created": 1774846705,
"data": [
{
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/30/sync-image/20260331073825672515332JyP6hAcs-1.png"
}
]
}
```
To retrieve the generated image, read `data[0].url`. Crazyrouter currently archives upstream inline image output and returns a public URL to the client.
***
## Validation Snapshot
| Item | Current Status |
| --------------------------- | -------------- |
| single URL reference | verified |
| `2` URL references | verified |
| `WEBP` URL | verified |
| `JPEG` URL | verified |
| `PNG` URL | verified |
| `1K` | verified |
| `4K` | verified |
| `1:1` | verified |
| `21:9` | verified |
| `output_format = png` | verified |
| `output_format = jpg` | verified |
| exact `8`-image ceiling | `Beta` |
| exact `30 MiB` URL boundary | `Beta` |
| `2K` | `Beta` |
## Current Known Limits
* `image` is not accepted
* `data:` / Base64 is not part of the public input contract
* the docs do not promise more than `2` references yet
* the docs do not promise the exact `30 MiB` URL boundary yet
* the docs do not promise full closure on every screenshot-listed ratio or parameter yet
If you need Gemini native `generateContent` image endpoints, see [Gemini Image Generation](/en/chat/gemini/image-gen) and [Gemini Image Editing](/en/chat/gemini/image-edit). If you care more about reference-count breadth, also see [Nano Banana](/en/images/nano-banana) and [Nano Banana 2](/en/images/nano-banana-2).
# Qwen Image
Source: https://docs.crazyrouter.com/en/images/qwen
Use the Qwen Image family through the OpenAI Images-compatible public contract
# Qwen Image
```
POST /v1/images/generations
```
Crazyrouter exposes the first batch of `Qwen Image` generation models through the OpenAI Images-compatible public contract. Clients keep using `/v1/images/generations`; Alibaba official and third-party channels stay internal as providers only.
## Public Models
| Model | Upstream execution shape | Customer-facing capability | Verification |
| ----------------- | ------------------------ | -------------------------- | ------------ |
| `qwen-image-plus` | async generation | text-to-image | verified |
| `qwen-image-max` | sync generation | text-to-image | verified |
| `qwen-image-2.0` | sync generation | text-to-image | verified |
| `qwen-image-2.0` | sync generation | text-to-image | Beta |
`qwen-image-2.0` is already aligned in protocol and code, but the production carrier evidence is still being closed, so it remains Beta for now.
## Public Contract
### Request Parameters
| Parameter | Type | Required | Description |
| ----------------- | ------- | -------- | -------------------------------------------------------------------------- |
| `model` | string | Yes | `qwen-image-plus`, `qwen-image-max`, `qwen-image-2.0`, or `qwen-image-2.0` |
| `prompt` | string | Yes | text-to-image prompt |
| `size` | string | No | output size; use sizes currently exposed by the model page or playground |
| `n` | integer | No | number of images, default `1` |
| `response_format` | string | No | `url` or `b64_json` |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "qwen-image-max",
"prompt": "A premium perfume poster with soft studio lighting and the title Morning Mist in Chinese",
"size": "1024x1024",
"n": 1,
"response_format": "url"
}'
```
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://crazyrouter.com/v1"
)
response = client.images.generate(
model="qwen-image-max",
prompt="A premium perfume poster with soft studio lighting and the title Morning Mist in Chinese",
size="1024x1024",
n=1
)
print(response.data[0].url)
```
### Response Example
```json theme={null}
{
"created": 1709123456,
"data": [
{
"url": "https://crazyrouter.com/files/qwen_image_abc123.png"
}
]
}
```
## Official Billing Truth
The current official truth for Qwen Image is billing per successfully generated image, not input/output token display pricing.
| Model | Official billing | Official price | Current doc state |
| ----------------- | ---------------- | --------------- | ----------------- |
| `qwen-image-plus` | per image | `¥0.20 / image` | verified |
| `qwen-image-max` | per image | `¥0.50 / image` | verified |
| `qwen-image-2.0` | per image | `¥0.20 / image` | verified |
| `qwen-image-2.0` | per image | `¥0.50 / image` | Beta |
## Scope Notes
* This first batch commits only the public `text-to-image` capability. Additional upstream multimodal abilities are not exposed as separate customer protocols yet.
* Providers may run async or sync upstream paths internally, but the customer-facing contract remains the same OpenAI Images request/response shape.
* The edit model `qwen-image-plus` is not part of this first-batch generation closure. Treat editing as a separate capability decision.
# Aider Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/aider
Connect Aider to Crazyrouter through the OpenAI-compatible path, with separate Windows and macOS install flows, config-file setup, env vars, and validation steps
Aider is a practical terminal pair-programming tool that works especially well for small iterative code changes, diff review, explicit context-file control, and repeated fix cycles inside a git repo. For Crazyrouter, the safest path is Aider's officially supported OpenAI-compatible setup.
## Overview
With environment variables or `~/.aider.conf.yml`, Aider can send requests to Crazyrouter:
* recommended protocol: `OpenAI-compatible API`
* base URL: `https://crazyrouter.com/v1`
* auth variable: `OPENAI_API_KEY`
* recommended default model string: `gpt-5.4`
If your main workflow is `read code -> edit a few places -> inspect the diff -> refine once more`, Aider is often one of the lightest and easiest tools to operationalize.
## Best For
* users who want small-step code edits from the terminal
* workflows that need explicit control over context files, diffs, and commit cadence
* teams that want Aider billed separately from Codex or Claude Code
* users who want the simplest OpenAI-compatible Crazyrouter setup path
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
Aider officially supports these settings:
* `OPENAI_API_KEY`
* `OPENAI_API_BASE`
* `openai-api-key`
* `openai-api-base`
For Crazyrouter, use:
```text theme={null}
OPENAI_API_BASE=https://crazyrouter.com/v1
```
One important accuracy detail: Crazyrouter model names are the raw model IDs shown in the model list and pricing page, such as `gpt-5.4` and `claude-sonnet-4-6`. Use that raw model ID directly in Aider:
```text theme={null}
gpt-5.4
```
Do not add an extra `openai/` prefix to Crazyrouter model names. `openai/gpt-5.4` is not a Crazyrouter model ID and can cause `model not found` or no-route failures.
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated token for Aider |
| Git | Prefer `git 2.23+` |
| Python | If you use the `aider-install` path, make sure you have `Python 3.8-3.13`; if you use the official one-line installer, it can provision Python 3.12 as needed |
| Aider | Use a current stable version |
| Git repo | Aider generally works best inside a git repo |
| Allowed models | Allow at least one coding-friendly model |
Suggested starter allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Full Install Path By Operating System
### Recommended Windows Path
The most reliable Windows setup is: `Git` + `Python` + `PowerShell install flow for Aider` + `PowerShell environment variables`.
Recommended order:
1. Install Git
2. Install Python
3. Install Aider from the official PowerShell installer, or use `aider-install`
4. Set temporary env vars in PowerShell
5. Persist user-level env vars in PowerShell
6. Open a fresh terminal and verify both the command and variables
Recommended verification commands:
```powershell theme={null}
git --version
python --version
pip --version
aider --version
where.exe git
where.exe python
where.exe aider
```
If `aider --version` is not found, close and reopen PowerShell and try again.
### Recommended macOS Path
The smoothest macOS setup is usually: `Xcode Command Line Tools` + `Homebrew` + `Git` + `Python` + `Aider official installer` + `~/.zshrc` for persistent env vars.
Recommended order:
1. Install Xcode Command Line Tools
2. Install Homebrew if needed
3. Install Git and Python
4. Run Aider's official installer, or install via `aider-install` or `uv`
5. Persist env vars in `~/.zshrc`
6. Open a fresh terminal and verify the executable path
Recommended verification commands:
```bash theme={null}
git --version
python3 --version
pip3 --version
aider --version
which git
which python3
which aider
```
### Linux Note
Linux can generally follow the same terminal flow as macOS, except persistent variables usually belong in `~/.bashrc`. For a first pass, it is safer to validate with temporary env vars before making the setup permanent.
## Detailed Install Walkthrough
Before connecting Aider to Crazyrouter, make sure the local toolchain is ready.
### 1. Install Git
```powershell theme={null}
winget install --id Git.Git -e --source winget
git --version
where.exe git
```
```bash theme={null}
xcode-select --install
git --version
```
Or:
```bash theme={null}
brew install git
git --version
which git
```
```bash theme={null}
sudo apt update
sudo apt install -y git
git --version
which git
```
Recommended one-time identity setup:
```bash theme={null}
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
```
### 2. Install Python and pip
```powershell theme={null}
winget install Python.Python.3.12
python --version
pip --version
where.exe python
```
```bash theme={null}
brew install python
python3 --version
pip3 --version
which python3
```
```bash theme={null}
sudo apt update
sudo apt install -y python3 python3-pip python3-venv
python3 --version
pip3 --version
which python3
```
### 3. Install Aider
Aider's current official one-line installers are:
```powershell theme={null}
powershell -ExecutionPolicy ByPass -c "irm https://aider.chat/install.ps1 | iex"
aider --version
where.exe aider
```
```bash theme={null}
curl -LsSf https://aider.chat/install.sh | sh
aider --version
which aider
```
If you prefer a more explicit step-by-step install, Aider's official `aider-install` flow is also valid:
```powershell theme={null}
python -m pip install aider-install
aider-install
aider --version
```
```bash theme={null}
python3 -m pip install aider-install
aider-install
aider --version
```
If your team already standardizes on `uv`, Aider's docs also allow:
```bash theme={null}
python -m pip install uv
uv tool install --force --python python3.12 --with pip aider-chat@latest
aider --version
```
Avoid starting with a plain system-wide `pip install aider-chat`. Aider's own installers, `aider-install`, or `uv` are usually safer and easier to debug.
## Quick Start
In Crazyrouter, create a token named something like `aider`. Start by allowing only models such as `gpt-5.4`, `claude-sonnet-4-6`, and `gemini-3-pro`.
The allowlist here uses Crazyrouter's raw model IDs. Use the same raw model IDs in Aider.
```bash theme={null}
export OPENAI_API_KEY=sk-xxx
export OPENAI_API_BASE=https://crazyrouter.com/v1
echo $OPENAI_API_KEY
echo $OPENAI_API_BASE
```
```powershell theme={null}
$env:OPENAI_API_KEY = "sk-xxx"
$env:OPENAI_API_BASE = "https://crazyrouter.com/v1"
echo $env:OPENAI_API_KEY
echo $env:OPENAI_API_BASE
```
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.bashrc
echo 'export OPENAI_API_BASE=https://crazyrouter.com/v1' >> ~/.bashrc
source ~/.bashrc
echo $OPENAI_API_BASE
```
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.zshrc
echo 'export OPENAI_API_BASE=https://crazyrouter.com/v1' >> ~/.zshrc
source ~/.zshrc
echo $OPENAI_API_BASE
```
```powershell theme={null}
[System.Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-xxx", "User")
[System.Environment]::SetEnvironmentVariable("OPENAI_API_BASE", "https://crazyrouter.com/v1", "User")
$env:OPENAI_API_KEY = "sk-xxx"
$env:OPENAI_API_BASE = "https://crazyrouter.com/v1"
```
Add this to `~/.aider.conf.yml`:
```yaml theme={null}
model: gpt-5.4
openai-api-base: https://crazyrouter.com/v1
```
If you prefer a safer secret-handling pattern, keep the key only in environment variables and store only `model` plus `openai-api-base` in the config file.
If this folder is not a Git repo yet:
```bash theme={null}
git init
git add .
git commit -m "chore: initial snapshot before Aider"
```
If it is already an existing repo, at least inspect the current state first:
```bash theme={null}
git status
```
```bash theme={null}
aider --model gpt-5.4
```
Start with a low-risk task such as: `Check the README for typos and suggest the smallest safe edits.` Confirm Aider can read files and respond sensibly before using it for real code changes.
## Recommended Model Setup
| Use case | Recommended Aider model string | Why |
| ------------------------ | ------------------------------ | --------------------------------------------------------------------------------- |
| default coding driver | `gpt-5.4` | uses Crazyrouter's raw model ID and works as the OpenAI-compatible Aider baseline |
| Claude-style alternative | `claude-sonnet-4-6` | good for long-context explanation and steady multi-turn collaboration |
| Gemini fallback path | `gemini-3-pro` | useful as a second compatibility-validation path |
Recommended rollout: start with `gpt-5.4`. Then add `claude-sonnet-4-6` or `gemini-3-pro` only after the baseline path is stable.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------- | -------------------- | ---------------------------------------------------------------------------- |
| dedicated token | Required | Do not share the Aider token with other IDE or CLI tools |
| model allowlist | Strongly recommended | Keep the model set small to avoid accidental high-cost switching |
| IP restriction | Situational | Consider it on fixed servers; be careful on mobile dev machines |
| quota cap | Strongly recommended | Long sessions and repeated repair loops can add up quickly |
| environment split | Recommended | Separate local development, remote hosts, and CI |
| leak response | Rotate immediately | If `.aider.conf.yml`, shell history, or recordings expose the key, rotate it |
## Verification Checklist
* [ ] `git --version` works
* [ ] `python --version` or `python3 --version` works
* [ ] `aider --version` works
* [ ] `OPENAI_API_KEY` is set correctly
* [ ] `OPENAI_API_BASE` is `https://crazyrouter.com/v1`
* [ ] if `~/.aider.conf.yml` is used, the model string is a Crazyrouter raw model ID such as `gpt-5.4`
* [ ] `aider --model gpt-5.4` launches correctly
* [ ] the first read-only or small-change task succeeds
* [ ] Crazyrouter logs show the matching request
* [ ] token quota and model allowlist match your intended setup
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `401 unauthorized` | wrong, expired, or incomplete API key | generate a new token and set it again |
| `403` or `model not allowed` | the token does not allow the selected model | allow that model in Crazyrouter token settings |
| `404` | wrong base URL or missing `/v1` | use `https://crazyrouter.com/v1` |
| `model not found` | wrong model string, an unsupported `openai/` prefix, or a model that is not currently available on Crazyrouter | switch back to a raw model ID that exists on the pricing page or model list, such as `gpt-5.4` or `claude-sonnet-4-6` |
| Aider launches but performs poorly | the model is too weak or the context is too noisy | return to `gpt-5.4` and reduce the context files |
| config file and env vars behave inconsistently | the two configuration sources conflict | pick one primary source and restart Aider |
| cost rises too quickly | long sessions and too many context files | clear or restart the session and shrink the context |
## Performance And Cost Tips
* validate on a small repo first
* keep `gpt-5.4` as the main model and add `claude-sonnet-4-6` only when you need cross-vendor validation
* split tokens by project type so cost tracking stays clear
* clear context when the session becomes too long or drifts away from the task
* after larger edits, review both the Aider diff and Crazyrouter logs
## FAQ
### What base URL should I use for Aider?
Use `https://crazyrouter.com/v1`.
### Why should the model name not be `openai/gpt-5.4`?
Because Crazyrouter model names do not include provider prefixes. Crazyrouter recognizes raw model IDs such as `gpt-5.4`; `openai/gpt-5.4` is treated as a different model name and is not available.
### Should I prefer env vars or a config file?
Both work. Environment variables are faster for a first setup; `~/.aider.conf.yml` is useful once the setup becomes permanent.
### Which model should I try first?
Start with `gpt-5.4`.
### Does Aider have to run inside a git repo?
Not strictly, but the experience is usually best inside a git repo because change review is easier and safer.
### Why should I avoid allowing too many models at first?
Because multi-turn sessions make troubleshooting, budget control, and stability harder when the model surface area is too broad.
If you want a very lightweight terminal tool for day-to-day small-step coding, Aider still deserves a strong place in the Crazyrouter application guides.
# ChatBox Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/chatbox
Connect Crazyrouter to ChatBox through the OpenAI-compatible provider flow, with verified model guidance, knowledge-base rollout advice, and troubleshooting
ChatBox is a widely used cross-platform AI client with Windows, macOS, Linux, and web availability. When you connect ChatBox to Crazyrouter, the safest approach is to use ChatBox's `OpenAI API Compatible` or `OpenAI API` provider flow instead of searching for a provider-specific preset.
This setup is useful because it:
* is simple for non-technical users
* lets you switch between Crazyrouter-approved models inside one desktop client
* works well for desktop chat, knowledge-base Q\&A, file reading, and everyday writing tasks
## Start Here
Use this configuration first:
* Provider / API Mode: `OpenAI API Compatible` or `OpenAI API`
* API Host: `https://crazyrouter.com`
* API Path: leave it blank or keep the default
* API Key: `sk-xxx`
* First validation model: `gpt-5.4`
According to ChatBox's current official provider documentation, the `API Path` usually does not need to be filled manually because ChatBox already has a default OpenAI-compatible chat path. For Crazyrouter docs, the safest starting point is to enter the root host `https://crazyrouter.com` and avoid manually forcing `/v1/chat/completions` at the beginning.
## Who This Guide Is For
* users who want a fast desktop setup for Crazyrouter
* users who want multi-model daily chat, translation, summarization, or writing assistance
* users who want to combine ChatBox knowledge-base or file-Q\&A features with Crazyrouter
* users who want a full GUI setup without writing code
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------------- |
| Crazyrouter account | Register at [crazyrouter.com](https://crazyrouter.com) first |
| Crazyrouter token | Create a dedicated token for ChatBox |
| ChatBox client | Desktop is recommended because knowledge-base features are stronger there |
| Allowed models | Start by allowing at least one chat model |
Suggested first-pass allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Install ChatBox
### Windows
1. Open the [ChatBox website](https://chatboxai.app/)
2. Download the Windows installer
3. Run the installer
4. Launch ChatBox after setup
### macOS
1. Open the [ChatBox website](https://chatboxai.app/)
2. Download the macOS build
3. Move it into `Applications`
4. If macOS shows a security prompt on first launch, complete the usual allow flow
### Linux
1. Open the [ChatBox website](https://chatboxai.app/)
2. Download the package or desktop build for your distribution
3. Install it and launch ChatBox
If your only goal is to verify that Crazyrouter works in ChatBox, start with the desktop app and postpone multi-device sync, knowledge-base imports, and large model lists until the basic chat path is stable.
## Recommended Provider Setup
The exact labels may vary slightly by ChatBox version. Common entry points include:
* `Settings`
* `Model Provider`
* `AI Provider`
* `Add`
If your current version already includes `OpenAI API`, select it directly. If not, add a new `OpenAI API Compatible` provider.
## Configuration Steps
On the first pass, only allow one or two models such as:
* `gpt-5.4`
* `claude-sonnet-4-6`
A small model scope makes troubleshooting much easier.
Launch ChatBox, then open the settings entry in the lower-left area and go to:
* `Model Provider`
* or `AI Provider`
Use one of these routes:
* if `OpenAI API` already exists, select it
* if not, click `Add` and create an `OpenAI API Compatible` provider
Recommended values:
* `API Host`: `https://crazyrouter.com`
* `API Path`: leave blank or keep the default
* `API Key`: `sk-xxx`
If ChatBox asks for a provider name, `Crazyrouter` is a clear choice.
For the first test, add only:
* `gpt-5.4`
After the minimal path works, you can add:
* `claude-sonnet-4-6`
* `gemini-3-pro`
If your ChatBox version includes a `Check` button, use it first.
If it only has `Save`, save the provider and then return to the main chat screen for validation.
Create a new chat, make sure the selected model is `gpt-5.4`, and send:
```text theme={null}
Reply only OK
```
If you get `OK` or an equivalent short answer consistently, the main ChatBox-to-Crazyrouter path is working.
## Recommended Validation Order
Follow this order instead of enabling everything at once:
1. Start with one token
2. Start with one model: `gpt-5.4`
3. Validate plain text chat first
4. Add a second model later
5. Enable knowledge base, file Q\&A, or more advanced settings only after chat is stable
## Recommended Models
| Scenario | Recommended model | Why |
| -------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------- |
| First connectivity test | `gpt-5.4` | Verified successfully in production on March 23, 2026, and best suited for the OpenAI-compatible baseline |
| Higher-quality writing and explanation | `claude-sonnet-4-6` | Better for detailed explanation, rewriting, and summaries |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path inside the same client |
## How To Use ChatBox Features With Crazyrouter
### Basic chat
This is the best first test and should always come before advanced features.
### Knowledge base / file Q\&A
Turn this on only after basic chat already works. For the first pass:
* keep files small
* keep content simple
* test with one file first
Do not start with a large knowledge-base import before confirming the API configuration itself.
### Multi-model switching
Useful when you want different models for different tasks, for example:
* default baseline chat: `gpt-5.4`
* important summaries and writing: `claude-sonnet-4-6`
* secondary vendor validation: `gemini-3-pro`
## Parameter Suggestions
If your ChatBox version exposes common generation settings, keep the first run conservative:
| Parameter | Suggested value | Notes |
| ---------------- | ------------------- | ----------------------------------------------- |
| Temperature | `0.2` to `0.7` | Keep it moderate during validation |
| Max Tokens | default or moderate | Avoid very large outputs during troubleshooting |
| Context Messages | default | Basic chat validation is enough at first |
## Token Best Practices
| Setting | Recommendation | Why |
| ---------------------- | -------------------- | --------------------------------------------------------------------------- |
| Dedicated token | Required | Do not share it with IDEs or automation tools |
| Model allowlist | Strongly recommended | Start with only one or two models |
| Spending limit | Strongly recommended | Knowledge-base or repeated Q\&A flows can amplify cost |
| Environment separation | Recommended | Separate personal desktop usage from team-shared usage |
| Leak response | Rotate immediately | Replace the key if it appears in screenshots, recordings, or screen sharing |
## Validation Checklist
* [ ] ChatBox is installed and launches normally
* [ ] A dedicated Crazyrouter token was created for ChatBox
* [ ] `OpenAI API` or `OpenAI API Compatible` is selected
* [ ] `API Host` is set to `https://crazyrouter.com`
* [ ] `API Path` is left blank or kept at the default
* [ ] `sk-xxx` was entered successfully
* [ ] Only `gpt-5.4` was added for the first pass
* [ ] Validation succeeded through `Check` or a minimal chat
* [ ] The request appears in Crazyrouter logs
## Common Errors And Fixes
| Symptom | Common cause | Fix |
| ------------------------------------ | ------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| 401 unauthorized | Token is wrong, incomplete, or expired | Generate a new token and paste it again |
| 404 | Host or path is wrong | Reset Host to `https://crazyrouter.com` and keep the path default |
| 403 / model not allowed | The token does not allow the selected model | Allow that model in Crazyrouter token settings |
| `model not found` | The model name is wrong | Switch back to `gpt-5.4` and revalidate |
| Save succeeds but chat fails | Wrong provider type or the model was not actually added | Recheck the provider mode and model list |
| Knowledge-base Q\&A is slow or fails | Files are too large or the task is too complex | Fall back to smaller files and plain text chat |
| Not sure whether `/v1` is required | Current ChatBox versions usually do not need a manually forced full path | Start with the root host and leave `API Path` blank or default |
## FAQ
### Which provider should I select in ChatBox?
Prefer `OpenAI API` or `OpenAI API Compatible`.
### What should I enter as the API Host?
Use `https://crazyrouter.com`.
### Do I need to manually enter `/v1/chat/completions`?
Usually no. Based on ChatBox's official provider documentation, `API Path` typically already has a default value, so leave it blank or unchanged first.
### What should the first model be?
Start with `gpt-5.4`.
### When should I add more models or knowledge-base features?
Only after the minimal chat path is already working.
If your goal is "make ChatBox work first", the best approach is not to configure many models and features at once. Start with `gpt-5.4` and validate the smallest possible chat path.
# ChatGPT on WeChat Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/chatgpt-on-wechat
Configure Crazyrouter API in the ChatGPT on WeChat project with production-verified model recommendations
## Overview
ChatGPT on WeChat is a widely used WeChat bot project that can route private and group chat traffic through Crazyrouter. The safest rollout is to keep its standard OpenAI-compatible configuration and validate one production-verified model before expanding the bot behavior.
## Recommended First-Pass Setup
* `open_ai_api_base`: `https://crazyrouter.com/v1`
* first validation model: `gpt-5.4`
* keep the initial allowlist small so troubleshooting stays simple
## Configuration
### Edit Configuration File
Edit `config.json`:
```json theme={null}
{
"open_ai_api_key": "sk-xxx",
"open_ai_api_base": "https://crazyrouter.com/v1",
"model": "gpt-5.4",
"proxy": "",
"single_chat_prefix": [""],
"single_chat_reply_prefix": "",
"group_chat_prefix": ["@bot"],
"group_name_white_list": ["AI Chat Group"]
}
```
### Environment Variables
```bash theme={null}
export OPEN_AI_API_KEY=sk-xxx
export OPEN_AI_API_BASE=https://crazyrouter.com/v1
export MODEL=gpt-5.4
```
### Docker Deployment
```yaml theme={null}
services:
chatgpt-on-wechat:
image: zhayujie/chatgpt-on-wechat
environment:
- OPEN_AI_API_KEY=sk-xxx
- OPEN_AI_API_BASE=https://crazyrouter.com/v1
- MODEL=gpt-5.4
volumes:
- ./config.json:/app/config.json
```
## Recommended Models
| Scenario | Model | Description |
| --------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
| First-pass route validation | `gpt-5.4` | Verified successfully in Crazyrouter production on March 23, 2026, and best for the OpenAI-compatible baseline |
| Higher-quality long replies | `claude-sonnet-4-6` | Better for complex explanations, summaries, and longer text |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
## Suggested Validation Order
1. Create one dedicated token
2. Start with one model: `gpt-5.4`
3. Send `Reply only OK` in a private chat first
4. Confirm the request appears in Crazyrouter logs
5. Only then expand group triggers, prefixes, and additional models
WeChat bot projects must comply with WeChat usage policies. Avoid sending messages too frequently to prevent account restrictions.
# ChatGPT Sidebar Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/chatgpt-sidebar
Configure Crazyrouter API in the ChatGPT Sidebar browser extension with the latest verified models
## Overview
ChatGPT Sidebar is a browser sidebar AI assistant extension suited for quick Q\&A, translation, summarization, and webpage reading help on any site. When connecting it to Crazyrouter, use its `Custom API` or `OpenAI` entry first and validate the route with a production-verified model before expanding the setup.
## Configuration Steps
Install ChatGPT Sidebar from the Chrome Web Store.
Click the extension icon and go to `Settings`.
* **API Provider**: Select `Custom API` or `OpenAI`
* **API URL**: `https://crazyrouter.com/v1`
* **API Key**: `sk-xxx`
* **Model**: `gpt-5.4`
Save settings. Click the extension icon on any web page to start using it.
## Recommended Models
| Scenario | Model |
| ------------------------------------ | ------------------- |
| First-pass route validation | `gpt-5.4` |
| Higher-quality long-form explanation | `claude-sonnet-4-6` |
| Gemini fallback path | `gemini-3-pro` |
`gpt-5.4` was verified successfully in Crazyrouter production on March 23, 2026, and is the best OpenAI-compatible baseline for this browser-extension path.
# Cherry Studio Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/cherry-studio
Connect Crazyrouter to Cherry Studio through its OpenAI-compatible provider flow, then finish first-run validation, model setup, MCP usage, and troubleshooting
Cherry Studio is a desktop AI client that works well for multi-model chat, research notes, and MCP-assisted workflows. When connecting it to Crazyrouter, the most reliable path is Cherry Studio's custom `OpenAI` provider mode, because it usually gives you the cleanest model management, streaming, and general chat compatibility.
## Overview
Using Cherry Studio's custom provider support, you can add Crazyrouter as an OpenAI-compatible upstream:
* Recommended protocol: `OpenAI-compatible API`
* Recommended provider type: `OpenAI`
* API URL: `https://crazyrouter.com`
* Auth method: `sk-...` token
* Recommended first validation model: `gpt-5.4`
Cherry Studio's official docs explain that if the upstream endpoint is something like `https://xxx.com/v1/chat/completions`, you usually enter only the root URL in `API URL`. For Crazyrouter, start with `https://crazyrouter.com`, not `https://crazyrouter.com/v1`.
Cherry Studio appends the standard remaining path automatically. You only need to enter a full custom path ending with `#` when the upstream is not using the normal `.../v1/chat/completions` route shape. Normal Crazyrouter chat setup does not need that.
## Best For
* desktop users who want one place for multiple models
* teams or individuals doing daily chat, writing, translation, and research
* users who want to combine Crazyrouter with MCP tools
* users who want fast switching between cheap and strong models
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
The recommended setup is to add a custom `OpenAI` provider and enter the Crazyrouter root domain in `API URL`:
```text theme={null}
https://crazyrouter.com
```
Do not start with:
* `https://crazyrouter.com/v1/chat/completions`
* `https://crazyrouter.com/v1/models`
Cherry Studio only needs a full custom path with a trailing `#` in special non-standard routing scenarios. Normal Crazyrouter chat setup does not need that.
## Prerequisites
| Item | Details |
| ------------------- | ------------------------------------------------------------ |
| Crazyrouter account | Register first at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for Cherry Studio |
| Cherry Studio | Use a current stable desktop build |
| Available models | Allow at least one verified chat model such as `gpt-5.4` |
Recommended starting whitelist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## 5-Minute Quick Start
In the Crazyrouter dashboard, create a new token named `cherry-studio`. For the first pass, allow only 2 to 4 models you know you actually need.
Open Cherry Studio, go to `Settings` → `Model Services`, then click `Add` or `+ Add`. Choose the provider type `OpenAI` and name it `Crazyrouter`.
In the provider settings, enter:
* `API Key`: your `sk-...`
* `API URL`: `https://crazyrouter.com`
Then click `Check` to validate the token and URL.
Open `Manage`, fetch the model list, and add the models you want to use. Seeing a model in the popup does not always mean it is already enabled in the provider list, so you may still need to click `+` to add it. For first-run validation, start with only one baseline model: `gpt-5.4`.
Turn on the provider toggle, go back to the chat screen, pick `gpt-5.4`, and send a simple prompt such as `Reply only OK`. If you get a normal reply, the setup is working.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ------------------------------------ | ------------------- | ---------------------------------------------------------------------------------------------------- |
| Default chat model | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the OpenAI-compatible baseline |
| Higher-quality code / long-form help | `claude-sonnet-4-6` | Strong reasoning, writing, and code explanation |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
Recommended order: get `gpt-5.4` working first, then add `claude-sonnet-4-6` and `gemini-3-pro`.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ------------------------------- | --------------------------- | ------------------------------------------------------------------------------------- |
| Dedicated token | Required | Do not share the same token with Cursor, Claude Code, or Codex |
| Model whitelist | Strongly recommended | Allow only the models Cherry Studio will actually use |
| IP restriction | Depends on your environment | Fine for fixed office networks; risky on laptops that change networks often |
| Quota cap | Strongly recommended | Desktop chat apps can generate lots of multi-turn traffic |
| Dev / shared machine separation | Recommended | Use separate tokens for personal, shared, and demo devices |
| Multi-key rotation | Use carefully | Cherry Studio supports multiple keys, but debugging is easier with a single key first |
## Verification Checklist
* [ ] `Check` succeeds in the provider settings
* [ ] `API URL` is set to `https://crazyrouter.com`
* [ ] the provider toggle is enabled
* [ ] at least one model was added from `Manage`
* [ ] the first chat request succeeds
* [ ] streaming output renders normally
* [ ] MCP services work if you enabled them
* [ ] the request appears in the Crazyrouter logs
## MCP Usage Tips
Cherry Studio supports MCP services, but the cleanest rollout is a two-step process:
1. verify the Crazyrouter chat model first
2. add MCP services only after the model path is stable
That keeps model-routing issues separate from MCP tool issues.
If you enable MCP:
* start with a model that handles tool use reliably
* attach only one MCP service for the first test
* use a simple read-only tool call before trying more complex actions
## Common Errors and Fixes
| Symptom | Likely cause | Fix |
| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `Check` fails | wrong API key or pasted value contains spaces | regenerate the token and paste a clean `sk-...` value |
| 401 unauthorized | token expired, was deleted, or is invalid | create a new token in Crazyrouter and replace it |
| 403 / model not allowed | the selected model is not in the token whitelist | allow that model in the token settings |
| 404 | `API URL` was entered as a full endpoint path, or the provider type is wrong | switch back to the `OpenAI` provider type and set the URL to `https://crazyrouter.com` |
| `Check` still fails even though the URL and key look right | Cherry Studio often validates against the last conversational model currently present in the provider list, and that model may be invalid | keep only `gpt-5.4`, remove suspicious models, and run `Check` again |
| model list does not load | wrong URL, network problem, or provider not enabled | run `Check`, then confirm the provider toggle and network connectivity |
| connection works but chat still fails | the added model is incompatible or unavailable | keep only `gpt-5.4` for baseline testing |
| streaming behaves oddly | model-level or client-version compatibility issue | switch back to `gpt-5.4` and upgrade Cherry Studio |
| MCP tool calls fail | the issue is in the MCP service, not the model route | disable MCP, confirm the model works, then fix MCP separately |
## Performance and Cost Tips
* Start with only 1 to 2 models so the first rollout stays easy to debug
* Default to `gpt-5.4`, then switch to `claude-sonnet-4-6` for harder long-form and code tasks
* If you keep long conversations open, give Cherry Studio its own quota cap
* Since Cherry Studio makes model switching easy, reserve expensive models for heavier work only
* If usage looks abnormal, check the Crazyrouter logs first for retries or long multi-turn sessions
## FAQ
### Which URL should I enter in Cherry Studio?
Start with `https://crazyrouter.com`.
### Why is `/v1` not the recommended first setting here?
Because Cherry Studio's own docs explain that many OpenAI-compatible upstreams only need the root URL, and the client appends the standard path itself. Crazyrouter should be set up that way first.
### When would I need a full endpoint path ending with `#`?
Only when your upstream is not using a standard OpenAI route pattern. For normal Crazyrouter chat setup, do not use that mode first.
### Which model should I test first?
Start with `gpt-5.4`.
### Can I configure many models right away?
Yes, but it is better not to do that on day one. Get one baseline model working first, then expand.
### Can Cherry Studio use MCP together with Crazyrouter?
Yes, but validate the chat model first and enable MCP after that. It makes troubleshooting much easier.
If your main goal is desktop multi-model chat and light MCP workflows, Cherry Studio is a strong option. If your main goal is agentic coding inside an IDE or terminal, Cursor, Claude Code, Codex, or Cline should still be the higher priority tools.
# Claude Code Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/claude-code
Connect Claude Code to Crazyrouter through the Anthropic Messages API, with full step-by-step instructions from Git and Node.js to installation commands, environment variables, and first-run validation
Claude Code is one of the best terminal coding tools to connect to Crazyrouter. It speaks the Anthropic Messages API directly and works especially well for code reading, editing, refactoring, command execution, tool use, and long-context repository analysis.
## Overview
With a few environment variables, Claude Code can send Anthropic requests directly to Crazyrouter:
* recommended protocol: `Anthropic Messages API`
* base URL: `https://crazyrouter.com`
* China-optimized base URL: `https://cn.crazyrouter.com`
* auth variable: `ANTHROPIC_API_KEY`
* recommended default model: `claude-sonnet-4-6`
Claude Code appends the Anthropic request path itself, so the base URL must stay at the site root: `https://crazyrouter.com` or `https://cn.crazyrouter.com`. Do not append `/v1` or `/v1/messages`.
If you want a script to install Claude Code and write the Crazyrouter environment variables for you, review the crazyrouter-claude-code repository.
## Best For
* developers who want Crazyrouter as the backend for Claude Code
* users who want stable tool use, long context, and terminal-first coding workflows
* teams that want Claude Code billed separately from Cursor, Codex, or Aider
* cross-platform setups that need one consistent CLI configuration
## Protocol Used
Recommended protocol: `Anthropic Messages API`
Use:
```text theme={null}
ANTHROPIC_BASE_URL=https://crazyrouter.com
```
For the China-optimized API route, use:
```text theme={null}
ANTHROPIC_BASE_URL=https://cn.crazyrouter.com
```
Do not use:
* `https://crazyrouter.com/v1`
* `https://crazyrouter.com/v1/messages`
* `https://crazyrouter.com/v1/complete`
* `https://cn.crazyrouter.com/v1`
* `https://cn.crazyrouter.com/v1/messages`
## System Requirements And Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------ |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for Claude Code |
| Git | `git 2.23+` is recommended for reviewing and rolling back AI edits |
| Node.js | `Node.js 18+` is recommended |
| Claude Code | Use a current stable release |
| Claude model access | Allow at least `claude-sonnet-4-6` on the token |
Suggested starter allowlist:
* `claude-sonnet-4-6`
* `claude-opus-4-6`
## Full Install Paths By OS
### Recommended Windows path
On Windows, the safest path is: `Git` + `Node.js` + `npm global install for Claude Code` + `PowerShell` for environment variables.
Recommended order:
1. Install Git
2. Install Node.js LTS
3. Install Claude Code with npm
4. Set temporary variables in PowerShell
5. Persist user-level variables in PowerShell
Recommended verification:
```powershell theme={null}
git --version
node -v
npm -v
claude --version
where.exe git
where.exe node
where.exe claude
```
If `claude --version` is still not found, close and reopen PowerShell before retrying.
### Recommended macOS path
On macOS, the smoothest path is usually: `Xcode Command Line Tools` + `Homebrew` + `Git` + `Node.js` + `npm global install for Claude Code` + `~/.zshrc` for persistent environment variables.
Recommended order:
1. Install Xcode Command Line Tools
2. Install Homebrew if needed
3. Install Git and Node.js
4. Install Claude Code with npm
5. Persist variables in `~/.zshrc`
6. Open a fresh terminal and verify the binary path
Recommended verification:
```bash theme={null}
git --version
node -v
npm -v
claude --version
which git
which node
which claude
```
### Why you should not append API paths manually
Claude Code uses the Anthropic-native protocol. You only provide the site root:
```text theme={null}
ANTHROPIC_BASE_URL=https://crazyrouter.com
```
The China-optimized route also uses only the site root:
```text theme={null}
ANTHROPIC_BASE_URL=https://cn.crazyrouter.com
```
Do not append `/v1`, `/v1/messages`, or any specific API path the way you would with an OpenAI-compatible client.
If you prefer a script that installs Claude Code and writes the Crazyrouter-related environment variables automatically, see [crazyrouter-claude-code](https://github.com/xujfcn/crazyrouter-claude-code). That repository provides one-click setup scripts for Windows, macOS, and Linux; this guide keeps the full manual path so you can audit each setting.
## Full Setup From Scratch
If Git is not installed yet, install it first before touching Claude Code.
```powershell theme={null}
winget install --id Git.Git -e --source winget
git --version
```
```bash theme={null}
xcode-select --install
git --version
```
If you already use Homebrew, you can also run:
```bash theme={null}
brew install git
git --version
```
```bash theme={null}
sudo apt update
sudo apt install -y git
git --version
```
After installation, set your global identity once:
```bash theme={null}
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
```
Claude Code depends on Node.js. Verify the installed version before going further.
```powershell theme={null}
winget install OpenJS.NodeJS.LTS
node -v
npm -v
```
```bash theme={null}
brew install node
node -v
npm -v
```
```bash theme={null}
sudo apt update
sudo apt install -y nodejs npm
node -v
npm -v
```
If `node -v` is still below 18 after installation, upgrade through `nvm` or the official Node installer before continuing.
```powershell theme={null}
npm install -g @anthropic-ai/claude-code
claude --version
where.exe claude
```
```bash theme={null}
npm install -g @anthropic-ai/claude-code
claude --version
which claude
```
Do not use `sudo npm install -g @anthropic-ai/claude-code`. If global npm permissions are broken, fix the npm/Node environment first instead of forcing a privileged install.
Log in to Crazyrouter and create a separate token named something obvious like `claude-code`.
For the first pass, allow only:
* `claude-sonnet-4-6`
* `claude-opus-4-6`
Give it its own budget so it does not share spend with Cursor, Codex, or OpenClaw.
Start with a temporary setup first. Once validation succeeds, make it persistent.
```bash theme={null}
export ANTHROPIC_BASE_URL=https://crazyrouter.com
export ANTHROPIC_API_KEY=sk-xxx
echo $ANTHROPIC_BASE_URL
echo $ANTHROPIC_API_KEY
```
```powershell theme={null}
$env:ANTHROPIC_BASE_URL = "https://crazyrouter.com"
$env:ANTHROPIC_API_KEY = "sk-xxx"
echo $env:ANTHROPIC_BASE_URL
echo $env:ANTHROPIC_API_KEY
```
If you use the China-optimized route, set `ANTHROPIC_BASE_URL` to the root domain `https://cn.crazyrouter.com`, not `https://cn.crazyrouter.com/v1`.
Temporary variables disappear after the shell closes. For regular use, write them to your shell profile.
```bash theme={null}
echo 'export ANTHROPIC_BASE_URL=https://crazyrouter.com' >> ~/.bashrc
echo 'export ANTHROPIC_API_KEY=sk-xxx' >> ~/.bashrc
source ~/.bashrc
```
```bash theme={null}
echo 'export ANTHROPIC_BASE_URL=https://crazyrouter.com' >> ~/.zshrc
echo 'export ANTHROPIC_API_KEY=sk-xxx' >> ~/.zshrc
source ~/.zshrc
```
```powershell theme={null}
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://crazyrouter.com", "User")
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-xxx", "User")
$env:ANTHROPIC_BASE_URL = "https://crazyrouter.com"
$env:ANTHROPIC_API_KEY = "sk-xxx"
```
If you use the China-optimized route, persist `ANTHROPIC_BASE_URL` as `https://cn.crazyrouter.com`.
Then open a fresh terminal and re-check:
```bash theme={null}
claude --version
echo $ANTHROPIC_BASE_URL
```
```powershell theme={null}
claude --version
echo $env:ANTHROPIC_BASE_URL
```
Claude Code can edit files and run commands. For the first validation, use a repo you know well.
If the current folder is not a Git repo yet:
```bash theme={null}
git init
git add .
git commit -m "chore: initial snapshot before Claude Code"
```
If it is already an existing repo, at least confirm the current state first:
```bash theme={null}
git status
```
Enter the project directory and run:
```bash theme={null}
cd /path/to/your/project
claude
```
For the first validation, use this order:
1. `Reply with only OK`
2. `Read the current repository structure only. Do not modify any files.`
3. `Find obvious typos in the README, but do not edit files yet.`
If all three work and Crazyrouter logs show matching requests, the setup is good.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ------------------------------- | ------------------- | -------------------------------------------------------------- |
| default daily driver | `claude-sonnet-4-6` | best balance of quality, speed, and cost for most coding tasks |
| difficult refactors | `claude-opus-4-6` | stronger complex reasoning, planning, and code understanding |
| long-context repo analysis | `claude-sonnet-4-6` | stable and strong for long sessions |
| cost-sensitive first validation | `claude-sonnet-4-6` | first get the main path working reliably |
Recommended rollout: stabilize normal work on `claude-sonnet-4-6`, then switch to `claude-opus-4-6` only for genuinely heavier tasks.
## Using Non-Claude Models in Claude Code
Beyond the native Claude family, Crazyrouter exposes several third-party models through the Anthropic Messages protocol. You can use them in Claude Code simply by switching the model name. The list below has been **end-to-end verified** (text / system / tool use / streaming SSE all pass).
### Verified working models
| Model ID | Provider | Tool Use | Streaming | Thinking | Best For |
| ----------------------------------------------------------------- | ------------- | -------- | --------- | -------------------------------------- | ------------------------------------------- |
| `deepseek-v4-pro` | DeepSeek | ✅ | ✅ | — | General coding & refactors, best price/perf |
| `deepseek-v4-flash` | DeepSeek | ✅ | ✅ | ✅ native | Reasoning with visible thinking blocks |
| `deepseek-reasoner` | DeepSeek | ✅ | ✅ | reasoning | Math / complex logic |
| `deepseek-chat` / `deepseek-v3` / `deepseek-v3.2` / `deepseek-r1` | DeepSeek | ✅ | ✅ | — | General text tasks |
| `MiniMax-M2.7` | MiniMax | ✅ | ✅ | ⚠️ inside text block as `` tags | Long-context CN tasks |
| `MiniMax-M2.5` | MiniMax | ✅ | ✅ | ⚠️ inside text block | General chat |
| `MiniMax-M2.1` | MiniMax | ✅ | ✅ | — | No thinking, cleanest output |
| `kimi-k2.5` / `kimi-k2` / `kimi-k2-instruct` | Moonshot Kimi | ✅ | ✅ | — | Long-context, CN-heavy work |
| `kimi-k2-thinking` | Moonshot Kimi | ✅ | ✅ | reasoning | Complex reasoning |
| `kimi-k2-0711-preview` / `kimi-k2-0905-preview` | Moonshot Kimi | ✅ | ✅ | — | Snapshot versions |
> Tested against `https://crazyrouter.com/v1/messages` with `anthropic-version: 2023-06-01` using a standard Anthropic Messages payload.
The following models currently return `get_channel_failed` on the Anthropic protocol (an upstream channel availability issue, not a protocol incompatibility). Use them via `/v1/chat/completions` (OpenAI protocol) for now:
* `moonshot-v1-8k` / `moonshot-v1-32k` / `moonshot-v1-128k`
* `kimi-k2-0905` (without the `-preview` suffix)
Channels such as `grok-*`, `coze`, `jimeng`, `baidu`, `zhipu`, `tencent`, `xunfei`, `mistral`, `cohere`, and `palm` **do not implement** Anthropic protocol conversion and cannot be used in Claude Code.
### How to switch models
Claude Code picks the model from the `ANTHROPIC_MODEL` environment variable, or via the in-session `/model` command. Replace the value with any model ID from the table above.
```bash theme={null}
export ANTHROPIC_BASE_URL=https://crazyrouter.com
export ANTHROPIC_API_KEY=sk-xxx
# Default to DeepSeek V4 Pro
export ANTHROPIC_MODEL=deepseek-v4-pro
claude
# Or one-off switch to Kimi thinking
ANTHROPIC_MODEL=kimi-k2-thinking claude
# Or one-off switch to MiniMax
ANTHROPIC_MODEL=MiniMax-M2.1 claude
```
```powershell theme={null}
$env:ANTHROPIC_BASE_URL = "https://crazyrouter.com"
$env:ANTHROPIC_API_KEY = "sk-xxx"
$env:ANTHROPIC_MODEL = "deepseek-v4-pro"
claude
# Or one-off switches
$env:ANTHROPIC_MODEL = "kimi-k2-thinking"; claude
$env:ANTHROPIC_MODEL = "MiniMax-M2.1"; claude
```
You can also switch inside a running Claude Code session:
```text theme={null}
/model deepseek-v4-pro
/model kimi-k2-thinking
/model MiniMax-M2.1
```
### Usage notes and known differences
* **DeepSeek family**: highest protocol fidelity. Tool calls, streaming, and `stop_reason=tool_use` all match Anthropic's spec; `deepseek-v4-flash` returns native `thinking` blocks that Claude Code renders as a thinking pane. **Recommended default: `deepseek-v4-pro`**.
* **Kimi family**: strong long-context behavior, tool calls work normally. `kimi-k2-thinking` includes a reasoning trace, useful for hard tasks.
* **MiniMax family**: the only models whose pricing entry explicitly advertises `anthropic` in `supported_endpoint_types`, so the protocol layer is the most direct fit. However, `M2.5` / `M2.7` emit their reasoning as a regular text block **wrapped in `...` tags** — Claude Code will display them verbatim. Two ways to avoid this:
1. Use `MiniMax-M2.1` (no thinking trace).
2. Add a system prompt: "Do not output `` tags or your reasoning, only return the final answer."
* **Token allowlist**: if your Claude Code-dedicated token has model allowlisting enabled, add the models above to it in the Crazyrouter dashboard, otherwise you will get `403 model not allowed`.
* **Thinking and billing**: thinking-enabled models (`-thinking`, `-flash`, `reasoner`, `MiniMax-M2.5/2.7`) consume extra output tokens. Set a separate budget cap on the Claude Code token.
### One-line check that a model works
```bash theme={null}
curl -sS https://crazyrouter.com/v1/messages \
-H "Authorization: Bearer $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-pro",
"max_tokens": 32,
"messages": [{"role":"user","content":"reply OK"}]
}'
```
A `200` response with non-empty `content[].text` means Claude Code can use this model.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ---------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------- |
| dedicated token | Required | Do not share Claude Code tokens with Cursor, Codex, or OpenClaw |
| model allowlist | Strongly recommended | Most Claude Code setups only need 1 to 2 Claude models |
| IP restriction | Recommended on fixed-egress environments | Be careful on laptops with changing IPs |
| quota cap | Strongly recommended | Long sessions and tool use can steadily consume budget |
| developer / host split | Recommended | Give each developer or shared host its own token |
| incident rotation | Required | If shell history, recordings, or shared terminals expose the token, rotate it immediately |
## Verification Checklist
* [ ] `git --version` works
* [ ] `node -v` is at least 18
* [ ] `claude --version` works
* [ ] `ANTHROPIC_BASE_URL` is set to `https://crazyrouter.com` or `https://cn.crazyrouter.com`
* [ ] `ANTHROPIC_API_KEY` is set correctly
* [ ] Claude Code launches successfully
* [ ] the first plain-text request succeeds
* [ ] repository read-only inspection works
* [ ] Crazyrouter logs show the Claude Code traffic
* [ ] token quota and model allowlist match your intended setup
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `claude: command not found` | Claude Code did not install cleanly, or the npm global path is not on PATH | reinstall and make sure the global npm bin directory is in PATH |
| Node version is too old | local Node.js version is below the requirement | upgrade to Node.js 18+ and reinstall Claude Code |
| `401 unauthorized` | invalid, expired, or badly pasted `ANTHROPIC_API_KEY` | create a new token and set the variables again |
| `403` or `model not allowed` | the token does not allow the selected Claude model | allow the required model in Crazyrouter |
| `404` | base URL was set with `/v1` or `/v1/messages` | reset it to `https://crazyrouter.com` or `https://cn.crazyrouter.com` |
| logs show `/v1/v1/messages`, `/v1/v1/models`, or `/v1/messages/v1/messages` | Claude Code was given a base URL that already contains `/v1` or a full endpoint, then appended its own path | set `ANTHROPIC_BASE_URL` to the root domain with no path |
| Claude Code still uses old settings | new environment variables were not reloaded | reopen the terminal or run `source ~/.bashrc` / `source ~/.zshrc` |
| Git changes become messy | no repository snapshot was created before AI edits | commit an initial snapshot before larger changes |
| cost is higher than expected | long context, repeated tool use, and long sessions | shorten sessions, split tasks, and cap budget per token |
## Performance And Cost Tips
* start with `claude-sonnet-4-6`
* switch to `claude-opus-4-6` only for hard architecture analysis or heavy refactors
* validate first in a small repo, not a large production repo
* check `git status` before each new task
* watch Crazyrouter logs and quota more closely when tool use becomes frequent
## FAQ
### Which base URL should I use for Claude Code?
Use the site root: `https://crazyrouter.com`
For the China-optimized route, use the site root: `https://cn.crazyrouter.com`
### Why should I not include `/v1` here?
Because Claude Code appends the Anthropic Messages path itself. You only provide the site root.
### What should I use on Windows?
If you mainly develop from the command line, prefer PowerShell or WSL2. In either case, make sure Git, Node.js, and Claude Code itself are installed correctly first.
### On Windows, should I use PowerShell or Git Bash?
For first-time setup, prefer PowerShell. Environment-variable persistence, `where.exe` checks, and user-level configuration are all more direct there.
### Why should I create a Git snapshot before the first real task?
Because Claude Code can edit files and run commands. A clean snapshot makes review and rollback much easier.
### Which model should I try first?
Start with `claude-sonnet-4-6`. It is usually the safest baseline.
If your first priority is Claude-family models plus a terminal-first coding workflow, Claude Code should be near the front of your Crazyrouter integration order.
Review the one-click setup scripts, README, and latest usage notes.
# Claude Dev Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/claude-dev
Configure Crazyrouter API in the Claude Dev VS Code extension with the latest verified Claude models
## Overview
Claude Dev is a VS Code AI coding extension suited for Claude-style code explanation, refactoring suggestions, and multi-turn collaboration through Crazyrouter. For public docs, prefer the OpenAI Compatible route first because it is more consistent with the rest of the Crazyrouter integration stack and easier to troubleshoot.
The `https://crazyrouter.com/v1` URL on this page applies only to Claude Dev's `OpenAI Compatible` provider. Do not copy it into Claude Code's `ANTHROPIC_BASE_URL`; Claude Code should use the root domain `https://crazyrouter.com` or `https://cn.crazyrouter.com`.
## Recommended Configuration
Search for `Claude Dev` in the VS Code extension marketplace and install it.
Click the Claude Dev icon in the sidebar to enter settings.
Prefer `OpenAI Compatible` as the API provider.
* **Base URL**: `https://crazyrouter.com/v1`
* **API Key**: `sk-xxx`
* **Model**: `claude-sonnet-4-6`
If you use the China-optimized API route and Claude Dev is set to the `OpenAI Compatible` provider, you can set the Base URL to `https://cn.crazyrouter.com/v1`.
## Recommended Models
| Scenario | Model |
| ------------------------------ | ------------------- |
| Daily coding | `claude-sonnet-4-6` |
| Heavier reasoning and planning | `claude-opus-4-7` |
`claude-sonnet-4-6` and `claude-opus-4-7` match the latest verified Claude model guidance in this doc set. For the smallest first-pass VS Code validation, start with `claude-sonnet-4-6`.
# Cline Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/cline
Connect Crazyrouter to the Cline VS Code extension through the OpenAI Compatible provider, with separate Windows and macOS install flows, setup, validation, and troubleshooting steps
Cline is a strong agent-style coding extension for VS Code, especially for file edits, terminal execution, step-by-step planning, and multi-turn code changes. For Crazyrouter, the recommended path is Cline's official `OpenAI Compatible` provider.
## Overview
With the OpenAI Compatible provider, Cline can send its agent traffic to Crazyrouter:
* recommended protocol: `OpenAI-compatible API`
* base URL: `https://crazyrouter.com/v1`
* auth format: `sk-...` token
* recommended default models: `claude-sonnet-4-6` or `gpt-5.4`
Cline can read and write files and execute terminal commands. After the connection works, the real risk is not connectivity but over-granting execution scope. Start with a small repo you know well.
## Best For
* users who want an agent-style coding workflow inside VS Code
* code modification flows powered by Crazyrouter's multi-model access
* teams that want IDE agent traffic separated from CLI traffic
* developers who want Claude, GPT, and other models behind one gateway
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
In Cline settings, use:
* `API Provider`: `OpenAI Compatible`
* `Base URL`: `https://crazyrouter.com/v1`
* `API Key`: your `sk-...`
* `Model ID`: the model you want to use
Do not set the base URL to:
* `https://crazyrouter.com`
* `https://crazyrouter.com/v1/chat/completions`
Unlike Claude Code, Codex, or Aider, the normal Cline-in-VS-Code path usually does not require shell environment variables. In most cases, you only need to enter `Base URL`, `API Key`, and `Model ID` in the Cline settings UI.
## Prerequisites
| Item | Notes |
| --------------------- | -------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated token for Cline |
| Git | Prefer `git 2.23+` |
| VS Code | Use a current stable release |
| Cline extension | Use a current version |
| Allowed models | Allow at least 1 to 2 models suitable for agentic coding |
| Environment variables | Usually not required for the standard VS Code setup |
Suggested starter allowlist:
* `claude-sonnet-4-6`
* `gpt-5.4`
* `gemini-3-pro`
## Full Install Path By Operating System
### Recommended Windows Path
The most reliable Windows setup is: `Git` + `VS Code` + `install Cline from the marketplace` + `enter Crazyrouter settings directly in Cline`.
Recommended order:
1. Install Git
2. Install VS Code
3. Install Cline from the VS Code marketplace
4. Create a Cline-specific Crazyrouter token
5. Open your repo and take a Git snapshot first
6. Fill in `OpenAI Compatible`, `Base URL`, `API Key`, and `Model ID` inside Cline
Recommended verification commands:
```powershell theme={null}
git --version
where.exe git
code --version
where.exe code
```
If `code --version` is not available but VS Code itself opens normally, Cline can still work fine. You just will not be able to open folders from the terminal with `code` yet.
### Recommended macOS Path
The smoothest macOS setup is usually: `Xcode Command Line Tools` + `Homebrew` + `Git` + `VS Code` + `install Cline from the marketplace`.
Recommended order:
1. Install Xcode Command Line Tools
2. Install Homebrew if needed
3. Install Git
4. Install VS Code
5. Install Cline in VS Code
6. Enter the Crazyrouter settings directly inside Cline
Recommended verification commands:
```bash theme={null}
git --version
which git
open -a "Visual Studio Code"
```
If you want the terminal `code` command, run `Shell Command: Install 'code' command in PATH` from the VS Code command palette, then verify:
```bash theme={null}
code --version
which code
```
### Linux Note
Linux users can generally follow the same pattern: install Git, install VS Code, then install Cline from the extension marketplace. A common Ubuntu / Debian path is:
```bash theme={null}
sudo apt update
sudo apt install -y git
sudo snap install code --classic
git --version
code --version
```
## Detailed Install Walkthrough
If Git is not installed yet, install it first.
```powershell theme={null}
winget install --id Git.Git -e --source winget
git --version
where.exe git
```
```bash theme={null}
xcode-select --install
git --version
```
Or:
```bash theme={null}
brew install git
git --version
which git
```
```bash theme={null}
sudo apt update
sudo apt install -y git
git --version
which git
```
Recommended one-time identity setup:
```bash theme={null}
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
```
Cline is most commonly used as a VS Code extension.
```powershell theme={null}
winget install Microsoft.VisualStudioCode
code --version
where.exe code
```
```bash theme={null}
brew install --cask visual-studio-code
open -a "Visual Studio Code"
```
If you want the `code` terminal command, run this from the VS Code command palette:
```text theme={null}
Shell Command: Install 'code' command in PATH
```
Then verify:
```bash theme={null}
code --version
which code
```
```bash theme={null}
sudo snap install code --classic
code --version
which code
```
After installation, open VS Code normally at least once.
In VS Code:
1. Press `Ctrl/Cmd + Shift + X`
2. Search for `Cline`
3. Click Install
4. Open Cline from the activity bar or from the command palette with `Cline: Open In New Tab`
If VS Code shows a prompt like `Running extensions might...`, allow it.
If you do not see the Cline icon, restart VS Code and check again.
In Crazyrouter, create a token named something like `cline`. For the first pass, allow only:
* `claude-sonnet-4-6`
* `gpt-5.4`
* `gemini-3-pro`
The standard Cline-in-VS-Code path usually stores the API key in the UI rather than through shell env vars. The most important setup decisions here are a dedicated token and a narrow allowlist.
Cline can edit files and run commands, so take a repo snapshot before you trust it with real work.
If this directory is not a Git repo yet:
```bash theme={null}
git init
git add .
git commit -m "chore: initial snapshot before Cline"
```
If it is already an existing repo, inspect the current state first:
```bash theme={null}
git status
```
In the Cline settings panel, enter:
* `API Provider`: `OpenAI Compatible`
* `Base URL`: `https://crazyrouter.com/v1`
* `API Key`: your `sk-...`
* `Model ID`: start with `claude-sonnet-4-6`
If your current Cline version shows a `Verify` button, click it first to confirm the connection. If not, you can validate with a small read-only prompt instead.
For the first pass, validate with only one model rather than switching across many models immediately.
Recommended validation order:
1. `Read the current workspace README and summarize it without changing any files.`
2. `Point out the 3 files that are most worth reviewing first.`
3. `Fix one obvious typo in the README only and show the diff.`
Once those all work and Crazyrouter logs show the matching requests, the main path is stable.
Only after the read-only and tiny-edit path is stable should you move to:
1. small multi-file changes
2. low-risk command execution
3. larger agent-style refactors
Avoid starting with broad autonomous runs in a large unfamiliar repo.
## Recommended Model Setup
| Use case | Recommended model | Why |
| -------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------- |
| default agent driver | `claude-sonnet-4-6` | stable for multi-turn planning, code explanation, and long context |
| OpenAI-compatible baseline | `gpt-5.4` | verified successfully in production on March 23, 2026, and suited for the main OpenAI-compatible path |
| Gemini fallback path | `gemini-3-pro` | useful as a second compatibility-validation path |
Recommended rollout: get the workflow stable on `claude-sonnet-4-6` first. If you also want an OpenAI-compatible baseline, add `gpt-5.4` second.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------- | ------------------------------------ | ------------------------------------------------------------------ |
| dedicated token | Required | Do not share Cline tokens with Cursor, Claude Code, or Aider |
| model allowlist | Strongly recommended | Cline is a higher-consumption tool, so narrow allowlists are safer |
| IP restriction | Recommended on fixed office networks | Use carefully on laptops and mobile networks |
| quota cap | Strongly recommended | Multi-step agent runs can consume budget very quickly |
| environment split | Recommended | Separate local VS Code, remote dev hosts, and team environments |
| permission split | Strongly recommended | High-risk repos should use their own low-budget token |
## Verification Checklist
* [ ] `git --version` works
* [ ] VS Code is installed correctly
* [ ] if you want terminal repo opening, `code --version` also works
* [ ] Cline is installed and opens correctly
* [ ] Cline is set to the `OpenAI Compatible` provider
* [ ] `Base URL` is `https://crazyrouter.com/v1`
* [ ] `API Key` is entered correctly
* [ ] `Model ID` is a real allowed model
* [ ] the first read-only task succeeds
* [ ] file edits or command flows work when expected
* [ ] Crazyrouter logs show the matching requests
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ------------------------------------------------ | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| the extension installs but no Cline icon appears | VS Code did not refresh or the extension was not activated cleanly | restart VS Code and reopen Cline from the command palette |
| the `code` command does not exist | VS Code is installed but the shell command is not in PATH | on Windows, reopen the terminal; on macOS, run `Shell Command: Install 'code' command in PATH` |
| `401 unauthorized` | wrong, expired, or badly pasted API key | create a new token and paste it again |
| `403` or `model not allowed` | the token does not allow the selected model | allow that model in Crazyrouter token settings |
| `404` | base URL was set to the root domain or a full endpoint path | use `https://crazyrouter.com/v1` |
| `model not found` | incorrect `Model ID` or unavailable model | switch back to `claude-sonnet-4-6` or another confirmed model |
| it cannot connect on a corporate network | proxy or firewall settings are blocking traffic | check VS Code's own proxy settings first; the Cline extension reuses VS Code's proxy configuration |
| Cline edits the wrong files | permissions are too wide or the prompt scope is too loose | validate with read-only tasks first, then widen permissions gradually |
| cost rises too fast | multi-step planning, large context, and auto execution | narrow the task scope and give Cline its own budget |
## Performance And Cost Tips
* start with read-only tasks and small edits on first setup
* use `claude-sonnet-4-6` or `gpt-5.4` for complex refactors
* avoid widening the model list too early; keep the first-pass allowlist narrow
* use different tokens for different workspaces or project types
* after large tasks, inspect Crazyrouter logs to see the real cost pattern
## FAQ
### Which provider should I choose in Cline?
Choose `OpenAI Compatible`.
### What base URL should I use?
Use `https://crazyrouter.com/v1`.
### Do I have to set environment variables for this Cline path?
Usually no. The normal VS Code path generally works by entering `Base URL`, `API Key`, and `Model ID` directly in Cline's settings UI.
### Which model should I try first?
Start with `claude-sonnet-4-6`.
### Why should I take a Git snapshot before the first real task?
Because Cline is a real coding agent that can edit files and run commands. A snapshot makes review and rollback much easier.
### Why should I avoid broad permissions immediately?
Because the safest rollout pattern is read-only first, then tiny edits, then wider execution scope only after the integration is clearly stable.
If you want a true agent workflow inside VS Code, Cline is usually a better fit than Cursor's BYOK path.
# OpenAI Codex CLI Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/codex
Connect Codex CLI to Crazyrouter with a custom provider for the OpenAI Responses API, with full step-by-step instructions from Git and Node.js to installation commands, config files, and environment variables
Codex CLI is OpenAI's terminal coding agent for repo edits, code review, large refactors, and command-driven development. For Crazyrouter, the recommended path is the current `config.toml` custom-provider setup, not the older configuration style.
## Overview
With a custom provider in `~/.codex/config.toml`, Codex CLI can send its requests to Crazyrouter:
* recommended protocol: `OpenAI-compatible API`
* API style used by Codex: `Responses API`
* base URL: `https://crazyrouter.com/v1`
* auth variable: `OPENAI_API_KEY`
* recommended default model: `gpt-5.4`
If you previously used only the ChatGPT login flow in Codex, switch to the API-key plus custom-provider path for Crazyrouter. It gives you cleaner control over models, logs, quota, and billing.
If you want a script to write the environment variables and Codex config for you, review the crazyrouter-codex-cli repository.
## Best For
* users who want Crazyrouter in a terminal agent workflow
* repo-scale edits, reviews, and automated coding tasks
* teams that want Codex traffic billed separately from Cursor or Claude Code
* coding-first workflows built around currently verified latest OpenAI models
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
Codex CLI currently works best with a custom `model_provider` configured like this:
* `base_url = "https://crazyrouter.com/v1"`
* `wire_api = "responses"`
Crazyrouter supports `/v1/responses`, so this Codex CLI integration can use the Responses API directly. But this path should currently be treated as GPT-only guidance because Claude does not support `POST /v1/responses`.
## System Requirements And Prerequisites
| Item | Notes |
| ------------------- | ---------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for Codex |
| Git | `git 2.23+` is recommended |
| Node.js | `Node.js 20+` is recommended |
| Codex CLI | Use a current stable version |
| Allowed models | Allow at least one coding-friendly model such as `gpt-5.4` |
Suggested starter allowlist:
* `gpt-5.4`
## Full Install Paths By OS
### Recommended Windows path
On Windows, the simplest path is: `Git` + `Node.js` + `npm global install for Codex` + `PowerShell` for environment variables and config.
Recommended order:
1. Install Git
2. Install Node.js LTS
3. Install Codex CLI with npm
4. Write `OPENAI_API_KEY` through PowerShell
5. Write `$HOME/.codex/config.toml` through PowerShell
Recommended verification:
```powershell theme={null}
git --version
node -v
npm -v
codex --version
where.exe git
where.exe node
where.exe codex
```
If `codex --version` is still not found, close and reopen PowerShell before retrying.
### Recommended macOS path
On macOS, the smoothest path is usually: `Homebrew` + `Git` + `Node.js` + `brew` or `npm` install for Codex + `~/.zshrc` for persistent environment variables.
Recommended order:
1. Install Xcode Command Line Tools
2. Install Homebrew if needed
3. Install Git and Node.js
4. Install Codex CLI
5. Persist `OPENAI_API_KEY` in `~/.zshrc`
6. Write `~/.codex/config.toml`
Recommended verification:
```bash theme={null}
git --version
node -v
npm -v
codex --version
which git
which node
which codex
```
### Alternative Codex install paths
Besides package managers, the official Codex GitHub repository also publishes binary releases. For most users, the recommended defaults are still:
* Windows: `npm install -g @openai/codex`
* macOS: `brew install --cask codex` or `npm install -g @openai/codex`
If you prefer a script that writes the Crazyrouter-related settings automatically, see [crazyrouter-codex-cli](https://github.com/xujfcn/crazyrouter-codex-cli). That repository provides one-click setup scripts for Windows, macOS, and Linux; this guide keeps the full manual path so you can audit each setting.
## Full Setup From Scratch
If Git is not installed yet, install it first and add a global identity.
```powershell theme={null}
winget install --id Git.Git -e --source winget
git --version
```
```bash theme={null}
xcode-select --install
git --version
```
Or:
```bash theme={null}
brew install git
git --version
```
```bash theme={null}
sudo apt update
sudo apt install -y git
git --version
```
Then run:
```bash theme={null}
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
```
Codex CLI is a Node.js tool. Make sure Node and npm are ready first.
```powershell theme={null}
winget install OpenJS.NodeJS.LTS
node -v
npm -v
```
```bash theme={null}
brew install node
node -v
npm -v
```
```bash theme={null}
sudo apt update
sudo apt install -y nodejs npm
node -v
npm -v
```
If your distro installs an older Node version, upgrade before continuing.
Recommended: use npm global install directly.
```powershell theme={null}
npm install -g @openai/codex
codex --version
where.exe codex
```
Recommended: use Homebrew first.
```bash theme={null}
brew install --cask codex
codex --version
which codex
```
If you prefer npm:
```bash theme={null}
npm install -g @openai/codex
codex --version
which codex
```
In Crazyrouter, create a token named something like `codex`. For the first pass, allow only:
* `gpt-5.4`
This keeps first-pass debugging and cost control much simpler.
Codex reads `OPENAI_API_KEY` through the provider config. Start with the current terminal only:
```bash theme={null}
export OPENAI_API_KEY=sk-xxx
echo $OPENAI_API_KEY
```
```powershell theme={null}
$env:OPENAI_API_KEY = "sk-xxx"
echo $env:OPENAI_API_KEY
```
For regular use, write the API key into your shell profile or user environment variables.
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.bashrc
source ~/.bashrc
```
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.zshrc
source ~/.zshrc
```
```powershell theme={null}
[System.Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-xxx", "User")
$env:OPENAI_API_KEY = "sk-xxx"
```
Codex CLI reads `~/.codex/config.toml` at startup.
```bash theme={null}
mkdir -p ~/.codex
cat > ~/.codex/config.toml <<'EOF'
model = "gpt-5.4"
model_provider = "crazyrouter"
[model_providers.crazyrouter]
name = "Crazyrouter"
base_url = "https://crazyrouter.com/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
[profiles.crazyrouter]
model = "gpt-5.4"
model_provider = "crazyrouter"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
EOF
```
```powershell theme={null}
New-Item -ItemType Directory -Force "$HOME/.codex" | Out-Null
@'
model = "gpt-5.4"
model_provider = "crazyrouter"
[model_providers.crazyrouter]
name = "Crazyrouter"
base_url = "https://crazyrouter.com/v1"
env_key = "OPENAI_API_KEY"
wire_api = "responses"
[profiles.crazyrouter]
model = "gpt-5.4"
model_provider = "crazyrouter"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
'@ | Set-Content -Path "$HOME/.codex/config.toml"
```
After writing the file, verify it:
```bash theme={null}
cat ~/.codex/config.toml
```
```powershell theme={null}
Get-Content $HOME/.codex/config.toml
```
If the current folder is not a repo yet:
```bash theme={null}
git init
git add .
git commit -m "chore: initial snapshot before Codex"
```
If it is already an existing repo, at least inspect the current state first:
```bash theme={null}
git status
```
In the repo, start with a minimal validation first:
```bash theme={null}
cd /path/to/your/project
codex --profile crazyrouter "Reply only OK"
```
After that, start interactive mode:
```bash theme={null}
codex --profile crazyrouter
```
Recommended validation order:
1. `Reply only OK`
2. `Read the repository structure only. Do not edit files.`
3. `Find the highest-risk file in this repo and explain why, but do not change anything.`
## Recommended Model Setup
| Use case | Recommended model | Why |
| --------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------ |
| default coding driver | `gpt-5.4` | verified successfully in production on March 23, 2026, and best suited for the main Codex / Responses API baseline |
If you need Claude, use the native Claude `POST /v1/messages` path or OpenAI-compatible `POST /v1/chat/completions` instead of putting Claude onto the Codex `wire_api = "responses"` route.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------- | ---------------------------------------- | ----------------------------------------------------------------- |
| dedicated token | Required | Do not share a Codex token with Cursor or Claude Code |
| model allowlist | Strongly recommended | Keep only the models Codex actually needs |
| IP restriction | Recommended on fixed-egress environments | Be careful on devices that change networks often |
| quota cap | Strongly recommended | Agent-style execution can consume budget quickly |
| environment split | Recommended | Use separate tokens for local machines, remote hosts, and CI |
| leak response | Rotate immediately | Shell history, config backups, or screen shares can expose tokens |
## Verification Checklist
* [ ] `git --version` works
* [ ] `node -v` works
* [ ] `codex --version` works
* [ ] `OPENAI_API_KEY` is set correctly
* [ ] `~/.codex/config.toml` contains `model_provider = "crazyrouter"`
* [ ] `base_url` is `https://crazyrouter.com/v1`
* [ ] `wire_api` is `responses`
* [ ] the first request succeeds
* [ ] Crazyrouter logs show the matching request
* [ ] token quota and allowlist match your intended setup
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `codex: command not found` | CLI did not install cleanly, or the global npm bin directory is not on PATH | reinstall Codex and ensure the global npm bin path is on PATH |
| `401 unauthorized` | wrong, expired, or badly pasted `OPENAI_API_KEY` | create a new token and reset the variable |
| `403` or `model not allowed` | the token does not allow the selected model | allow the required model in Crazyrouter |
| `404` | `base_url` is wrong or missing `/v1` | change it to `https://crazyrouter.com/v1` |
| request-shape errors | `wire_api` is not `responses` | set `wire_api = "responses"` |
| Codex launches but does not use Crazyrouter | `model_provider` is not switched to `crazyrouter` | re-check `config.toml` |
| Git changes are hard to review | no clean repo snapshot before AI edits | commit a first snapshot before real edits |
| cost grows too quickly | long context, repeated tool use, or one token shared across repos | split tokens, cap quota, and keep the model allowlist small |
## Performance And Cost Tips
* validate first in a small repo, not a huge production repo
* keep `gpt-5.4` as the main driver and get the GPT / Responses baseline working first
* separate Codex from IDE tools for cleaner cost attribution
* use stricter quota caps for higher-risk repos or CI jobs
* when spend spikes, inspect Crazyrouter logs first to see whether agent loops are the cause
## FAQ
### Which base URL should I use in Codex CLI?
Use `https://crazyrouter.com/v1`.
### On Windows, should I use PowerShell or Git Bash?
For first-time setup, prefer the PowerShell path in this guide. It is the easiest way to keep user-level environment variables and `$HOME/.codex/config.toml` consistent.
### Why do I need `wire_api = "responses"`?
Because Codex CLI's custom-provider path is designed around the Responses API, and Crazyrouter supports `/v1/responses`.
### Why is Claude no longer recommended here?
Because Claude currently supports only `POST /v1/messages` and `POST /v1/chat/completions`, not `POST /v1/responses`. The Codex path here is fixed to `wire_api = "responses"`, so Claude should not be presented as a recommended model for this route.
### Why should I make a Git snapshot before the first real task?
Because Codex can edit files and run commands. A clean snapshot makes review and rollback much easier.
### If I already used `codex login`, do I still need an API key?
Yes. For Crazyrouter, you should still use `OPENAI_API_KEY` plus the custom provider configuration.
### Which model should I try first?
Start with `gpt-5.4`.
If you want the smoothest terminal agent workflow on the OpenAI / Responses API path, configure Codex around the GPT / Responses route. If you want Claude first, switch to Claude Code or the native Claude API docs instead.
Review the one-click setup scripts, README, and latest usage notes.
# Coze Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/coze
Use Crazyrouter in Coze through API plugins or workflow HTTP nodes, and clearly separate the public setup path from enterprise custom-model capabilities
Coze is ByteDance's bot and workflow platform. It is useful for building bots, chaining workflow steps, calling plugins, and publishing to different channels. When connecting Coze to Crazyrouter, the most stable and public-doc-friendly path is not to assume every Coze plan supports direct custom-model integration. The recommended public path is to use an HTTP / API plugin or a workflow HTTP request node first.
## Start Here
For most Crazyrouter users, these are the two recommended Coze integration paths:
* Option 1: call Crazyrouter through a `Create from API` plugin
* Option 2: call Crazyrouter through a workflow HTTP request node
Do not present "attach Crazyrouter directly as a custom model in Coze model management" as the default public guide, because:
* Coze features differ across editions, regions, and plans
* Coze's published plan FAQ explicitly lists `custom model` as an enterprise flagship capability
* For public documentation, the safer baseline is the HTTP / API plugin route
The most important accuracy rule for this page is: document Coze's public baseline as "call Crazyrouter through HTTP / API plugins or workflow HTTP requests", not "every user can directly mount a custom upstream model".
## Who This Guide Is For
* Users who want to call Crazyrouter inside a Coze bot or workflow
* Users who want Crazyrouter to act as an external model endpoint
* Users who want the smallest reproducible setup before touching enterprise-only capabilities
* Teams that want plugin- or workflow-based access to multiple models
## Recommended Public Setup
### Public baseline: HTTP / API plugin route
Recommended parameters:
* Request method: `POST`
* URL: `https://crazyrouter.com/v1/chat/completions`
* Headers:
* `Authorization: Bearer sk-xxx`
* `Content-Type: application/json`
* First validation model: `gpt-5.4`
### Why this route comes first
Because it:
* depends less on Coze plan differences
* makes it easier to tell whether the issue is Coze setup or Crazyrouter token / model scope
* is the most stable route to document publicly
## Requirements And Prerequisites
| Item | Notes |
| ----------------------- | ------------------------------------------------------------ |
| Crazyrouter account | Register at [crazyrouter.com](https://crazyrouter.com) first |
| Crazyrouter token | Create a dedicated token for Coze |
| Coze account | You need access to create bots, workflows, or plugins |
| Publish or debug access | At minimum, you should be able to debug a bot or workflow |
| Allowed models | Allow at least one chat model first |
Suggested initial allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Option 1: Connect Crazyrouter Through An API Plugin
For the first pass, only allow:
* `gpt-5.4`
* `claude-sonnet-4-6`
Do not enable too many models on day one. Troubleshooting is easier when the scope is small.
In the Coze workspace, open the area that matches your current version, usually something like:
* `Plugins`
* `Create Plugin`
* `Create from API` or a similarly named entry
Exact menu names may vary by Coze version, region, or product line, but the core idea is the same: create a plugin that calls an external HTTP API.
Enter:
* `Method`: `POST`
* `URL`: `https://crazyrouter.com/v1/chat/completions`
Enter:
```text theme={null}
Authorization: Bearer sk-xxx
Content-Type: application/json
```
For the first test, use:
```json theme={null}
{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "{{input}}"
}
]
}
```
If your plugin UI supports parameter mapping, map user input into a placeholder such as `{{input}}`.
If your version supports plugin debugging, send:
```text theme={null}
Reply only OK
```
Make sure the API returns successfully before attaching the plugin to a bot or workflow.
After the plugin passes standalone testing, attach it to:
* a bot plugin capability
* or a workflow node
For the first rollout, keep the task simple, such as summarization, rewrite, or a fixed Q\&A step.
## Option 2: Connect Crazyrouter Through A Workflow HTTP Request Node
If you do not want to maintain a separate plugin, you can call Crazyrouter directly from a workflow HTTP request node.
### Recommended configuration
* Request method: `POST`
* URL: `https://crazyrouter.com/v1/chat/completions`
* Headers:
* `Authorization: Bearer sk-xxx`
* `Content-Type: application/json`
* Body:
```json theme={null}
{
"model": "gpt-5.4",
"messages": [
{
"role": "user",
"content": "{{input}}"
}
]
}
```
### Recommended validation order
1. Send a fixed string such as `Reply only OK`
2. Replace the fixed string with a variable input
3. Map the result into downstream nodes only after the HTTP node is stable
## How To Think About "Custom Model Integration"
Some Coze versions or plans may support custom-model integration, but that should not be the default public Crazyrouter guide.
Reasons:
* Coze's own plan FAQ currently lists `custom model` as an enterprise flagship capability
* For most ordinary users, the most reproducible and lowest-friction route is still HTTP / API plugins
* This page therefore treats custom-model support as background context, not as the default public setup path
## Recommended Models
| Use case | Recommended model | Why |
| --------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------- |
| First connection test | `gpt-5.4` | Verified successfully in production on March 23, 2026, and best for validating the Coze-to-Crazyrouter path |
| Higher-quality output | `claude-sonnet-4-6` | Better for stronger explanation and content generation |
| Gemini fallback path | `gemini-3-pro` | Useful as a second compatibility-validation path |
## Token Best Practices
| Setting | Recommendation | Why |
| --------------------- | -------------------- | ----------------------------------------------------------------- |
| Dedicated token | Required | Do not share a Coze token with desktop apps or IDE tools |
| Model allowlist | Strongly recommended | Start with only one or two models |
| Spending limit | Strongly recommended | Workflow loops and retries can multiply usage |
| Environment isolation | Recommended | Use separate tokens for dev / test / production |
| Leak handling | Rotate immediately | Replace the key if it appears in screenshots or shared workspaces |
## Validation Checklist
* [ ] Created a dedicated Crazyrouter token for Coze
* [ ] Chosen the HTTP / API plugin route or workflow HTTP request route first
* [ ] Set the request URL to `https://crazyrouter.com/v1/chat/completions`
* [ ] Filled the `Authorization` header as `Bearer sk-xxx`
* [ ] Set `Content-Type` to `application/json`
* [ ] Validated the smallest request body with `gpt-5.4`
* [ ] Confirmed the plugin or HTTP node works in standalone debugging
* [ ] Confirmed it still works after attaching to the bot or workflow
* [ ] Confirmed the request appears in Crazyrouter logs
## Common Errors And Fixes
| Symptom | Common cause | Fix |
| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| 401 unauthorized | Token is wrong, expired, or copied incompletely | Generate a new token and re-enter the `Authorization` header |
| 404 | URL is wrong or missing `/v1/chat/completions` | Change it to the full URL |
| 403 / model not allowed | The token does not allow that model | Allow the model in Crazyrouter token settings |
| `model not found` | Model name is wrong | Switch back to `gpt-5.4` and revalidate |
| Plugin can be created but fails inside the bot | Input / output mapping is inconsistent | Fall back to a fixed-string test first |
| Workflow node fails intermittently | Input is too large, retries are too aggressive, or concurrency is too high | Shrink the input and return to a minimal test |
| You cannot find a "model management" custom-upstream entry from another tutorial | Your version or plan is different | Go back to the HTTP / API plugin route instead of relying on enterprise-only capabilities |
## FAQ
### What is the best Coze-to-Crazyrouter route?
In public docs, prefer the HTTP / API plugin route or the workflow HTTP request node route.
### Why is "custom model integration" not the main path here?
Because Coze capabilities vary a lot by version and plan, and Coze's plan FAQ also places `custom model` under enterprise flagship capabilities. Public docs should lead with the most reproducible lower-threshold HTTP path.
### What URL should I enter?
Use `https://crazyrouter.com/v1/chat/completions`.
### What should the first model be?
Start with `gpt-5.4`.
### When should I add Claude or more models?
Only after the single-model, single-node, single-task path is already stable.
If your goal is "make Coze call Crazyrouter reliably first", the most important thing is not choosing the fanciest integration path. It is getting the smallest HTTP / API flow working end to end.
# Cursor Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/cursor
Connect Crazyrouter to Cursor and understand the usable scope, limitations, and troubleshooting for BYOK mode
Cursor is a practical way to bring Crazyrouter into your day-to-day coding workflow for chat, code explanation, refactoring suggestions, and general editing help.
## Overview
With Cursor's BYOK (Bring Your Own Key) flow, you can route part of your chat-model traffic through Crazyrouter and pay against your own token instead of bundling everything into Cursor usage.
* recommended path: OpenAI-compatible mode
* Crazyrouter base URL: `https://crazyrouter.com/v1`
* auth format: `sk-...` token
* best first-use features: Chat, Ask, and normal editing conversations
According to Cursor's official documentation, custom API keys only work with standard chat models. Features that depend on specialized models, such as Tab Completion, continue using Cursor's built-in models. That limitation comes from Cursor, not from Crazyrouter.
## Best For
* developers who want to use Crazyrouter tokens inside Cursor
* teams that want better control over model choice, cost, and quota
* users who want Cursor chat routed through Crazyrouter
* setups where IDE, CLI, and automation tokens should be tracked separately
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
When connecting Cursor to Crazyrouter, use this OpenAI-compatible base URL:
```text theme={null}
https://crazyrouter.com/v1
```
Do not use:
* `https://crazyrouter.com`
* `https://crazyrouter.com/v1/chat/completions`
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------------ |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for Cursor |
| Cursor desktop app | Update to a current stable version before setup |
| Allowed models | Make sure the token allows at least 1 to 2 OpenAI-compatible chat models |
Recommended starter allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
If you also plan to configure Claude Code, Codex, or Cline, do not share the same token with Cursor. Separate tokens make quota control and debugging much easier.
## Quick Start
In Crazyrouter, create a new token and name it something obvious like `cursor`. Start with a small allowlist such as `gpt-5.4` and `claude-sonnet-4-6`.
Open Cursor and go to `Cursor Settings` → `Models`.
In the OpenAI-related section, enter:
* `OpenAI API Key`: your `sk-...`
* `Override OpenAI Base URL`: `https://crazyrouter.com/v1`
If your Cursor build does not show `Override OpenAI Base URL`, your current version does not fully expose the custom OpenAI-compatible endpoint path yet. In that case, upgrade Cursor first or wait for improved support on the Cursor side.
Click `Verify`. After it succeeds, enable one model for the first validation. `gpt-5.4` is the safest starting point.
Open the chat panel and send a simple request such as `Reply with only OK`. If that succeeds, Crazyrouter is connected.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ------------------------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------ |
| default baseline | `gpt-5.4` | verified successfully in production on March 23, 2026, and stable for the main Cursor OpenAI-compatible path |
| high-quality code and long-form work | `claude-sonnet-4-6` | stronger for complex explanation, summaries, and code assistance |
| Gemini fallback path | `gemini-3-pro` | useful as a second compatibility-validation path |
Recommended rollout order: get `gpt-5.4` working first, then test `claude-sonnet-4-6` and `gemini-3-pro`.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| --------------- | -------------------- | ------------------------------------------------------------------------------------------ |
| dedicated token | Required | Do not share one token across Cursor and other tools |
| model allowlist | Recommended | Keep only the models Cursor should actually use |
| IP restriction | Situational | Usually avoid it on laptops with changing egress IPs; consider it on fixed office networks |
| quota cap | Strongly recommended | Give Cursor its own budget |
| env separation | Recommended | Use separate tokens for personal machines, team workstations, and CI |
| rotation | Recommended | If screenshots, recordings, or sync accidentally expose the token, rotate it quickly |
## Verification Checklist
* [ ] `Verify` succeeds in `Cursor Settings` → `Models`
* [ ] `Override OpenAI Base URL` is set to `https://crazyrouter.com/v1`
* [ ] at least one Crazyrouter-backed model is selected
* [ ] the first chat request succeeds
* [ ] the matching request appears in Crazyrouter logs
* [ ] token quota and model allowlist match your intended setup
* [ ] you understand that Tab Completion and similar features may still bypass Crazyrouter
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ------------------------------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `Verify` fails | wrong API key or wrong base URL | re-check the `sk-...` key and `https://crazyrouter.com/v1` |
| `401 unauthorized` | invalid, expired, or badly pasted token | generate a new token and paste the raw value again |
| `403` or `model not allowed` | the model is not in the token allowlist | allow that model in Crazyrouter token settings |
| `404` | base URL was set to the root domain or a full endpoint path | use exactly `https://crazyrouter.com/v1` |
| no models show up or the list looks wrong | Cursor BYOK refresh failed or the current version has compatibility issues | restart Cursor, verify again, and update to the latest stable build if needed |
| chat works but Tab Completion does not use Crazyrouter | Cursor officially keeps specialized features on built-in models | expected behavior, not a Crazyrouter outage |
| custom models do not behave correctly | Cursor's custom OpenAI-compatible endpoint support is still inconsistent | get `gpt-5.4` working first, then test other models gradually |
| cost jumps unexpectedly | one token is shared across too many tools or the allowlist is too wide | narrow the model set and give Cursor its own quota cap |
## Performance And Cost Tips
* start with only `gpt-5.4`
* use `gpt-5.4` for the baseline coding and chat workflow
* add `claude-sonnet-4-6` or `gemini-3-pro` only after the baseline path is stable
* split Cursor, Claude Code, and Codex traffic across different tokens
* if usage looks suspiciously high, inspect Crazyrouter logs and check whether long multi-turn context is driving costs
## FAQ
### Which base URL should I enter in Cursor?
Use `https://crazyrouter.com/v1`.
### Why do some Cursor features still not go through Crazyrouter?
Because Cursor officially limits custom API keys to standard chat models. Specialized features such as Tab Completion continue using Cursor-managed models.
### Which model should I use first?
Start with `gpt-5.4`. It is the latest OpenAI-compatible baseline already verified in production.
### Can I use Claude or other non-OpenAI models directly?
You can try them, but first complete a clean OpenAI-compatible baseline setup. Whether a custom model works cleanly in your current Cursor version depends on Cursor's compatibility implementation.
### Chat works, but model selection keeps getting weird. What should I do?
Restart Cursor, verify again, and fall back to `gpt-5.4` as the known-good baseline before expanding the config.
If your main goal is a stable coding workflow through Crazyrouter, Claude Code, Codex, and Cline are often more direct and controllable than Cursor's custom endpoint path. Cursor is best treated as a chat-first and general editing integration.
# Dify Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/dify
Connect Crazyrouter to Dify for chat models, embeddings, and workflows, then finish provider setup, first-run validation, and troubleshooting
Dify is a strong fit for workflows, agents, knowledge bases, and internal AI application platforms. When connecting it to Crazyrouter, the recommended rollout is to start with the OpenAI-compatible provider path, get one chat model working first, and only then add embeddings or other model types.
## Overview
Using Dify's model provider configuration, you can add Crazyrouter as an OpenAI-compatible upstream:
* Recommended protocol: `OpenAI-compatible API`
* Recommended entry point: `Settings` → `Model Provider`
* Base URL: `https://crazyrouter.com/v1`
* Auth method: `sk-...` token
* Recommended first validation model: `gpt-5.4`
Depending on your Dify version or plugin-based distribution, the provider may appear as `OpenAI`, `OpenAI-API-compatible`, `OpenAI Compatible`, or something similar. Pick the OpenAI-compatible provider that lets you set a custom `API Base URL`.
Official Dify docs treat a custom `API Base URL` as an optional field for proxy or compatible-upstream scenarios. For Crazyrouter, that is exactly the intended pattern, so use `https://crazyrouter.com/v1` as the OpenAI-compatible upstream. Also, model-provider configuration is usually limited to workspace admins or owners; if you cannot see the entry, check your role first.
## Best For
* teams building workflows, agents, or knowledge-base apps
* orgs that want chat and embedding models on the same upstream
* internal AI platforms with visual orchestration
* environments that need clean dev, staging, and production separation
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
When connecting Crazyrouter in Dify, the usual OpenAI-compatible base URL is:
```text theme={null}
https://crazyrouter.com/v1
```
Do not enter:
* `https://crazyrouter.com`
* `https://crazyrouter.com/v1/chat/completions`
The exact UI label can move between `Model Provider`, `Providers`, localized labels, or plugin-related entry points across Dify versions. Keep the first-pass validation flow unchanged: save the provider first, add only one `LLM` model `gpt-5.4`, and validate with a minimal Chat app before adding anything else.
## Prerequisites
| Item | Details |
| ------------------- | ----------------------------------------------------------------- |
| Crazyrouter account | Register first at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for Dify |
| Dify | Use a current stable version; provider labels may vary by release |
| Available models | Allow at least one verified chat model such as `gpt-5.4` |
Recommended starting whitelist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `text-embedding-3-large`
* `text-embedding-3-small`
If you plan to use a knowledge base, prepare at least one chat model and one embedding model.
## 5-Minute Quick Start
In the Crazyrouter dashboard, create a token named `dify`. For the first pass, allow `gpt-5.4` and one embedding model such as `text-embedding-3-large`.
Log in with a workspace admin-capable account and go to `Settings` → `Model Provider`.
Choose the `OpenAI` or `OpenAI-compatible` provider entry and fill in:
* `API Key`: your `sk-...`
* `API Base URL`: `https://crazyrouter.com/v1`
For the first rollout, add a single LLM such as:
* `Model`: `gpt-5.4`
* `Type`: `LLM`
Then create a very simple Chat app or Workflow app for validation. Do not add chat, embeddings, rerank, and workflow tools all at once, or troubleshooting will get mixed together.
In the app, send `Reply only OK`. If it succeeds and appears in the Crazyrouter logs, the chat path is working. Add embeddings only after that.
## Embeddings and Knowledge Base Guidance
If you want to use Dify knowledge bases, RAG, or document retrieval, add an embedding model as the second step:
| Purpose | Recommended model | Notes |
| -------------------------- | ------------------------ | ------------------------------------------------- |
| Default embedding model | `text-embedding-3-large` | Strong quality for a first knowledge-base rollout |
| Lower-cost embedding model | `text-embedding-3-small` | Better for budget-sensitive indexing |
Recommended order:
1. validate the chat model
2. validate embeddings
3. then import documents and tune retrieval
That keeps troubleshooting much cleaner.
## Recommended Model Setup
| Use case | Recommended model | Why |
| -------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------- |
| Default workflow chat model | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the main Dify baseline |
| Higher-quality complex workflows | `claude-sonnet-4-6` | Better for complex explanations, summaries, and long text |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
| Default embedding model | `text-embedding-3-large` | More reliable knowledge-base quality |
| Lower-cost embedding model | `text-embedding-3-small` | Good for budget-sensitive indexing |
Recommended order: get the chat model working first, then add embeddings.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ------------------------- | --------------------------------------- | ------------------------------------------------------------------------ |
| Dedicated token | Required | Do not share it with chat frontends or CLI tools |
| Model whitelist | Strongly recommended | Allow only the models Dify workflows actually need |
| IP restriction | Recommended for fixed deployment egress | Use carefully in changing local-dev environments |
| Quota cap | Strongly recommended | Workflows, batches, and knowledge-base imports can consume a lot quickly |
| Environment separation | Required | Use different tokens for dev, staging, and production |
| Split chat and embeddings | Recommended | Helpful for cost tracking and rate limiting in high-volume setups |
## Verification Checklist
* [ ] Crazyrouter is saved in `Model Provider`
* [ ] `API Base URL` is set to `https://crazyrouter.com/v1`
* [ ] at least one LLM is configured successfully
* [ ] the first Dify app request succeeds
* [ ] the request appears in the Crazyrouter logs
* [ ] at least one embedding model is configured if you need knowledge-base features
* [ ] token quota and model whitelist match your rollout plan
* [ ] dev, staging, and production use separate tokens
## Common Errors and Fixes
| Symptom | Likely cause | Fix |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `Model Provider` is missing | your account is not a workspace admin or owner | switch to an account with the right role, or ask an admin to configure it |
| the provider area exists but there is no obvious OpenAI-compatible option | your version names it differently, exposes it as a plugin, or requires the provider to be enabled first | look for `OpenAI`, `OpenAI Compatible`, or `OpenAI-API-compatible`, and check plugin or version docs if needed |
| provider cannot be saved | wrong API key or wrong provider type without custom base URL support | switch to the OpenAI-compatible provider entry and re-enter the `sk-...` token |
| 401 unauthorized | token expired, was removed, or was copied incorrectly | generate a new token and replace it |
| 403 / model not allowed | Dify is trying to use a model that is not whitelisted | allow that model in Crazyrouter |
| 404 | `API Base URL` was entered as the root domain or a full endpoint path | change it to `https://crazyrouter.com/v1` |
| provider saves but the app still fails | wrong model name or bad app-level parameter choices | fall back to `gpt-5.4` for baseline validation |
| knowledge-base import fails | the chat path works but embeddings were not configured correctly | validate the embedding model separately, then retry import |
| workflow cost grows too quickly | batch runs, long context, or many apps share one token | split tokens, add quota caps, and narrow the whitelist |
| some advanced models behave inconsistently in Dify | model-level parameter compatibility differs across nodes | validate on `gpt-5.4` first, then swap in stronger models gradually |
## Performance and Cost Tips
* Keep `gpt-5.4` as the workflow baseline during initial validation
* For the first knowledge-base launch, import a small document set before indexing everything
* Track chat and embedding traffic separately so cost sources stay visible
* Set tighter quota caps for batch jobs, scheduled jobs, and internal test environments
* If usage spikes, check Crazyrouter logs first to see whether the cause is retries, imports, or multiple apps sharing one token
## FAQ
### Which Base URL should I use in Dify?
Use `https://crazyrouter.com/v1`.
### Why should I not use only the root domain here?
Because Dify's OpenAI-compatible provider usually expects the OpenAI-compatible base, not the root domain.
### Should I configure chat or embeddings first?
Configure chat first, confirm the app can answer, then add embeddings.
### Can I configure rerank models directly?
That depends on your Dify version and installed provider plugins. Get chat and embeddings working first, then decide whether you need rerank support.
### Why does this guide insist on starting with one chat model only?
Because Dify issues can come from the provider layer, model type, app configuration, or knowledge-base chain. Validating a single `gpt-5.4` chat app first makes isolation much easier.
### Should Dify use multiple tokens?
Yes. At minimum, separate dev and production. At higher volume, split chat and embeddings too.
Dify is best treated as an application and workflow platform, not just a chat frontend. That is why dedicated tokens, whitelist control, and per-environment quota strategy matter much more here.
# Gemini CLI Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/gemini-cli
Configure Gemini CLI for Crazyrouter using the auth and model settings verified by real requests
## Overview
Gemini CLI is Google's command-line AI assistant. By configuring Crazyrouter's Gemini-native endpoint, you can use Gemini models that have been verified with real requests in Crazyrouter production.
## Configuration
### Environment Variables
In the current Gemini CLI release, API-key mode still requires `GEMINI_API_KEY` to be present explicitly. For Crazyrouter's Gemini-native endpoint, set these three variables together:
```bash theme={null}
export GEMINI_API_KEY=sk-xxx
export GEMINI_MODEL=gemini-3-pro
export GOOGLE_GEMINI_BASE_URL=https://crazyrouter.com
```
PowerShell:
```powershell theme={null}
$env:GEMINI_API_KEY="sk-xxx"
$env:GEMINI_MODEL="gemini-3-pro"
$env:GOOGLE_GEMINI_BASE_URL="https://crazyrouter.com"
```
If you want this to persist across sessions, put the same values into `~/.gemini/.env` or your PowerShell profile.
### Configuration File
Edit `~/.gemini/settings.json`:
```json theme={null}
{
"security": {
"auth": {
"selectedType": "gemini-api-key"
}
},
"apiKey": "sk-xxx",
"baseUrl": "https://crazyrouter.com",
"model": {
"name": "gemini-3-pro"
}
}
```
Notes:
* Do not leave the auth mode as `oauth-personal`, or the CLI will continue trying Google sign-in.
* Do not write `model` as a plain string in current versions; use `model.name`.
* In some CLI paths, `settings.json` alone is not enough. Headless mode may still require the `GEMINI_API_KEY` environment variable.
### `~/.gemini/.env` Example
```bash theme={null}
GEMINI_API_KEY=sk-xxx
GEMINI_MODEL=gemini-3-pro
GOOGLE_GEMINI_BASE_URL=https://crazyrouter.com
```
### Launch
```bash theme={null}
gemini
```
## Recommended Model
| Model | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `gemini-3-pro` | Verified successfully with a real Gemini CLI request in Crazyrouter production on April 8, 2026, and recommended as the current baseline |
Crazyrouter supports both the Gemini native API format and the OpenAI-compatible format. Gemini CLI uses the Gemini-native format. The `gemini-3-pro` example above, the `gemini-api-key` auth mode, and `GOOGLE_GEMINI_BASE_URL=https://crazyrouter.com` have been validated with a real CLI request.
# GPT Academic Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/gpt-academic
Configure Crazyrouter API in GPT Academic and switch to currently verified latest models
## Overview
GPT Academic is aimed at paper polishing, translation, code explanation, and other academic workflows. When connecting it to Crazyrouter, keep its OpenAI URL redirect approach, but move the default model set to the latest options already verified in production.
## Configuration
### Edit Configuration File
Edit `config.py` or `config_private.py`:
```python theme={null}
API_KEY = "sk-xxx"
API_URL_REDIRECT = {
"https://api.openai.com/v1/chat/completions": "https://crazyrouter.com/v1/chat/completions"
}
# Or set directly
LLM_MODEL = "gpt-5.4"
AVAIL_LLM_MODELS = [
"gpt-5.4",
"claude-sonnet-4-6",
"gemini-3-pro"
]
```
### Environment Variables
```bash theme={null}
export API_KEY=sk-xxx
export API_URL_REDIRECT='{"https://api.openai.com/v1/chat/completions": "https://crazyrouter.com/v1/chat/completions"}'
export LLM_MODEL=gpt-5.4
```
### Docker Deployment
```yaml theme={null}
services:
gpt-academic:
image: ghcr.io/binary-husky/gpt_academic
ports:
- "22303:22303"
environment:
- API_KEY=sk-xxx
- LLM_MODEL=gpt-5.4
- API_URL_REDIRECT={"https://api.openai.com/v1/chat/completions": "https://crazyrouter.com/v1/chat/completions"}
```
## Recommended Models
| Scenario | Model | Description |
| --------------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
| First-pass academic workflow validation | `gpt-5.4` | Verified successfully in Crazyrouter production on March 23, 2026, and best for the OpenAI-compatible baseline |
| Higher-quality long-form summarization | `claude-sonnet-4-6` | Better for complex explanation, rewriting, and summaries |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
GPT Academic's URL redirect feature forwards OpenAI requests directly to Crazyrouter. Start by validating one minimal session with `gpt-5.4`, then expand the model list and plugin usage gradually.
# Immersive Translate Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/immersive-translate
Connect Crazyrouter to the Immersive Translate browser extension through the OpenAI service path, with custom API URL, model, rate, validation, and troubleshooting guidance
Immersive Translate is a strong browser extension for webpage translation, bilingual reading, text-selection translation, and document translation. For Crazyrouter, the most reliable route is the extension's officially supported `OpenAI` service path, using the `More Settings` section to enter a custom API address.
## Overview
With Immersive Translate's OpenAI service setup, you can send requests to Crazyrouter with:
* recommended protocol: `OpenAI-compatible API`
* service type: `OpenAI`
* API key: your `sk-...`
* custom API URL: `https://crazyrouter.com/v1/chat/completions`
* recommended first validation model: `gpt-5.4`
The most important difference between Immersive Translate and ChatBox is this: here you should usually start with the full endpoint path, not just the root domain.
## Why This Guide Uses The Full Endpoint Path
According to Immersive Translate's official OpenAI service docs, the extension supports customizing the OpenAI API address in `More Settings`. For Crazyrouter, the safer first-pass value is therefore:
```text theme={null}
https://crazyrouter.com/v1/chat/completions
```
Do not start by entering only the root domain such as `https://crazyrouter.com`, and do not stop at `/v1`. For Immersive Translate's OpenAI-style path, the safest first validation is the full `/v1/chat/completions` endpoint.
## Best For
* users who want high-quality AI webpage translation
* users who want Crazyrouter-based control over translation costs
* users who want separate budgets by browser or device
* users who prefer an OpenAI-compatible route for a browser translation extension
## Prerequisites
| Item | Notes |
| ----------------------------- | -------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated token for Immersive Translate |
| Browser | Chrome, Edge, Firefox, or another supported browser |
| Immersive Translate extension | Use a current stable release |
| Allowed models | Allow at least one translation-friendly model |
Suggested starter allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
## Install And Setup Path
### Chrome / Edge Path
1. install Immersive Translate from the extension store
2. open the extension settings
3. go to `Translation Services`
4. choose `OpenAI`
5. open `More Settings`
6. enter the Crazyrouter key and full custom API URL
### Firefox Path
1. install Immersive Translate from Firefox Add-ons
2. open the settings page
3. go to `Translation Services`
4. choose `OpenAI`
5. open `More Settings`
6. enter the Crazyrouter settings
## Detailed Setup
Install Immersive Translate from the official extension store for your browser.
For the first pass, allow only:
* `gpt-5.4`
* `claude-sonnet-4-6`
Do not start by allowing a wide model set in a translation scenario.
In the extension UI, go to:
* `Settings`
* `Translation Services`
* choose `OpenAI`
Fill in:
* `API Key`: your `sk-...`
* `Custom API URL`: `https://crazyrouter.com/v1/chat/completions`
* `Model`: start with `gpt-5.4`
If some fields are hidden by default, expand `More Settings` first.
Immersive Translate's official OpenAI docs explicitly warn about rate limits. On the first Crazyrouter validation, keep the request rate conservative, especially for long webpages or ebooks.
Safe starter pattern:
* keep requests-per-second low
* validate with a small page or selected text first
* only raise the rate after the setup is already stable
Recommended order:
1. translate a short selected paragraph
2. translate a short webpage
3. only then try full-page or longer-document translation
That makes it much easier to tell whether the issue is config-related or simply request-volume-related.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ----------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------- |
| first-pass minimal validation | `gpt-5.4` | verified successfully in production on March 23, 2026, and best for proving the OpenAI-compatible route works |
| higher-quality translation | `claude-sonnet-4-6` | better for long-form explanation, refinement, and more quality-sensitive content |
| Gemini fallback path | `gemini-3-pro` | useful as a second compatibility-validation path after the baseline is already stable |
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| --------------- | -------------------- | ---------------------------------------------------------------------------- |
| dedicated token | Required | do not share browser translation tokens with IDE or CLI tools |
| model allowlist | Strongly recommended | start with only 1 to 2 translation models |
| quota cap | Strongly recommended | full-page and ebook translation can spend much faster than normal chat |
| device split | Recommended | separate tokens by browser or machine if needed |
| leak response | Rotate immediately | recordings, screenshots, or browser sync leaks should trigger a key rotation |
## Verification Checklist
* [ ] the extension is installed correctly
* [ ] `OpenAI` is selected as the translation service
* [ ] `API Key` is entered correctly
* [ ] `Custom API URL` is `https://crazyrouter.com/v1/chat/completions`
* [ ] the first model is `gpt-5.4` or another allowed model
* [ ] a short selected paragraph translates successfully
* [ ] a short webpage translates successfully
* [ ] Crazyrouter logs show the matching request
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ---------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `404` | the API URL is missing `/chat/completions`, or only the root domain was entered | switch to the full `https://crazyrouter.com/v1/chat/completions` URL |
| `401 unauthorized` | wrong, expired, or incomplete API key | generate a new token and paste it again |
| `403` or `model not allowed` | the token does not allow the selected model | allow that model in Crazyrouter token settings |
| `429` or unstable behavior | the request rate is too high | lower the request rate and validate on smaller text first |
| long pages fail more often | concurrency or rate is too high | reduce scope first, then increase gradually |
| cost rises too fast | you started with full-page or full-document translation immediately | begin with `gpt-5.4` on a smaller scope first |
## Cost Tips
* default to `gpt-5.4`
* translate selected text first instead of full pages immediately
* sample long content first before translating all of it
* if you install the extension on multiple browsers, separate the tokens for cleaner cost tracking
## FAQ
### What API URL should I enter in Immersive Translate?
Use the full path: `https://crazyrouter.com/v1/chat/completions`.
### Why is this different from ChatBox, where the guide starts from the root domain?
Because Immersive Translate's official OpenAI custom-address path is better aligned with a full endpoint URL, which makes the first validation more reliable.
### Which model should I try first?
Start with `gpt-5.4`.
### Why not translate full pages or ebooks immediately?
Because that amplifies configuration mistakes, rate-limit issues, and cost at the same time. Small text first is the fastest debugging pattern.
If your goal is to manage browser AI translation cost through Crazyrouter, Immersive Translate is one of the most important browser-extension guides to keep detailed and accurate.
# LangChain Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/langchain
Connect Crazyrouter to LangChain in Python and JavaScript / TypeScript projects through the OpenAI-compatible path, with install, env-var, validation, RAG, and troubleshooting guidance
LangChain is one of the most common LLM application frameworks for chat flows, prompt chains, tool use, RAG, agent-style workflows, and application-level orchestration. For Crazyrouter, the most reliable route is LangChain's official OpenAI-compatible component stack.
## Overview
With LangChain's OpenAI components, you can send requests to Crazyrouter with:
* recommended protocol: `OpenAI-compatible API`
* base URL: `https://crazyrouter.com/v1`
* auth variable: `OPENAI_API_KEY`
* main Python package: `langchain-openai`
* main JavaScript / TypeScript package: `@langchain/openai`
If you are integrating Crazyrouter into real application code rather than just chatting in a desktop client, LangChain is often the most natural engineering path.
## Best For
* developers integrating Crazyrouter into Python or Node.js applications
* teams building prompt chains, RAG, tool calling, or workflow orchestration
* users who want an abstraction layer instead of manually writing raw HTTP requests
* projects that want to keep future model switching flexible
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
Core Crazyrouter settings:
```text theme={null}
OPENAI_API_KEY=sk-xxx
BASE_URL=https://crazyrouter.com/v1
```
In LangChain, that usually maps to:
* Python: `api_key` + `base_url`
* JavaScript / TypeScript: `apiKey` + `configuration.baseURL`
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------------------------------- |
| Crazyrouter account | Create one at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated token for your LangChain project |
| Python | Prefer `Python 3.10+` |
| Node.js | Prefer `Node.js 18+` |
| LangChain packages | `langchain-openai` for Python and `@langchain/openai` for JS / TS |
| Allowed models | Allow at least one chat model; if you use vector search, allow an embedding model too |
Suggested starter allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
* `text-embedding-3-large`
## Full Python Path
### Recommended Windows Path
```powershell theme={null}
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -U pip
pip install -U langchain-openai langchain-community
python --version
pip --version
```
If you want the FAISS example too:
```powershell theme={null}
pip install faiss-cpu
```
### Recommended macOS / Linux Path
```bash theme={null}
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
pip install -U langchain-openai langchain-community
python --version
pip --version
```
If you want the FAISS example too:
```bash theme={null}
pip install faiss-cpu
```
## Full JavaScript / TypeScript Path
### Windows PowerShell
```powershell theme={null}
npm init -y
npm install @langchain/openai @langchain/core
node -v
npm -v
```
### macOS / Linux
```bash theme={null}
npm init -y
npm install @langchain/openai @langchain/core
node -v
npm -v
```
## Detailed Setup
For the first pass, allow only:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `text-embedding-3-large`
Add more models only after the basic route is already stable.
```bash theme={null}
export OPENAI_API_KEY=sk-xxx
echo $OPENAI_API_KEY
```
```powershell theme={null}
$env:OPENAI_API_KEY = "sk-xxx"
echo $env:OPENAI_API_KEY
```
If you want a persistent setup:
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.bashrc
source ~/.bashrc
```
```bash theme={null}
echo 'export OPENAI_API_KEY=sk-xxx' >> ~/.zshrc
source ~/.zshrc
```
```powershell theme={null}
[System.Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-xxx", "User")
$env:OPENAI_API_KEY = "sk-xxx"
```
Create `test_langchain_chat.py`:
```python theme={null}
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
temperature=0,
)
response = llm.invoke("Reply only OK")
print(response.content)
```
Run:
```bash theme={null}
python test_langchain_chat.py
```
Once the route works, avoid hard-coding the key:
```python theme={null}
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5.4",
api_key=os.environ["OPENAI_API_KEY"],
base_url="https://crazyrouter.com/v1",
temperature=0,
)
```
Create `test-langchain-chat.mjs`:
```javascript theme={null}
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "gpt-5.4",
apiKey: process.env.OPENAI_API_KEY,
configuration: {
baseURL: "https://crazyrouter.com/v1",
},
temperature: 0,
});
const response = await llm.invoke("Reply only OK");
console.log(response.content);
```
Run:
```bash theme={null}
node test-langchain-chat.mjs
```
Recommended order:
1. single-turn chat first
2. prompt + parser second
3. embeddings third
4. RAG or agent flows last
## Python Examples
### Minimal Chat Example
```python theme={null}
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
temperature=0.7,
)
response = llm.invoke("What is LangChain?")
print(response.content)
```
### Embeddings Example
```python theme={null}
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(
model="text-embedding-3-large",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
)
vectors = embeddings.embed_documents(["Text one", "Text two"])
print(len(vectors), len(vectors[0]))
```
### Prompt Chain Example
```python theme={null}
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
)
prompt = ChatPromptTemplate.from_template("Explain {topic} in simple terms")
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "quantum computing"})
print(result)
```
### Minimal RAG Example
```python theme={null}
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
)
embeddings = OpenAIEmbeddings(
model="text-embedding-3-large",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
)
texts = [
"Crazyrouter supports multiple AI model protocols",
"Crazyrouter supports OpenAI-compatible routing",
]
vectorstore = FAISS.from_texts(texts, embeddings)
retriever = vectorstore.as_retriever()
prompt = ChatPromptTemplate.from_template(
"Answer the question based on the following context:\n{context}\n\nQuestion: {question}"
)
chain = {"context": retriever, "question": RunnablePassthrough()} | prompt | llm
result = chain.invoke("Which protocol is the best fit for LangChain on Crazyrouter?")
print(result.content)
```
## JavaScript / TypeScript Example
### Minimal Chat Example
```javascript theme={null}
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "gpt-5.4",
apiKey: process.env.OPENAI_API_KEY,
configuration: {
baseURL: "https://crazyrouter.com/v1",
},
temperature: 0,
});
const response = await llm.invoke("Hello");
console.log(response.content);
```
## Recommended Model Setup
| Use case | Recommended model | Why |
| ------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| first-pass validation | `gpt-5.4` | verified successfully in production on March 23, 2026, and best for proving that LangChain and Crazyrouter are connected |
| higher-quality long-form and complex chains | `claude-sonnet-4-6` | better for complex explanation, summaries, and heavier reasoning |
| Gemini fallback path | `gemini-3-pro` | useful as a second compatibility-validation path |
| vector retrieval | `text-embedding-3-large` | strong first embedding baseline |
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------- | -------------------- | ------------------------------------------------------------ |
| dedicated token | Required | do not share LangChain project tokens with desktop clients |
| model allowlist | Strongly recommended | start with only the chat model plus embedding model you need |
| quota cap | Strongly recommended | chains, RAG, and agents can multiply spend quickly |
| environment split | Recommended | separate dev, staging, and production |
| leak response | Rotate immediately | never commit the key to Git |
## Verification Checklist
* [ ] Python or Node.js runtime is ready
* [ ] `OPENAI_API_KEY` is set correctly
* [ ] `langchain-openai` or `@langchain/openai` is installed
* [ ] the chat model is set to `https://crazyrouter.com/v1` through `base_url` or `baseURL`
* [ ] the first `Reply only OK` request succeeds
* [ ] Crazyrouter logs show the matching request
* [ ] if embeddings are used, the embedding model is also allowed
* [ ] if RAG is used, it was first validated on a tiny dataset
## Common Errors And Fixes
| Symptom | Likely cause | Fix |
| ------------------------ | --------------------------------------------------------------- | ------------------------------------------------------ |
| `401 unauthorized` | wrong, expired, or badly pasted `OPENAI_API_KEY` | generate a new token and set it again |
| `404` | wrong `base_url` or missing `/v1` | use `https://crazyrouter.com/v1` |
| `model not found` | wrong model name or the token does not allow it | switch back to `gpt-5.4` and check the allowlist |
| embeddings fail | the embedding model was not allowed | add `text-embedding-3-large` to the token allowlist |
| RAG fails in many places | too many components were added at once | go back to single-turn chat, then rebuild step by step |
| spend rises too quickly | chains, retrieval, and multi-turn agent loops are stacking cost | reduce scope and separate budgets by environment |
## FAQ
### Which protocol should LangChain use with Crazyrouter?
Use the OpenAI-compatible route.
### What base URL should I set?
Use `https://crazyrouter.com/v1`.
### Which Python package should I use?
Prefer `langchain-openai`.
### Which JavaScript / TypeScript package should I use?
Prefer `@langchain/openai`.
### Why not jump straight into agents or large RAG pipelines?
Because once a LangChain flow becomes complex, debugging becomes much harder. Minimal chat first, then layer features gradually.
If you are integrating Crazyrouter into a real application codebase, LangChain is still one of the most important framework guides to keep detailed and accurate.
# LobeChat Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/lobechat
Connect Crazyrouter to LobeChat through the OpenAI-compatible path, then finish chat validation, self-host setup, model management, and troubleshooting
LobeChat works well as a self-hosted chat frontend, a personal multi-model workspace, or a shared team chat surface. When connecting it to Crazyrouter, the most reliable route is LobeChat's `OpenAI` path with the proxy URL pointed at Crazyrouter's OpenAI-compatible base.
## Overview
Using LobeChat's OpenAI settings, you can route chat traffic through Crazyrouter:
* Recommended protocol: `OpenAI-compatible API`
* Recommended route: the LobeChat `OpenAI` provider
* Base URL: `https://crazyrouter.com/v1`
* Auth method: `sk-...` token
* Recommended first validation model: `gpt-5.4`
If you self-host LobeChat, you can also preconfigure Crazyrouter as the default OpenAI upstream through environment variables.
## Best For
* teams or individuals who want a stable chat frontend
* self-hosted AI chat workspaces
* users who want conversation history with multiple model choices
* admins who want to ship a default model configuration to internal users
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
When connecting Crazyrouter in LobeChat, use this OpenAI-compatible base URL:
```text theme={null}
https://crazyrouter.com/v1
```
Do not enter:
* `https://crazyrouter.com`
* `https://crazyrouter.com/v1/chat/completions`
LobeChat documents `OPENAI_PROXY_URL` as the OpenAI API request base URL, and its common defaults and examples are `/v1`-style. The local `http://127.0.0.1:4000/api/status` payload also exposes an official example using `{address}/v1`. So for Crazyrouter, `https://crazyrouter.com/v1` is the correct first-pass setup. If your own reverse proxy already adds `/v1`, adjust that layer to avoid a duplicated suffix.
## Prerequisites
| Item | Details |
| ------------------- | -------------------------------------------------------------------------- |
| Crazyrouter account | Register first at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for LobeChat |
| LobeChat | Hosted or self-hosted is fine; use a current stable build |
| Available models | Allow at least one verified OpenAI-compatible chat model such as `gpt-5.4` |
Recommended starting whitelist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
If you also plan to connect Crazyrouter to Cursor, Codex, or Claude Code, keep LobeChat on its own token. It makes cost tracking much easier.
## 5-Minute Quick Start
In the Crazyrouter dashboard, create a token named `lobechat`. For the first rollout, allow only the models you actually need, such as `gpt-5.4` and `claude-sonnet-4-6`.
In LobeChat, open `Settings` → `Language Model` from the avatar menu or settings entry.
In the `OpenAI` configuration, enter:
* `API Key`: your `sk-...`
* `API Proxy URL`: `https://crazyrouter.com/v1`
Also enable the custom proxy URL option if your version exposes it.
Save the settings and choose `gpt-5.4` as the default model first. Do not start with a large model list.
Start a new conversation and send `Reply only OK`. If it returns successfully and appears in the Crazyrouter logs, the integration is working.
## Self-Hosted Quick Config
If you deploy LobeChat with Docker, you can preconfigure the default OpenAI path like this:
```yaml theme={null}
services:
lobechat:
image: lobehub/lobe-chat
ports:
- "3210:3210"
environment:
- OPENAI_API_KEY=sk-xxx
- OPENAI_PROXY_URL=https://crazyrouter.com/v1
- OPENAI_MODEL_LIST=gpt-5.4,claude-sonnet-4-6,gemini-3-pro
```
If you do not want end users to replace the key freely, combine this with the config controls your deployed LobeChat version supports for hosted defaults or restricted client-side customization.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ---------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------ |
| Default main chat model | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the main LobeChat baseline |
| Higher-quality writing / code help | `claude-sonnet-4-6` | Strong long-form writing and reasoning |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
Recommended order: get `gpt-5.4` working first, then expand to `claude-sonnet-4-6` and `gemini-3-pro`.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ---------------------- | ---------------------------------------- | ----------------------------------------------------------- |
| Dedicated token | Required | Do not share the same token with IDE or CLI tools |
| Model whitelist | Strongly recommended | Allow only the models the chat frontend should use |
| IP restriction | Recommended for fixed self-hosted egress | Use carefully on changing home or mobile networks |
| Quota cap | Strongly recommended | Team chat frontends can burn through a shared token quickly |
| Environment separation | Recommended | Use different tokens for staging and production |
| Default model control | Recommended | Keep premium models out of the default path unless needed |
## Verification Checklist
* [ ] `API Key` is saved correctly
* [ ] `API Proxy URL` is set to `https://crazyrouter.com/v1`
* [ ] the custom proxy URL option is enabled if required by your version
* [ ] the first model is selected successfully
* [ ] the first chat request succeeds
* [ ] streaming works normally
* [ ] the request appears in the Crazyrouter logs
* [ ] token quota and model whitelist match your plan
## Common Errors and Fixes
| Symptom | Likely cause | Fix |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| settings cannot be saved or validation fails | wrong API key or wrong proxy URL | recheck the `sk-...` value and `https://crazyrouter.com/v1` |
| 401 unauthorized | token expired, was removed, or is invalid | generate a new token and replace it |
| 403 / model not allowed | selected model is missing from the token whitelist | allow that model in Crazyrouter |
| 404 | proxy URL was entered as the root domain or a full endpoint path | change it to `https://crazyrouter.com/v1` |
| settings look correct but you still get 404s | your own gateway, reverse proxy, or deployment layer already appends `/v1` once | inspect the upstream chain and remove the duplicated suffix from one layer |
| model looks selectable but requests fail | LobeChat cached an old model list or the default model is not valid | switch back to `gpt-5.4`, refresh, and reselect |
| chat works but streaming is unstable | client-version or model compatibility issue | use `gpt-5.4` as the baseline and upgrade LobeChat |
| usage spikes when multiple users share the app | one shared token has no quota cap | set a quota cap for the team frontend or split tokens |
| users can still switch away from Crazyrouter after self-hosting | you only set defaults, not restrictions | add deployment-side controls or disable client customization where supported |
## Performance and Cost Tips
* Keep only `gpt-5.4` in the first rollout
* Use a cheaper default model for team chat only if you have separately validated that route in your own deployment
* If you also enable knowledge features, plugins, or long-context sessions, give LobeChat its own quota cap
* Separate staging and production tokens so internal testing does not affect real usage budgets
* If usage looks suspicious, check the Crazyrouter logs first for long sessions or multiple users sharing one token
## FAQ
### Which Base URL should I use in LobeChat?
Use `https://crazyrouter.com/v1`.
### Why should I not enter only the root domain here?
Because LobeChat's OpenAI proxy settings work best when you give it the OpenAI-compatible base directly, not just the root domain.
### What if my own reverse proxy already appends `/v1`?
Then do not add another `/v1` in the final URL you expose to LobeChat. Check the proxy chain first so you do not end up with a duplicated suffix.
### Which model should I test first?
Start with `gpt-5.4`.
### Can LobeChat use multiple models with Crazyrouter?
Yes, but it is better to validate one model first and expand after that.
### Should I hardcode the token in environment variables for self-hosting?
If you want tighter control over upstream routing and cost, yes. If you want each user to bring their own key, keep the client-side entry open.
If your goal is a stable chat frontend and a shared workspace, LobeChat is a strong choice. If your goal is agentic coding and automated edits, Cursor, Claude Code, Codex, and Cline should still take priority.
# n8n Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/n8n
Configure Crazyrouter in n8n with OpenAI credentials, AI Agent workflows, and an HTTP Request fallback, then finish validation and troubleshooting
n8n is a strong fit when you want to place LLM calls inside automation flows, agents, approval chains, and business-system integrations. When connecting it to Crazyrouter, the recommended rollout is to get one minimal workflow working with n8n's OpenAI credential path first, then decide whether you need the more flexible HTTP Request fallback.
## Overview
Using n8n's OpenAI credentials or AI nodes, you can route workflow model traffic through Crazyrouter:
* Recommended protocol: `OpenAI-compatible API`
* Recommended route: n8n `OpenAI API` credential + node-level `Base URL`
* Base URL: `https://crazyrouter.com/v1`
* Auth method: `sk-...` token
* Recommended first validation model: `gpt-5.4`
If a specific node does not expose the parameters or newer model features you need, fall back to the `HTTP Request` node and call Crazyrouter directly.
## Best For
* teams putting AI inside automation workflows
* users connecting forms, databases, approvals, webhooks, and LLMs
* builders using `AI Agent` nodes with tool orchestration
* internal automation stacks that need visual workflow control
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
When connecting Crazyrouter in n8n, use:
```text theme={null}
https://crazyrouter.com/v1
```
Do not enter:
* `https://crazyrouter.com`
* `https://crazyrouter.com/v1/chat/completions`
## Prerequisites
| Item | Details |
| ------------------- | ------------------------------------------------------------ |
| Crazyrouter account | Register first at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for n8n |
| n8n | Use a current stable version with AI nodes available |
| Available models | Allow at least one verified chat model such as `gpt-5.4` |
Recommended starting whitelist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
* `text-embedding-3-large` if you will use vector or retrieval-related flows
## 5-Minute Quick Start
In the Crazyrouter dashboard, create a token named `n8n`. For the first rollout, allow only `gpt-5.4` and `claude-sonnet-4-6`.
In n8n, go to `Settings` → `Credentials` → `Add Credential`, then choose `OpenAI API` or the equivalent OpenAI credential type in your version.
First fill in the credential:
* `API Key`: your `sk-...`
Then in the `OpenAI`, `OpenAI Chat Model`, or related AI node `Options`, set:
* `Base URL`: `https://crazyrouter.com/v1`
Create a workflow such as `Manual Trigger` → `OpenAI Chat Model` → `Output`, and set the model to `gpt-5.4`.
Send a simple input such as `Reply only OK` through the `OpenAI Chat Model` node and execute the workflow manually. Once it succeeds, add AI Agent or more complex logic later.
## Minimal Workflow Example
### OpenAI Chat Model node
```json theme={null}
{
"node": "OpenAI Chat Model",
"parameters": {
"model": "gpt-5.4",
"messages": [
{ "role": "user", "content": "{{ $json.input }}" }
]
}
}
```
### AI Agent workflow
Start with the simplest path:
1. `Manual Trigger`
2. `AI Agent`
3. `Output`
In the `AI Agent`, choose the Crazyrouter credential and attach only one simple tool for the first test. That keeps model issues separate from tool-chain issues.
## HTTP Request Fallback
Use the `HTTP Request` node if you need:
* newer parameters not yet exposed by n8n AI nodes
* tighter control over the request body
* easier debugging of headers, body, or streaming behavior
Example:
```http theme={null}
Method: POST
URL: https://crazyrouter.com/v1/chat/completions
Headers:
Authorization: Bearer sk-xxx
Content-Type: application/json
Body:
{
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "{{ $json.input }}"}
]
}
```
Recommended order: first validate with the native OpenAI credential and AI nodes; only switch to `HTTP Request` when node coverage is not enough.
Depending on the n8n version, `Base URL` may appear on the credential page or in the specific OpenAI / Chat Model node `Options`. Current official docs more clearly document node-level `Base URL` overrides, so for Crazyrouter the safest first setup is: put the API key in the credential, then set `Base URL` on the node.
## Recommended Model Setup
| Use case | Recommended model | Why |
| ---------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------- |
| Default workflow model | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the main n8n baseline |
| Higher-quality complex agent flows | `claude-sonnet-4-6` | Better for more complex explanation and long-form tasks |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
| Retrieval / vector-related flows | `text-embedding-3-large` | Good for later vector or search-enhanced pipelines |
Recommended order: get `gpt-5.4` working in a minimal flow, then expand to agents, tools, and batch jobs.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ---------------------- | ----------------------------------- | ----------------------------------------------------------------------------- |
| Dedicated token | Required | Do not share it with chat frontends, CLI tools, or SDK demos |
| Model whitelist | Strongly recommended | Allow only the models the workflows really need |
| IP restriction | Recommended for fixed server egress | Use carefully if local dev and cloud runs are mixed |
| Quota cap | Strongly recommended | Retries, loops, and bulk tasks can burn through budget quickly |
| Environment separation | Required | Use different tokens for dev, staging, and production |
| Node tiering | Recommended | Use cheaper models for high-volume jobs and stronger models only where needed |
## Verification Checklist
* [ ] the `OpenAI API` credential is saved successfully
* [ ] node-level `Base URL` is set to `https://crazyrouter.com/v1`
* [ ] the `OpenAI Chat Model` node executes successfully
* [ ] the first minimal workflow returns a valid response
* [ ] the `AI Agent` node works too if you need agent flows
* [ ] the request appears in the Crazyrouter logs
* [ ] token quota and model whitelist match your plan
* [ ] dev, staging, and production workflows use separate tokens
## Common Errors and Fixes
| Symptom | Likely cause | Fix |
| --------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| credential test fails | wrong API key, or `Base URL` was entered in the wrong place for your n8n version | recheck the `sk-...` value and confirm `Base URL` is set where your version actually supports it |
| 401 unauthorized | token expired, was deleted, or pasted with extra spaces | create a new token and replace it |
| 403 / model not allowed | the workflow uses a model that is not whitelisted | allow that model in Crazyrouter |
| 404 | `Base URL` was entered as the root domain or a full endpoint path | change it to `https://crazyrouter.com/v1` |
| workflow keeps retrying and cost grows fast | node retries, loops, or batch logic is misconfigured | limit retries, split flows, and add quota caps |
| AI Agent starts but tool use is unstable | the tool chain is too complex for first-pass validation | keep only one simple tool until the baseline works |
| native AI node is missing parameters you need | n8n's node wrapper does not expose that feature yet | switch that step to an `HTTP Request` node |
| batch jobs are slow or expensive | model choice or flow design is a poor fit for the task | move large-volume runs back to the smallest validated baseline first |
## Performance and Cost Tips
* Keep `gpt-5.4` as the default automation baseline during initial rollout
* Add stricter caps and alerts for looped, scheduled, or batch workflows
* Keep production and debugging flows on separate tokens
* Validate AI Agent flows with fewer tools and shorter chains before scaling up
* If cost spikes, check both Crazyrouter logs and n8n execution history to see whether retries or loops are the cause
## FAQ
### Which Base URL should I use in n8n?
Use `https://crazyrouter.com/v1`.
### Should I put `Base URL` in the credential or in the node?
Check the UI in your current n8n version. Current official docs more clearly mention node-level `Base URL` options; if your credential page also supports it, that can work too, but the safest first setup is credential for the API key and node for `Base URL`.
### Should I start with native AI nodes or `HTTP Request`?
Start with native OpenAI credentials and AI nodes. Use `HTTP Request` only when you need deeper control or unsupported parameters.
### Which model should I test first?
Start with `gpt-5.4`.
### Why did workflow costs suddenly increase?
Usually the cause is not a single request. It is more often loops, batches, retries, or many executions sharing one token.
### Does n8n really need multiple tokens?
Yes. At minimum, separate development from production. High-volume jobs should often get their own token too.
Once n8n is connected to Crazyrouter, the real challenge is not just making one request work. It is controlling retries, loops, batch execution, and quota boundaries across automation flows.
# NextChat Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/nextchat
Connect Crazyrouter to NextChat through the OpenAI-compatible path, then finish hosted or self-hosted setup, model list control, and troubleshooting
NextChat (formerly ChatGPT Next Web) is a good fit when you want a lightweight, fast, easy-to-deploy chat frontend. When connecting it to Crazyrouter, the recommended approach is to stay on NextChat's default OpenAI-compatible route and point the service URL at the Crazyrouter root domain.
## Overview
Using NextChat's OpenAI settings, you can route requests through Crazyrouter:
* Recommended protocol: `OpenAI-compatible API`
* Recommended route: the default NextChat OpenAI flow
* Base URL: `https://crazyrouter.com`
* Auth method: `sk-...` token
* Recommended first validation model: `gpt-5.4`
NextChat's official README documents `BASE_URL` as the OpenAI API request base URL and uses root-domain style examples. The local `http://127.0.0.1:4000/api/status` response also exposes a root-style `server_address`. So for Crazyrouter, the safest first-pass setup is `https://crazyrouter.com`; only switch to a more specific path if your customized build explicitly requires it.
## Best For
* users who want a lightweight chat frontend quickly
* personal or small-team web chat with Crazyrouter
* admins who want to ship default model and upstream settings through env vars
* users who want the simplest possible OpenAI-compatible first setup
## Protocol Used
Recommended protocol: `OpenAI-compatible API`
When connecting Crazyrouter in NextChat, start with:
```text theme={null}
https://crazyrouter.com
```
Do not start with:
* `https://crazyrouter.com/v1/chat/completions`
* `https://crazyrouter.com/v1/models`
If an older or customized NextChat build requires a more specific API host setting, adjust to that version after you validate the baseline setup with the root domain.
The exact entry point varies by deployment style: hosted usage often exposes a settings panel, while self-hosted usage often pushes the values through environment variables only. Regardless of the UI, keep first-pass validation minimal: `API Key` + root-domain `BASE_URL` + one model `gpt-5.4`.
## Prerequisites
| Item | Details |
| ------------------- | -------------------------------------------------------------------------- |
| Crazyrouter account | Register first at [crazyrouter.com](https://crazyrouter.com) |
| Crazyrouter token | Create a dedicated `sk-...` token for NextChat |
| NextChat | Hosted or self-hosted is fine; use a current stable version |
| Available models | Allow at least one verified OpenAI-compatible chat model such as `gpt-5.4` |
Recommended starting whitelist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## 5-Minute Quick Start
In the Crazyrouter dashboard, create a token named `nextchat`. For the first rollout, allow only baseline models such as `gpt-5.4` and `claude-sonnet-4-6`.
In NextChat, open the `Settings` panel from the bottom-left icon or settings entry.
In the OpenAI-related settings, enter:
* `API Key`: your `sk-...`
* `Base URL`: `https://crazyrouter.com`
In the `Model` field, manually enter or select `gpt-5.4`. If your version supports a custom model list, add more models later.
Start a new chat and send `Reply only OK`. Once it works, add more models gradually.
## Self-Hosted Quick Config
A common Docker setup looks like this:
```yaml theme={null}
services:
nextchat:
image: yidadaa/chatgpt-next-web
ports:
- "3000:3000"
environment:
- OPENAI_API_KEY=sk-xxx
- BASE_URL=https://crazyrouter.com
- CUSTOM_MODELS=+gpt-5.4,+claude-sonnet-4-6,+gemini-3-pro
- HIDE_USER_API_KEY=1
```
Common environment variables:
| Variable | Recommended value | Notes |
| ------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `OPENAI_API_KEY` | `sk-xxx` | default Crazyrouter token |
| `BASE_URL` | `https://crazyrouter.com` | use the root domain first, matching the official `BASE_URL` pattern for baseline validation |
| `CUSTOM_MODELS` | `+gpt-5.4,+claude-sonnet-4-6,+gemini-3-pro` | adds selectable models in the UI |
| `HIDE_USER_API_KEY` | `1` | prevents end users from entering their own key |
## Recommended Model Setup
| Use case | Recommended model | Why |
| ---------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------ |
| Default main chat model | `gpt-5.4` | Verified successfully in production on March 23, 2026, and suited for the main NextChat baseline |
| Higher-quality long-form and explanation | `claude-sonnet-4-6` | Better for longer text and more complex explanations |
| Gemini fallback path | `gemini-3-pro` | Useful as a second vendor-compatible validation path |
Recommended order: validate `gpt-5.4` first, then expand the list with `CUSTOM_MODELS`.
## Token Setup Best Practices
| Setting | Recommendation | Notes |
| ----------------------- | ---------------------------------------- | -------------------------------------------------------------- |
| Dedicated token | Required | Do not share it with LobeChat, Cursor, or Codex |
| Model whitelist | Strongly recommended | Allow only the models the frontend should expose |
| IP restriction | Consider it for fixed self-hosted egress | Use carefully on changing personal networks |
| Quota cap | Strongly recommended | Multi-user chat traffic can grow fast |
| Environment separation | Recommended | Use separate tokens for demo, staging, and production |
| User-supplied key entry | Disable by default | Set `HIDE_USER_API_KEY=1` if you want centralized cost control |
## Verification Checklist
* [ ] `API Key` is saved correctly
* [ ] `Base URL` is set to `https://crazyrouter.com`
* [ ] the first model is set to `gpt-5.4`
* [ ] the first chat request succeeds
* [ ] `CUSTOM_MODELS` works if you use self-hosted deployment
* [ ] streaming output works normally
* [ ] the request appears in the Crazyrouter logs
* [ ] token quota and model whitelist match your rollout plan
## Common Errors and Fixes
| Symptom | Likely cause | Fix |
| ----------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| 401 unauthorized | token is wrong, expired, or pasted with extra spaces | create a new token and replace it |
| 403 / model not allowed | the model is not in the token whitelist | allow that model in Crazyrouter |
| 404 | you entered a full endpoint path, or your version expects a different env var name | switch back to `https://crazyrouter.com` and check whether your build uses `BASE_URL` or another setting name |
| the self-hosted UI does not show these settings | your deployment style fixes them in environment variables instead of the frontend settings panel | inspect `OPENAI_API_KEY`, `BASE_URL`, and `CUSTOM_MODELS` in the deployment config directly |
| no models appear in the UI | `CUSTOM_MODELS` is missing or old config is cached | validate with a manual `gpt-5.4` entry first, then refresh and recheck env vars |
| request goes out but the model fails | default model name is wrong or unavailable | fall back to `gpt-5.4` for baseline testing |
| users can still switch to their own key | `HIDE_USER_API_KEY=1` was not set | add that variable in deployment config |
| usage grows too quickly | many users share one broad token | split tokens, reduce whitelist scope, and add quota caps |
## Performance and Cost Tips
* Default to exposing only `gpt-5.4` in the first rollout
* Keep premium models out of the default list until you actually need them
* On public or semi-public deployments, hide user-supplied key entry whenever possible
* Separate demo traffic from production traffic with different tokens
* If usage looks abnormal, check Crazyrouter logs first for long sessions or many users sharing one key
## FAQ
### Which URL should I use in NextChat?
Start with `https://crazyrouter.com`.
### Why does this guide not recommend `/v1` first?
Because the official NextChat docs show `BASE_URL` in a root-domain style, and the local `4000` environment also exposes a root-style `server_address`. That makes the root domain the safest first-pass setup.
### Which model should I test first?
Start with `gpt-5.4`.
### Do I have to configure `CUSTOM_MODELS`?
No. You can manually enter `gpt-5.4` first, validate the connection, and add a model list later.
### Why do some self-hosted deployments only let me change env vars, not UI settings?
Because different NextChat deployment modes expose configuration differently. Some self-hosted setups pin upstream routing, keys, and models in environment variables, and the frontend only consumes those values.
### Should I hide user-provided keys in self-hosted deployments?
Yes, if you want centralized upstream routing and predictable cost control.
If you want the lightest possible chat frontend with minimal deployment friction, NextChat is a strong fit. If you need richer collaboration or more advanced app-building features, LobeChat or Dify is usually the better next step.
# RikkaHub Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/rikkahub
Configure Crazyrouter API in RikkaHub
## Overview
RikkaHub is an AI model aggregation client that supports unified management of multiple model providers.
## Configuration Steps
Go to the RikkaHub settings page and find the `Model Services` or `API Configuration` option.
Click to add a new provider:
* **Type**: OpenAI Compatible
* **Name**: Crazyrouter
* **API Base URL**: `https://crazyrouter.com/v1`
* **API Key**: `sk-xxx`
After configuration, select the models you want to use from the model list.
## Available Models
After configuration, you can use all models supported by Crazyrouter, including:
* GPT-4o, GPT-4o-mini
* Claude Sonnet, Claude Opus
* Gemini Pro, Gemini Flash
* And 300+ other models
RikkaHub supports configuring multiple providers simultaneously, allowing flexible switching during conversations.
# Zotero Setup Guide
Source: https://docs.crazyrouter.com/en/integrations/zotero
Connect Crazyrouter to Zotero through AI plugins that support OpenAI-compatible endpoints, and clearly separate directly supported plugin types from ones that are not a good public default
Zotero itself is a reference manager, not a built-in Crazyrouter client. In practice, the integration path is usually: install a Zotero AI plugin first, and then enter Crazyrouter's OpenAI-compatible URL, API key, and model inside that plugin.
The most important rule for this page is not "any Zotero AI plugin will work". You should first separate plugins into two groups:
* directly usable: plugins that support a custom `Base API URL`, `API URL`, or `Endpoint`
* not a good public default: plugins that only accept an official OpenAI key and do not expose a custom upstream URL
## Start Here
The recommended public Crazyrouter path in Zotero is:
* choose a Zotero AI plugin that supports a custom OpenAI-compatible endpoint
* enter `https://crazyrouter.com/v1` as the base URL
* enter `sk-xxx` as the API key
* use `gpt-5.4` as the first validation model
Not every Zotero AI plugin supports a custom upstream URL. If a plugin only exposes an "OpenAI API Key" field and does not provide a `Base URL` or `API URL` setting, it usually cannot be redirected to Crazyrouter directly. That kind of plugin should not be the default public guide.
## Why This Guide Is Written This Way
Because the Zotero AI plugin ecosystem varies a lot:
* Zotero's own plugin documentation explains that plugins are community-built, with a common installation flow but different capabilities
* some plugins explicitly document a configurable `base API URL`
* other plugins publicly document only an `OpenAI API Key`
So the public Crazyrouter guide should teach users to choose a plugin that supports a custom OpenAI-compatible endpoint, rather than assuming every plugin can connect directly.
## Who This Guide Is For
* Users who want paper summarization, translation, and Q\&A inside Zotero
* Users who want literature reading and Crazyrouter model calls in one workflow
* Users who want AI help while reviewing items, reading PDFs, or organizing notes
* Users who prefer a GUI workflow instead of writing scripts
## Prerequisites
| Item | Notes |
| ------------------- | ------------------------------------------------------------ |
| Crazyrouter account | Register at [crazyrouter.com](https://crazyrouter.com) first |
| Crazyrouter token | Create a dedicated token for Zotero |
| Zotero desktop app | Plugins mainly run in the desktop app |
| AI plugin | It must support a custom OpenAI-compatible endpoint |
| Papers or PDFs | Prepare at least one test item |
Suggested first-pass allowlist:
* `gpt-5.4`
* `claude-sonnet-4-6`
* `gemini-3-pro`
## Install Zotero
### Windows
1. Open the [Zotero download page](https://www.zotero.org/download/)
2. Download the Windows installer
3. Run the installer
4. Launch Zotero
### macOS
1. Open the [Zotero download page](https://www.zotero.org/download/)
2. Download the macOS build
3. Move Zotero into `Applications`
4. Launch Zotero
### Linux
1. Open the [Zotero download page](https://www.zotero.org/download/)
2. Download the official Linux package
3. Extract it and launch Zotero following Zotero's official instructions
4. Confirm Zotero starts normally
According to Zotero's official documentation, plugins are mainly installed in the desktop app. These AI plugin flows are not a good first-pass setup route from mobile.
## How To Choose A Zotero AI Plugin
For public documentation, prefer plugins that provide:
* a `Base API URL`, `API URL`, or `Endpoint` field
* an `API Key` field
* a manual model field
* ideally a preferences panel inside Zotero
### A practical public rule
If a plugin's public docs mention capabilities like these, it is usually a better Crazyrouter candidate:
* `Customize base API URL`
* `API URL`
* `Custom endpoint`
* `Model preferences`
For example, the public README for `zotero-chatgpt` explicitly mentions a configurable `base API URL`; by contrast, the public README for `Aria` focuses on entering an `OpenAI API Key` and model preferences, and does not present a custom upstream URL as the main public path. So the safer Crazyrouter baseline is to choose a plugin that clearly supports a custom OpenAI-compatible endpoint.
## Recommended Configuration Shape
The exact field names vary by plugin, but for a first pass use this pattern:
| Plugin field | Recommended value |
| ---------------------- | --------------------------------------------- |
| Base API URL / API URL | `https://crazyrouter.com/v1` |
| Full Endpoint | `https://crazyrouter.com/v1/chat/completions` |
| API Key | `sk-xxx` |
| Model | `gpt-5.4` |
If the plugin asks for a "base URL", prefer `https://crazyrouter.com/v1`. Only use `https://crazyrouter.com/v1/chat/completions` when the plugin explicitly asks for the full chat endpoint.
## Configuration Steps
For the first pass, only allow:
* `gpt-5.4`
* `claude-sonnet-4-6`
Do not open a large model list on day one. A narrow scope is easier to debug.
Install Zotero for your platform and confirm that you can open at least one paper item or PDF normally.
Based on Zotero's official plugin installation documentation, download the plugin `.xpi` file first. Then in Zotero:
* open `Tools`
* open `Plugins`
* drag the `.xpi` file onto the Plugins window
Restart Zotero after installation.
Common entry points include:
* `Edit` → `Preferences`
* the plugin's own preferences page
* a plugin sidebar or toolbar entry
The exact location depends on the plugin, but the goal is always to find the API and model configuration area.
If the plugin supports a base-URL style configuration, enter:
* `Base API URL`: `https://crazyrouter.com/v1`
* `API Key`: `sk-xxx`
* `Model`: `gpt-5.4`
If the plugin supports only a full endpoint field, use:
* `Endpoint`: `https://crazyrouter.com/v1/chat/completions`
Some plugins need a Zotero restart after changes to the API key, model, or preference fields. After the first setup, a restart is a safe default.
Do not begin with a complicated literature review. For the first pass, only:
* select one item with an abstract
* or open one small PDF
* run one summarization, translation, or simple Q\&A action
A good first prompt is:
```text theme={null}
Summarize this paper in 3 bullet points.
```
## Recommended Validation Order
Move in this order:
1. Confirm Zotero and the plugin both open correctly
2. Validate `gpt-5.4` first
3. Test single-paper summarization
4. Test translation next
5. Only then try multi-paper comparison, long-form analysis, or batch tasks
## Recommended Models
| Scenario | Recommended model | Why |
| ----------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------- |
| First connection test | `gpt-5.4` | Verified successfully in production on March 23, 2026, and best for plugin-to-Crazyrouter validation |
| Deep analysis and explanation | `claude-sonnet-4-6` | Better for long explanations, comparison, and method-level interpretation |
| Gemini fallback path | `gemini-3-pro` | Useful as a second compatibility-validation path |
## Good Zotero Workflows For Crazyrouter
### Single-paper summarization
This is the best first validation because the context is small and the output is easy to judge.
### PDF translation
Start with one page or one short passage before expanding the scope.
### Multi-paper comparison
Do not use this as the first test. Try it only after single-paper summarization and translation are already stable.
### Note generation
If the plugin can write results back into Zotero notes, begin with short summaries first instead of generating long notes in bulk.
## Token Best Practices
| Setting | Recommendation | Why |
| ------------------- | -------------------- | ------------------------------------------------------------------ |
| Dedicated token | Required | Do not share it with IDEs or automation |
| Model allowlist | Strongly recommended | Start with only one or two models |
| Spending limit | Strongly recommended | Long PDFs and repeated summaries can amplify usage |
| Use-case separation | Recommended | Separate personal academic usage from team-shared usage |
| Leak response | Rotate immediately | Replace the key if it appears in demos, recordings, or screenshots |
## Validation Checklist
* [ ] Zotero desktop is installed
* [ ] An AI plugin with a custom OpenAI-compatible endpoint is installed
* [ ] A dedicated Crazyrouter token was created for Zotero
* [ ] The base URL or full endpoint was entered correctly
* [ ] `sk-xxx` was entered correctly
* [ ] `gpt-5.4` was used as the first model
* [ ] Zotero was restarted if the plugin requires it
* [ ] A single-paper summarization or translation test succeeded
* [ ] The request appears in Crazyrouter logs
## Common Errors And Fixes
| Symptom | Common cause | Fix |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| The plugin only has an OpenAI key field and no Base URL | The plugin does not support a custom upstream | Switch to a plugin that supports a custom `Base API URL` or `Endpoint` |
| 401 unauthorized | Token is wrong, incomplete, or expired | Generate a new token and enter it again |
| 404 | The base URL or full endpoint is wrong | Reset it to `https://crazyrouter.com/v1` or `https://crazyrouter.com/v1/chat/completions` |
| 403 / model not allowed | The token does not allow that model | Allow the model in Crazyrouter token settings |
| `model not found` | The model name is wrong | Switch back to `gpt-5.4` and do a minimal validation |
| The plugin shows no response or ignores new settings | The plugin needs a Zotero restart | Restart Zotero and try again |
| Summarization fails without a clear API error | The item has no abstract, the PDF is missing, or the plugin did not receive enough context | Switch to an item with an abstract or an attached PDF |
| Long-document jobs are very slow | The PDF is too long or the task is too heavy | Reduce the scope to one paragraph, one page, or one paper |
## FAQ
### Can Zotero itself connect to Crazyrouter directly?
Usually not through Zotero alone. The common route is to configure Crazyrouter inside an AI plugin that supports OpenAI-compatible endpoints.
### What kind of plugin is best for Crazyrouter?
Prefer plugins that support a custom `Base API URL`, `API URL`, or `Endpoint`.
### What if the plugin only accepts an OpenAI API Key?
That plugin usually cannot be redirected to Crazyrouter directly, so it is not a good public default. It is better to switch to a plugin with custom endpoint support.
### What base URL should I enter?
Prefer `https://crazyrouter.com/v1`.
### What should the first model be?
Start with `gpt-5.4`.
### When should I try multi-paper analysis or complex review prompts?
Only after single-paper summarization and single-paper translation are already stable.
If your goal is "make Zotero work with Crazyrouter first", the key is not choosing the fanciest plugin. It is confirming that your plugin truly supports a custom OpenAI-compatible endpoint, and then validating a single-paper summary with `gpt-5.4`.
# Callback Protocol
Source: https://docs.crazyrouter.com/en/reference/callback
Webhook callback protocol for async tasks
## Overview
For async tasks (Midjourney image generation, video generation, music generation, etc.), Crazyrouter supports Webhook callbacks to notify task status changes.
## Callback URL Configuration
Specify the callback URL via the `notifyHook` parameter when submitting a task:
```json theme={null}
{
"prompt": "a beautiful sunset",
"notifyHook": "https://your-server.com/api/callback"
}
```
## Callback Request Format
Crazyrouter sends a POST request to your callback URL:
```
POST https://your-server.com/api/callback
Content-Type: application/json
```
### Midjourney Callback
```json theme={null}
{
"id": "task_abc123",
"action": "IMAGINE",
"status": "SUCCESS",
"prompt": "a beautiful sunset",
"imageUrl": "https://cdn.example.com/image.png",
"progress": "100%",
"failReason": "",
"submitTime": 1706000000000,
"startTime": 1706000010000,
"finishTime": 1706000060000
}
```
### Video Generation Callback (Kling/Luma/Runway)
```json theme={null}
{
"id": "task_xyz789",
"status": "succeed",
"type": "video",
"output": {
"video_url": "https://cdn.example.com/video.mp4",
"cover_url": "https://cdn.example.com/cover.jpg",
"duration": 5.0
},
"created_at": 1706000000,
"updated_at": 1706000120
}
```
### Suno Music Callback
```json theme={null}
{
"id": "task_music456",
"status": "complete",
"output": {
"audio_url": "https://cdn.example.com/song.mp3",
"title": "My Song",
"duration": 180
}
}
```
## Callback Status Flow
```
Submitted → NOT_START → IN_PROGRESS → SUCCESS / FAILURE
```
A callback is triggered on each status change.
## Callback Server Examples
```python Python (Flask) theme={null}
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route("/api/callback", methods=["POST"])
def callback():
data = request.json
task_id = data["id"]
status = data["status"]
print(f"Task {task_id} status update: {status}")
if status == "SUCCESS":
image_url = data.get("imageUrl")
print(f"Image URL: {image_url}")
return jsonify({"success": True})
app.run(port=8080)
```
```javascript Node.js (Express) theme={null}
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/callback', (req, res) => {
const { id, status, imageUrl } = req.body;
console.log(`Task ${id} status: ${status}`);
if (status === 'SUCCESS') {
console.log(`Image: ${imageUrl}`);
}
res.json({ success: true });
});
app.listen(8080);
```
The callback URL must be publicly accessible. Ensure your server can receive POST requests and return a 200 status code within 5 seconds.
If a callback fails, the system retries up to 3 times with intervals of 10 seconds, 30 seconds, and 60 seconds.
# Status Codes
Source: https://docs.crazyrouter.com/en/reference/status-codes
Status code reference for all API types
## HTTP Status Codes
| Status Code | Description | Recommended Action |
| ----------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| 200 | Request successful | - |
| 400 | Bad request parameters | Check request body format and parameters |
| 401 | Authentication failed | Check if API Key is correct |
| 403 | Insufficient permissions | Check if the token has access to the requested model |
| 404 | Resource not found | Check URL path |
| 429 | Rate limit exceeded | Reduce request frequency or contact admin |
| 500 | Server-side 5xx error | Safe to retry; may be an internal CrazyRouter error or an upstream 5xx relayed through CrazyRouter |
| 502 | Gateway or upstream result retrieval failure | Usually means CrazyRouter reached the upstream stage but could not obtain a valid upstream response or result; safe to retry |
| 503 | Service unavailable | System maintenance in progress |
## Difference Between 500 and 502
* `500` is broader. In CrazyRouter, it can mean either an internal server error on our side or an upstream `5xx` that was returned through our relay.
* `502` is more specific. It usually means the request reached the gateway or upstream step, but CrazyRouter could not get a valid upstream response or fetch the upstream result, for example because the upstream was unavailable, returned an invalid gateway-level response, or the result URL could not be retrieved.
* If the same issue keeps happening:
* frequent `502` errors usually point to upstream availability, connectivity, or result URL retrieval issues;
* frequent `500` errors need log-based classification, and only cases explicitly marked as site-internal or panic-type should be treated as a CrazyRouter-side defect.
## Chat Completions Error Codes
```json theme={null}
{
"error": {
"message": "Error description",
"type": "error_type",
"code": "error_code"
}
}
```
| code | Description |
| ------------------------- | ---------------------------------------- |
| `invalid_api_key` | API Key is invalid or expired |
| `insufficient_quota` | Insufficient balance |
| `model_not_found` | Model does not exist or is not enabled |
| `context_length_exceeded` | Input exceeds model context length limit |
| `rate_limit_exceeded` | Rate limit exceeded |
| `content_filter` | Content blocked by safety filter |
## Midjourney Task Status Codes
| Status | Description |
| ------------- | --------------------- |
| `NOT_START` | Task not started |
| `SUBMITTED` | Submitted |
| `IN_PROGRESS` | Generating |
| `SUCCESS` | Generation successful |
| `FAILURE` | Generation failed |
| `CANCEL` | Cancelled |
### MJ Error Codes
| code | Description |
| ---- | --------------------- |
| 1 | Submission successful |
| 21 | Task already exists |
| 22 | Queued |
| 23 | Queue full |
| 24 | Submission failed |
## Kling Video Status Codes
| Status | Description |
| ------------ | ----------------------------- |
| `queued` | Submitted or waiting in queue |
| `processing` | Processing |
| `succeeded` | Generation successful |
| `failed` | Generation failed |
## Jimeng Task Status Codes
| Status | Description |
| ------------ | ----------------------------- |
| `queued` | Submitted or waiting in queue |
| `processing` | Processing |
| `succeeded` | Generation successful |
| `failed` | Generation failed |
## Luma Video Status Codes
| Status | Description |
| ------------ | ----------- |
| `pending` | Pending |
| `processing` | Processing |
| `completed` | Completed |
| `failed` | Failed |
## Suno Music Status Codes
| Status | Description |
| ------------ | ----------- |
| `submitted` | Submitted |
| `processing` | Generating |
| `complete` | Completed |
| `error` | Error |
## Runway Video Status Codes
| Status | Description |
| ----------- | ----------- |
| `PENDING` | Pending |
| `RUNNING` | Generating |
| `SUCCEEDED` | Succeeded |
| `FAILED` | Failed |
## General Error Handling Recommendations
When encountering a 429 error, do not retry immediately. Use an exponential backoff strategy, starting with a 1-second wait and doubling each time.
```python theme={null}
import time
import requests
def request_with_retry(url, headers, json_data, max_retries=3):
for i in range(max_retries):
response = requests.post(url, headers=headers, json=json_data)
if response.status_code == 429:
wait = 2 ** i
print(f"Rate limited, waiting {wait} seconds before retrying...")
time.sleep(wait)
continue
return response
return response
```
# AI Thinking Fields
Source: https://docs.crazyrouter.com/en/reference/thinking
Production-revalidated guide to the thinking and reasoning fields exposed by different Crazyrouter protocols
# AI Thinking Fields
This page only lists thinking and reasoning surfaces that were revalidated against Crazyrouter production on `2026-03-22`.
The key point is that different protocols expose "thinking" differently:
* OpenAI Responses returns a standalone `reasoning` item
* Claude native Messages returns a `thinking` block
* Gemini Native is most reliably observed through `usageMetadata.thoughtsTokenCount`
## Currently verified fields
| Model | Protocol | Verified field or marker | Notes |
| ----------------- | ------------------ | ---------------------------------- | ------------------------------------------------------------ |
| `gpt-5.4` | Responses | `output[].type = "reasoning"` | Can return displayable summaries when `summary` is requested |
| `claude-opus-4-7` | Anthropic Messages | `content[].type = "thinking"` | Returned alongside a `text` block |
| `gemini-3-pro` | Gemini Native | `usageMetadata.thoughtsTokenCount` | Confirms thinking tokens were actually used |
In the current recheck, `gpt-5.4` Chat Completions did not reliably return usable `message.reasoning_content`, so it is not treated as the primary observable field here.
***
## GPT: Responses `reasoning` item
```json theme={null}
{
"output": [
{
"id": "rs_xxx",
"type": "reasoning",
"encrypted_content": "...",
"summary": [
{
"type": "summary_text",
"text": "..."
}
]
},
{
"type": "message",
"content": [
{
"type": "output_text",
"text": "Final answer"
}
]
}
]
}
```
Extraction example:
```python theme={null}
response = client.responses.create(
model="gpt-5.4",
input="Which is larger, 9.11 or 9.9?",
reasoning={"effort": "high", "summary": "detailed"}
)
for item in response.output:
if item.type == "reasoning":
for part in item.summary:
if part.type == "summary_text":
print("Thinking summary:", part.text)
```
***
## Claude: `thinking` block
```json theme={null}
{
"content": [
{
"type": "thinking",
"thinking": "..."
},
{
"type": "text",
"text": "Final answer"
}
]
}
```
Extraction example:
```python theme={null}
message = client.messages.create(
model="claude-opus-4-7",
max_tokens=320,
thinking={
"type": "enabled",
"budget_tokens": 128
},
messages=[
{"role": "user", "content": "Which is larger, 9.11 or 9.9?"}
]
)
for block in message.content:
if block.type == "thinking":
print("Thinking:", block.thinking)
elif block.type == "text":
print("Answer:", block.text)
```
***
## Gemini: `thoughtsTokenCount`
In the current production recheck, the most reliable observable signal was not a visible reasoning paragraph in the body, but a usage field:
```json theme={null}
{
"usageMetadata": {
"thoughtsTokenCount": 120
}
}
```
This indicates that:
* the thinking budget was actually used
* the request consumed thinking tokens during generation
Extraction example:
```python theme={null}
data = response.json()
thoughts = data.get("usageMetadata", {}).get("thoughtsTokenCount", 0)
print("Thinking tokens:", thoughts)
```
***
## Usage notes
* Do not assume every model returns raw chain-of-thought text
* Do not mix thinking fields across protocols
* For logging, auditing, or UI display, decide per protocol whether to read `reasoning`, `thinking`, or `thoughtsTokenCount`
Related pages:
* [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
* [Claude Native Messages](/en/chat/anthropic/messages)
* [Gemini Native API](/en/chat/gemini/native)
# Getting Started
Source: https://docs.crazyrouter.com/en/reference/tutorial
Production-revalidated starter paths for connecting to Crazyrouter from OpenAI, Anthropic, and Gemini
# Getting Started
This page only documents starter paths that were revalidated against Crazyrouter production on `2026-03-23`.
For the fastest start, separate the integration styles first:
* OpenAI-compatible: `https://crazyrouter.com/v1`
* Anthropic native: `https://crazyrouter.com`
* Gemini native: `https://crazyrouter.com/v1beta/models/...`
## Shortest migration rule
When migrating from an OpenAI-compatible client, you usually only change two things:
1. set `base_url` to `https://crazyrouter.com/v1`
2. replace the key with your Crazyrouter `sk-xxx`
***
## Migrating from OpenAI
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=64
)
```
This production recheck confirmed that:
* `gpt-5.4` works through `/v1/chat/completions`
* if you need reasoning summaries or OpenAI-style web search, you should prefer `/v1/responses`
Related pages:
* [Responses API Overview](/en/chat/responses/overview)
* [GPT-5 Thinking Mode](/en/chat/responses/gpt5-thinking)
***
## Migrating from Anthropic
### Option A: stay on the OpenAI-compatible layer
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=64
)
```
### Option B: use native Anthropic Messages
```python theme={null}
import anthropic
client = anthropic.Anthropic(
api_key="sk-xxx",
base_url="https://crazyrouter.com"
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=128,
messages=[{"role": "user", "content": "Hello"}]
)
```
If you need:
* standard Claude chat: prefer `claude-sonnet-4-6`
* an explicit thinking block: prefer `claude-opus-4-7`
Related page:
* [Claude Native Format](/en/chat/anthropic/messages)
***
## Migrating from Gemini
### Option A: OpenAI-compatible layer
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="gemini-3-pro",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=64
)
```
### Option B: Gemini native
```bash theme={null}
curl "https://crazyrouter.com/v1beta/models/gemini-3-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{
"role": "user",
"parts": [
{"text": "Hello"}
]
}
]
}'
```
If you need:
* simple reuse of existing OpenAI SDK code: start with the compatibility layer
* structured outputs, Google Search, or thinking: prefer Gemini native
Related pages:
* [Gemini OpenAI-Compatible Format](/en/chat/gemini/openai-compat)
* [Gemini Native Format](/en/chat/gemini/native)
***
## Environment variables
If you use the OpenAI-compatible route, a good default is:
```bash theme={null}
export OPENAI_API_KEY=sk-xxx
export OPENAI_BASE_URL=https://crazyrouter.com/v1
```
```powershell theme={null}
$env:OPENAI_API_KEY = "sk-xxx"
$env:OPENAI_BASE_URL = "https://crazyrouter.com/v1"
```
Then your code can be:
```python theme={null}
from openai import OpenAI
client = OpenAI()
```
***
## Starter recommendations
| Goal | Recommended starting path |
| ----------------------------------------------------- | --------------------------------------------------- |
| Fastest GPT integration | OpenAI-compatible + `gpt-5.4` |
| Fastest Claude integration | Anthropic native + `claude-sonnet-4-6` |
| Fastest Gemini integration | OpenAI-compatible or Gemini native + `gemini-3-pro` |
| Need reasoning summaries | Responses API |
| Need a Claude thinking block | `claude-opus-4-7` |
| Need Gemini Google Search / thinking / responseSchema | Gemini native |
Crazyrouter supports OpenAI, Anthropic, and Gemini protocols at the same time. In practice, the more reliable approach is usually not forcing every model through one protocol, but choosing the route that best matches the capability you need.
# Node.js Basic Chat
Source: https://docs.crazyrouter.com/en/sdks/nodejs
Node.js integration with Crazyrouter using the openai package
## Installation
```bash theme={null}
npm install openai
```
## Basic Chat
```javascript theme={null}
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'sk-xxx',
baseURL: 'https://crazyrouter.com/v1',
});
async function main() {
const response = await client.chat.completions.create({
model: 'gpt-5.4',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'Explain what Node.js is in one sentence' },
],
});
console.log(response.choices[0].message.content);
}
main();
```
## Streaming Output
```javascript theme={null}
async function streamChat() {
const stream = await client.chat.completions.create({
model: 'gpt-5.4',
messages: [{ role: 'user', content: 'Write a poem about programming' }],
stream: true,
});
for await (const chunk of stream) {
const content = chunk.choices[0]?.delta?.content || '';
process.stdout.write(content);
}
console.log();
}
streamChat();
```
## Multi-turn Conversation
```javascript theme={null}
const messages = [
{ role: 'system', content: 'You are a JavaScript expert.' },
];
async function chat(userInput) {
messages.push({ role: 'user', content: userInput });
const response = await client.chat.completions.create({
model: 'gpt-5.4',
messages,
});
const reply = response.choices[0].message.content;
messages.push({ role: 'assistant', content: reply });
return reply;
}
async function main() {
console.log(await chat('What is a Promise?'));
console.log(await chat('How is it different from async/await?'));
}
main();
```
## CommonJS Usage
```javascript theme={null}
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: 'sk-xxx',
baseURL: 'https://crazyrouter.com/v1',
});
client.chat.completions
.create({
model: 'gpt-5.4',
messages: [{ role: 'user', content: 'Hello' }],
})
.then((res) => console.log(res.choices[0].message.content));
```
These examples default to `gpt-5.4`, which was verified successfully in Crazyrouter production on March 23, 2026. If you need to swap models, prefer other verified options such as `claude-sonnet-4-6` or `gemini-3-pro`.
# PHP Examples
Source: https://docs.crazyrouter.com/en/sdks/php
PHP Crazyrouter API examples
## Basic Chat
```php theme={null}
'gpt-5.4',
'messages' => [
['role' => 'user', 'content' => 'Hello, write a bubble sort in PHP']
]
];
$ch = curl_init($baseUrl . '/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo $result['choices'][0]['message']['content'];
```
## Image Editing
```php theme={null}
'gpt-image-2',
'image' => new CURLFile('original.png', 'image/png'),
'prompt' => 'Change the background to a starry sky',
];
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_POSTFIELDS => $postFields,
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
// gpt-image-2 usually returns data[0].url; do not send response_format=b64_json
$imageUrl = $result['data'][0]['url'] ?? null;
echo "Image URL: " . $imageUrl . "\n";
```
## Streaming Output
```php theme={null}
'gpt-5.4',
'messages' => [['role' => 'user', 'content' => 'Tell me a joke']],
'stream' => true,
];
$ch = curl_init($baseUrl . '/chat/completions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey,
],
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_WRITEFUNCTION => function ($ch, $data) {
$lines = explode("\n", $data);
foreach ($lines as $line) {
if (str_starts_with($line, 'data: ') && $line !== 'data: [DONE]') {
$json = json_decode(substr($line, 6), true);
$content = $json['choices'][0]['delta']['content'] ?? '';
echo $content;
}
}
return strlen($data);
},
]);
curl_exec($ch);
curl_close($ch);
echo "\n";
```
The chat examples above default to `gpt-5.4`, which was verified successfully in Crazyrouter production on March 23, 2026. If you switch models, prefer other verified options such as `claude-sonnet-4-6` or `gemini-3-pro`.
# Python Basic Chat
Source: https://docs.crazyrouter.com/en/sdks/python/basic
Python basic chat, multi-turn conversation, and streaming output
## Install Dependencies
```bash theme={null}
pip install openai requests
```
## Basic Chat
```python OpenAI SDK theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
response = client.chat.completions.create(
model="gpt-5.4",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain artificial intelligence in one sentence"}
]
)
print(response.choices[0].message.content)
```
```python requests theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/chat/completions",
headers={
"Authorization": "Bearer sk-xxx",
"Content-Type": "application/json"
},
json={
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "Explain artificial intelligence in one sentence"}
]
}
)
data = response.json()
print(data["choices"][0]["message"]["content"])
```
## Multi-turn Conversation
Maintain a `messages` list to implement multi-turn dialogue:
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
messages = [
{"role": "system", "content": "You are a Python programming assistant."}
]
def chat(user_input):
messages.append({"role": "user", "content": user_input})
response = client.chat.completions.create(
model="gpt-5.4",
messages=messages
)
reply = response.choices[0].message.content
messages.append({"role": "assistant", "content": reply})
return reply
# Multi-turn dialogue
print(chat("How do I read a CSV file?"))
print(chat("What if the file is very large?"))
print(chat("Can I use pandas for this?"))
```
## Streaming Output
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Write a poem about programming"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
print()
```
## Streaming with requests
```python theme={null}
import requests
import json
response = requests.post(
"https://crazyrouter.com/v1/chat/completions",
headers={
"Authorization": "Bearer sk-xxx",
"Content-Type": "application/json"
},
json={
"model": "gpt-5.4",
"messages": [{"role": "user", "content": "Hello"}],
"stream": True
},
stream=True
)
for line in response.iter_lines():
if line:
line = line.decode("utf-8")
if line.startswith("data: ") and line != "data: [DONE]":
data = json.loads(line[6:])
content = data["choices"][0]["delta"].get("content", "")
print(content, end="", flush=True)
print()
```
All examples default to `gpt-5.4`, which was verified successfully in Crazyrouter production on March 23, 2026. If you need to swap models, prefer other verified options such as `claude-sonnet-4-6` or `gemini-3-pro`.
# Python Embeddings
Source: https://docs.crazyrouter.com/en/sdks/python/embeddings
Python text embedding API usage
## Basic Usage
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
response = client.embeddings.create(
model="text-embedding-3-large",
input="Crazyrouter is an AI model gateway"
)
embedding = response.data[0].embedding
print(f"Dimensions: {len(embedding)}")
```
## Batch Embeddings
```python theme={null}
texts = [
"The history of artificial intelligence",
"Differences between machine learning and deep learning",
"Applications of natural language processing"
]
response = client.embeddings.create(
model="text-embedding-3-large",
input=texts
)
for i, item in enumerate(response.data):
print(f"Text {i}: dimensions {len(item.embedding)}")
```
## Custom Dimensions
The `text-embedding-3-*` series supports custom output dimensions:
```python theme={null}
response = client.embeddings.create(
model="text-embedding-3-large",
input="Test text",
dimensions=256 # Reduce to 256 dimensions
)
print(f"Dimensions: {len(response.data[0].embedding)}") # 256
```
## Compute Similarity
```python theme={null}
import numpy as np
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
response = client.embeddings.create(
model="text-embedding-3-large",
input=["Cats are pets", "Dogs are also common pets", "Quantum mechanics is a branch of physics"]
)
vectors = [item.embedding for item in response.data]
print(f"Cat vs Dog: {cosine_similarity(vectors[0], vectors[1]):.4f}")
print(f"Cat vs Quantum mechanics: {cosine_similarity(vectors[0], vectors[2]):.4f}")
```
Reducing dimensions can lower storage and computation costs but may sacrifice some accuracy. Test with your specific use case to find the right dimension.
# Python Function Calling
Source: https://docs.crazyrouter.com/en/sdks/python/function-calling
Complete Python Function Calling example
## Overview
Function Calling allows models to call functions you define, enabling interaction with external systems. The model does not execute functions directly -- it returns the function name and arguments, and your code executes them and returns the results to the model.
## Complete Example
```python theme={null}
import json
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
# 1. Define tools
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather information for a specified city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name, e.g.: New York"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["city"]
}
}
},
{
"type": "function",
"function": {
"name": "search_products",
"description": "Search for products",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search keyword"},
"max_price": {"type": "number", "description": "Maximum price"}
},
"required": ["query"]
}
}
}
]
# 2. Mock function implementations
def get_weather(city, unit="celsius"):
return {"city": city, "temperature": 22, "unit": unit, "condition": "Sunny"}
def search_products(query, max_price=None):
return [{"name": f"{query} Product A", "price": 99}, {"name": f"{query} Product B", "price": 199}]
# 3. Conversation loop
messages = [{"role": "user", "content": "What's the weather like in New York today? Also search for umbrellas"}]
response = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
tools=tools,
tool_choice="auto"
)
message = response.choices[0].message
# 4. Handle tool calls
if message.tool_calls:
messages.append(message)
for tool_call in message.tool_calls:
func_name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
if func_name == "get_weather":
result = get_weather(**args)
elif func_name == "search_products":
result = search_products(**args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False)
})
# 5. Get final response
final = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
tools=tools
)
print(final.choices[0].message.content)
```
## Force a Specific Function Call
```python theme={null}
response = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
tools=tools,
tool_choice={"type": "function", "function": {"name": "get_weather"}}
)
```
## Supported Models
For the OpenAI-compatible Function Calling examples in this page, use the following verified baseline first:
* `gpt-5.4`
Tool calling with `gpt-5.4` was verified in Crazyrouter production on March 23, 2026. For other vendors, check their dedicated pages first because request formats and support details can differ.
# Python Image Generation
Source: https://docs.crazyrouter.com/en/sdks/python/images
Python image generation and editing with DALL-E and GPT-Image-2
## DALL-E 3 Image Generation
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://cn.crazyrouter.com/v1")
response = client.images.generate(
model="dall-e-3",
prompt="A cat wearing a spacesuit walking on the moon, digital art style",
size="1024x1024",
quality="hd",
n=1
)
image_url = response.data[0].url
print(f"Image URL: {image_url}")
```
### DALL-E Parameters
| Parameter | Options | Description |
| --------- | ------------------------------------- | ---------------- |
| `size` | `1024x1024`, `1792x1024`, `1024x1792` | Image dimensions |
| `quality` | `standard`, `hd` | Image quality |
| `style` | `vivid`, `natural` | Style |
## GPT-Image-2 Image Generation
```python theme={null}
response = client.images.generate(
model="gpt-image-2",
prompt="A modern minimalist logo with an artificial intelligence theme",
size="1024x1024",
quality="low",
output_format="png",
n=1
)
print(response.data[0].url)
```
## GPT-Image-2 Image Editing
```python theme={null}
# Image editing (requires original image)
response = client.images.edit(
model="gpt-image-2",
image=open("original.png", "rb"),
prompt="Change the background to a beach sunset",
size="1024x1024",
quality="low"
)
print(response.data[0].url)
```
## Download and Save Images
```python theme={null}
import requests
response = client.images.generate(
model="dall-e-3",
prompt="Cyberpunk city nightscape",
size="1792x1024"
)
# Download image
image_url = response.data[0].url
img_data = requests.get(image_url).content
with open("cyberpunk_city.png", "wb") as f:
f.write(img_data)
print("Image saved")
```
`gpt-image-2` usually returns `data[0].url`. Do not send `response_format` with `gpt-image-2`; use `output_format="png"`, `"jpeg"`, or `"webp"` to choose the image file format. For production image requests, use the primary route `https://cn.crazyrouter.com/v1`.
Image generation costs are relatively high. Test your prompt with smaller sizes first, then generate high-quality large images once satisfied.
# Python OpenAI SDK
Source: https://docs.crazyrouter.com/en/sdks/python/openai-sdk
Connect to Crazyrouter using the OpenAI SDK, LangChain, and LlamaIndex
## OpenAI Official SDK
```bash theme={null}
pip install openai
```
```python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
# Synchronous call
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}],
temperature=0.7,
max_tokens=1000
)
print(response.choices[0].message.content)
```
### Async Call
```python theme={null}
from openai import AsyncOpenAI
import asyncio
client = AsyncOpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
async def main():
response = await client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Hello"}]
)
print(response.choices[0].message.content)
asyncio.run(main())
```
## LangChain Integration
```bash theme={null}
pip install langchain-openai
```
```python theme={null}
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1",
temperature=0.7
)
# Simple call
response = llm.invoke("Write a quicksort in Python")
print(response.content)
```
### LangChain Chain
```python theme={null}
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(
model="gpt-5.4",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a {role}."),
("user", "{input}")
])
chain = prompt | llm
response = chain.invoke({"role": "Python expert", "input": "Explain decorators"})
print(response.content)
```
### LangChain Embeddings
```python theme={null}
from langchain_openai import OpenAIEmbeddings
embeddings = OpenAIEmbeddings(
model="text-embedding-3-large",
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
vectors = embeddings.embed_documents(["Text one", "Text two"])
print(f"Vector dimensions: {len(vectors[0])}")
```
## LlamaIndex Integration
```bash theme={null}
pip install llama-index-llms-openai llama-index-embeddings-openai
```
```python theme={null}
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
# LLM configuration
llm = OpenAI(
model="gpt-5.4",
api_key="sk-xxx",
api_base="https://crazyrouter.com/v1"
)
response = llm.complete("What is RAG?")
print(response.text)
# Embedding configuration
embed_model = OpenAIEmbedding(
model="text-embedding-3-large",
api_key="sk-xxx",
api_base="https://crazyrouter.com/v1"
)
vector = embed_model.get_text_embedding("Test text")
print(f"Dimensions: {len(vector)}")
```
The chat examples above default to `gpt-5.4`, which was verified successfully in Crazyrouter production on March 23, 2026. If you replace the model, prefer other verified options such as `claude-sonnet-4-6`; the embedding examples should continue using `text-embedding-3-large`.
# Python Audio
Source: https://docs.crazyrouter.com/en/sdks/python/tts-stt
Python text-to-speech (TTS) and speech-to-text (STT)
## Text-to-Speech (TTS)
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
# Generate speech
response = client.audio.speech.create(
model="tts-1",
voice="alloy",
input="Hello, welcome to the Crazyrouter API service."
)
# Save as MP3 file
response.stream_to_file("output.mp3")
print("Audio saved to output.mp3")
```
### Available Voices
| Voice | Characteristics |
| --------- | ----------------- |
| `alloy` | Neutral, balanced |
| `echo` | Male, calm |
| `fable` | Male, warm |
| `onyx` | Male, deep |
| `nova` | Female, lively |
| `shimmer` | Female, soft |
### High Quality TTS
```python theme={null}
# Use tts-1-hd for higher audio quality
response = client.audio.speech.create(
model="tts-1-hd-1106",
voice="nova",
input="High quality speech synthesis example",
response_format="opus", # Supports mp3, opus, aac, flac
speed=1.0 # 0.25 to 4.0
)
response.stream_to_file("output_hd.opus")
```
## Speech-to-Text (STT)
```python theme={null}
# Whisper speech recognition
audio_file = open("recording.mp3", "rb")
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
language="en" # Optional, specifying language improves accuracy
)
print(transcript.text)
```
### Transcription with Timestamps
```python theme={null}
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=open("recording.mp3", "rb"),
response_format="verbose_json",
timestamp_granularities=["segment"]
)
for segment in transcript.segments:
print(f"[{segment['start']:.1f}s - {segment['end']:.1f}s] {segment['text']}")
```
## Audio Translation
Translate non-English audio to English text:
```python theme={null}
audio_file = open("foreign_audio.mp3", "rb")
translation = client.audio.translations.create(
model="whisper-1",
file=audio_file
)
print(translation.text) # English output
```
TTS supported models include `tts-1`, `tts-1-hd-1106`, and `tts-1`. STT uses the `whisper-1` model.
# Python Vision
Source: https://docs.crazyrouter.com/en/sdks/python/vision
Python image recognition with gpt-5.4 and Claude
## gpt-5.4 Vision - URL Method
```python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe the content of this image"},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/photo.jpg"
}
}
]
}]
)
print(response.choices[0].message.content)
```
## gpt-5.4 Vision - Local Image
```python theme={null}
import base64
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
# Read local image and convert to base64
with open("photo.jpg", "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_data}"
}
}
]
}]
)
print(response.choices[0].message.content)
```
## Multi-Image Comparison
```python theme={null}
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Compare the differences between these two images"},
{"type": "image_url", "image_url": {"url": "https://example.com/img1.jpg"}},
{"type": "image_url", "image_url": {"url": "https://example.com/img2.jpg"}}
]
}]
)
print(response.choices[0].message.content)
```
## Claude Vision
Claude models also support vision through the OpenAI-compatible format:
```python theme={null}
response = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image in detail"},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_data}"
}
}
]
}],
max_tokens=1024
)
print(response.choices[0].message.content)
```
## Supported Vision Models
| Model | Description |
| ------------------- | ------------------------------------------------------------------------------------ |
| `gpt-5.4` | OpenAI-compatible vision model verified successfully in production on March 23, 2026 |
| `claude-sonnet-4-6` | Claude OpenAI-compatible vision model verified successfully in production |
Vision input with `gpt-5.4` and `claude-sonnet-4-6` was verified in Crazyrouter production on March 23, 2026. Image size should not exceed 20MB; base64 encoding adds approximately 33% to the payload size, so URL method is recommended for larger files.
# Create Token
Source: https://docs.crazyrouter.com/en/token-management/create
POST /api/token/
Create a new API token
## Overview
Create a new API token for calling AI model APIs.
The `/api/token/*` endpoints are mainly for Crazyrouter dashboard automation around API key management. They require a user `access token` plus the `New-Api-User` header, and are not the normal interface for `sk-xxx` model calls.
## Authentication
This endpoint requires user-side authentication:
```text theme={null}
Authorization: Bearer your_access_token
New-Api-User: 1
```
## Request Parameters
Token name for easy identification
Initial quota in internal quota units. If set to 0, use it together with `unlimited_quota`
Whether the token has unlimited quota
Expiration timestamp. `-1` means never expires
Whether to enable a model whitelist
Model restriction config as a string, usually a JSON string such as `["gpt-5.4","claude-sonnet-4-6"]`
IP whitelist string. You can pass a single IP or multiple IPs separated by newlines
Token group. It must be a group the current user is allowed to use
## Response Format
The current implementation only returns a success state after creation:
```json theme={null}
{
"success": true,
"message": ""
}
```
## Code Examples
```python Python theme={null}
import json
import requests
headers = {
"Authorization": "Bearer your_access_token",
"New-Api-User": "1",
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0"
}
response = requests.post(
"https://crazyrouter.com/api/token/",
headers=headers,
json={
"name": "Production",
"remain_quota": 100000,
"unlimited_quota": False,
"expired_time": -1,
"model_limits_enabled": True,
"model_limits": json.dumps(["gpt-5.4", "claude-sonnet-4-6"]),
"allow_ips": "203.0.113.10"
}
)
print(response.json())
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/api/token/ \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 1" \
-H "Content-Type: application/json" \
-d '{
"name": "Production",
"remain_quota": 100000,
"expired_time": -1,
"model_limits_enabled": true,
"model_limits": "[\"gpt-5.4\"]"
}'
```
The current create endpoint does not return the full generated `key` in the response. If your workflow requires copying the full token immediately, prefer creating it from the console UI and saving it there.
# Delete Token
Source: https://docs.crazyrouter.com/en/token-management/delete
DELETE /api/token/{id}
Delete a specified API token
## Overview
Permanently delete a specified API token. The token's API Key will be invalidated immediately after deletion.
The `/api/token/*` endpoints are mainly for Crazyrouter dashboard automation around API key management. They require a user `access token` plus the `New-Api-User` header, and are not the normal interface for `sk-xxx` model calls.
## Authentication
Use user-side authentication with these headers:
```text theme={null}
Authorization: Bearer your_access_token
New-Api-User: 1
```
## Path Parameters
ID of the token to delete
## Response Format
```json theme={null}
{
"success": true,
"message": "Token deleted successfully"
}
```
## Code Examples
```python Python theme={null}
import requests
headers = {
"Authorization": "Bearer your_access_token",
"New-Api-User": "1",
"User-Agent": "Mozilla/5.0"
}
token_id = 10
response = requests.delete(
f"https://crazyrouter.com/api/token/{token_id}",
headers=headers
)
print(response.json())
```
```bash cURL theme={null}
curl -X DELETE https://crazyrouter.com/api/token/10 \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 1"
```
This operation is irreversible. All applications using this Key will immediately lose API access.
# List Tokens
Source: https://docs.crazyrouter.com/en/token-management/list
GET /api/token/
Get a paginated list of API tokens for the current user
## Overview
Retrieve all API tokens created by the current user, with pagination support.
The `/api/token/*` endpoints are mainly for Crazyrouter dashboard automation around API key management. They require a user `access token` plus the `New-Api-User` header, and are not the normal interface for `sk-xxx` model calls.
## Authentication
Authenticate using the user's access token with the following headers:
```text theme={null}
Authorization: Bearer {access_token}
New-Api-User: {user_id}
```
## Request Parameters
Page number. The backend accepts older styles too, but `1` is the recommended starting page
Items per page, maximum 100
## Response Format
```json theme={null}
{
"success": true,
"message": "",
"data": {
"page": 1,
"page_size": 10,
"total": 1,
"items": [
{
"id": 1,
"user_id": 1,
"key": "sk-xxxxxxxxxxxxxxxx",
"status": 1,
"name": "My Token",
"created_time": 1706000000,
"accessed_time": 1706100000,
"expired_time": -1,
"remain_quota": 500000,
"unlimited_quota": false,
"model_limits_enabled": true,
"model_limits": "[\"gpt-5.4\",\"claude-sonnet-4-6\"]",
"allow_ips": "203.0.113.10",
"used_quota": 12345,
"group": "default"
}
]
}
}
```
## Field Descriptions
| Field | Type | Description |
| ---------------------- | ------ | ---------------------------------------------- |
| `id` | int | Token ID |
| `key` | string | API key in `sk-xxx` format |
| `status` | int | Status: 1=enabled, 2=disabled |
| `name` | string | Token name |
| `expired_time` | int | Expiration timestamp, `-1` means never expires |
| `remain_quota` | int | Remaining quota |
| `unlimited_quota` | bool | Whether quota is unlimited |
| `used_quota` | int | Used quota |
| `model_limits_enabled` | bool | Whether the model whitelist is enabled |
| `model_limits` | string | Model restriction config string |
| `allow_ips` | string | IP whitelist string |
| `group` | string | Group |
## Code Examples
```python Python theme={null}
import requests
headers = {
"Authorization": "Bearer your_access_token",
"New-Api-User": "1",
"User-Agent": "Mozilla/5.0"
}
response = requests.get(
"https://crazyrouter.com/api/token/?p=1&size=100",
headers=headers
)
page = response.json()["data"]
for token in page["items"]:
print(f"[{token['name']}] {token['key'][:10]}... Quota: {token['remain_quota']}")
```
```bash cURL theme={null}
curl "https://crazyrouter.com/api/token/?p=1&size=100" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 1"
```
# Usage Logs and Cost Monitoring
Source: https://docs.crazyrouter.com/en/token-management/logs-and-costs
Use management APIs to list API keys, query usage logs, summarize quota, and calculate USD cost
## Use Cases
If a customer needs monitoring per API key, use the Crazyrouter management APIs instead of trying to query with a business `sk-xxx` token directly:
* List all API keys under the current account
* Query usage logs by time range, key name, or model name
* Get summarized quota consumption for a specific key
* Convert quota into USD cost using system pricing metadata
Management APIs use user-level authentication, not the business token used for model inference calls.
## Authentication
Management APIs require both headers:
```text theme={null}
Authorization: Bearer {access_token}
New-Api-User: {user_id}
```
* `access_token`: user access token used for dashboard or management API authentication
* `New-Api-User`: current user ID, and it must match the user bound to the `access_token`
* `sk-xxx`: business token for model calls only, not for `/api/token/*` or `/api/log/*` management APIs
## Recommended Integration Flow
Recommended sequence:
1. Call `/api/token/` to get the current account's API key list
2. Call `/api/log/self` with `token_name` to fetch detailed logs for one key
3. Call `/api/log/self/stat` to fetch the summarized quota for the same filter
4. Call `/api/status` to get `quota_per_unit`
5. Convert quota into USD with `quota / quota_per_unit`
## 1. List API Keys
```bash cURL theme={null}
curl "https://crazyrouter.com/api/token/?p=1&page_size=100" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 485"
```
Example response:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"page": 1,
"page_size": 100,
"total": 1,
"items": [
{
"id": 409,
"name": "gptai",
"key": "sk-xxxxxxxxxxxxxxxx",
"status": 2,
"used_quota": 16605808,
"model_limits_enabled": true,
"model_limits": "kimi-k2.5"
}
]
}
}
```
Recommended fields to persist for monitoring:
* `id`
* `name`
* `status`
* `used_quota`
* `model_limits_enabled`
* `model_limits`
## 2. Query Usage Logs for a Specific Key
Use `/api/log/self` to query the current user's own consumption logs. At minimum, send:
* `type`
* `token_name`
* `start_timestamp`
* `end_timestamp`
* `p`
* `page_size`
Example:
```bash cURL theme={null}
curl "https://crazyrouter.com/api/log/self?type=2&token_name=gptai&start_timestamp=1771334901&end_timestamp=1772309095&p=1&page_size=5" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 485"
```
Example response:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"page": 1,
"page_size": 5,
"total": 4988,
"items": [
{
"created_at": 1772308747,
"token_name": "gptai",
"model_name": "deepseek-chat",
"quota": 3188,
"cost_usd": 0.006376,
"prompt_tokens": 884,
"completion_tokens": 397,
"use_time": 16.48,
"is_stream": true,
"ip": "203.0.113.10",
"other": {
"client": "openai-python",
"request_id": "req_xxx",
"request_method": "POST",
"request_path": "/v1/chat/completions",
"http_status": 200,
"discount": 0
}
}
]
}
}
```
### Key Fields
| Field | Description |
| -------------------- | -------------------------------------- |
| `token_name` | Which business key handled the request |
| `model_name` | The actual billed model |
| `quota` | System quota consumed by this request |
| `cost_usd` | USD cost converted from quota |
| `prompt_tokens` | Input tokens |
| `completion_tokens` | Output tokens |
| `use_time` | Request latency in seconds |
| `other.request_id` | Request ID for tracing |
| `other.client` | Client identifier |
| `other.request_path` | Upstream endpoint path |
| `other.http_status` | Upstream HTTP status code |
`cost_usd` is derived with `quota / quota_per_unit`. If your production environment has not yet been upgraded to a version that returns this field, you can still calculate cost from the summary quota.
## 3. Query Summary Consumption
If you only need a dashboard, report, or alerting input, use the summary endpoint:
```bash cURL theme={null}
curl "https://crazyrouter.com/api/log/self/stat?type=2&token_name=gptai&start_timestamp=1771334901&end_timestamp=1772309095" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 485"
```
Example response:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"quota": 16605808,
"rpm": 0,
"tpm": 0
}
}
```
Where:
* `quota`: total consumed quota under the current filter
* `rpm` and `tpm`: reserved fields for extended monitoring
## 4. Query Current Account Balance
If the customer does not only want per-key monitoring, but also wants to display the current Crazyrouter account balance directly in their own admin panel, call `/api/user/self`.
Use the same management-auth headers:
```bash cURL theme={null}
curl "https://crazyrouter.com/api/user/self" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 4004"
```
Example response:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"id": 4004,
"username": "google_4004",
"quota": 11000000,
"used_quota": 0,
"request_count": 0,
"group": "default"
}
}
```
Key fields:
| Field | Description |
| --------------- | ------------------------------------------------- |
| `quota` | Current remaining balance in internal quota units |
| `used_quota` | Historical used amount in internal quota units |
| `request_count` | Historical request count |
| `group` | Current account group |
Conversion:
```text theme={null}
balance_usd = quota / quota_per_unit
used_usd = used_quota / quota_per_unit
```
Example:
```text theme={null}
quota = 11000000
quota_per_unit = 500000
balance_usd = 11000000 / 500000 = 22
```
So the example above means:
```text theme={null}
$22.00
```
`/api/user/self` is better for displaying the current total account balance. `/api/log/self` and `/api/log/self/stat` are better for analyzing usage by time range, business key, or model.
## 5. Convert Quota to USD Cost
System conversion metadata is available from the public `/api/status` endpoint:
```bash cURL theme={null}
curl "https://crazyrouter.com/api/status"
```
Relevant fields:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"quota_per_unit": 500000,
"quota_display_type": "USD",
"usd_exchange_rate": 7.3
}
}
```
Formula:
```text theme={null}
cost_usd = quota / quota_per_unit
```
Example:
```text theme={null}
16605808 / 500000 = 33.211616 USD
```
## Python Example
```python theme={null}
import requests
BASE_URL = "https://crazyrouter.com"
ACCESS_TOKEN = "your_access_token"
USER_ID = "485"
TOKEN_NAME = "gptai"
headers = {
"Authorization": f"Bearer {ACCESS_TOKEN}",
"New-Api-User": USER_ID,
"User-Agent": "Mozilla/5.0",
}
token_resp = requests.get(
f"{BASE_URL}/api/token/",
params={"p": 1, "page_size": 100},
headers=headers,
timeout=30,
)
token_resp.raise_for_status()
tokens = token_resp.json()["data"]["items"]
log_resp = requests.get(
f"{BASE_URL}/api/log/self/stat",
params={
"type": 2,
"token_name": TOKEN_NAME,
"start_timestamp": 1771334901,
"end_timestamp": 1772309095,
},
headers=headers,
timeout=30,
)
log_resp.raise_for_status()
quota = log_resp.json()["data"]["quota"]
status_resp = requests.get(f"{BASE_URL}/api/status", timeout=30)
status_resp.raise_for_status()
quota_per_unit = status_resp.json()["data"]["quota_per_unit"]
cost_usd = quota / quota_per_unit
print("tokens:", [item["name"] for item in tokens])
print("quota:", quota)
print("cost_usd:", round(cost_usd, 6))
```
## Monitoring Recommendations
Recommended dimensions for customer-side monitoring:
* Aggregate request count, total quota, and total cost by `token_name`
* Aggregate consumption distribution by `model_name`
* Split traffic by `other.request_path`, such as `/v1/chat/completions` and `/v1/responses`
* Track success and failure rates by `other.http_status`
* Keep `other.request_id` for incident investigation
## FAQ
### Why can't management APIs use `sk-xxx` directly?
Because `sk-xxx` is validated by the token-auth flow for business requests, while `/api/token/*` and `/api/log/self*` are user-authenticated management APIs that require `access_token` plus `New-Api-User`.
### Can I query my logs for a single key?
Yes. The recommended approach is filtering `/api/log/self` and `/api/log/self/stat` by `token_name`.
### Can I get cost directly via API?
If your server version already exposes `cost_usd`, you can read per-request USD cost directly from log items. For summary-level monitoring, use `quota / quota_per_unit`; this matches the dashboard calculation method.
# Get Token Models
Source: https://docs.crazyrouter.com/en/token-management/models
GET /v1/models
Query the list of models available to a specific token
## Overview
Get the list of models that the current token (API Key) can access. If the token has no model restrictions, all enabled system models are returned.
The currently supported public endpoint is:
```text theme={null}
GET /v1/models
```
`GET /api/token/models` is not a currently exposed public endpoint. Use `/v1/models` instead.
## Authentication
Authenticate using an API Key (sk-xxx):
```
Authorization: Bearer sk-xxx
```
## Response Format
```json theme={null}
{
"success": true,
"object": "list",
"data": [
{
"id": "gpt-5.4",
"object": "model",
"owned_by": "openai"
},
{
"id": "claude-sonnet-4-6",
"object": "model",
"owned_by": "anthropic"
}
]
}
```
## Code Examples
```python Python theme={null}
from openai import OpenAI
client = OpenAI(
api_key="sk-xxx",
base_url="https://crazyrouter.com/v1"
)
# Get model list via OpenAI SDK
models = client.models.list()
for model in models.data:
print(model.id)
```
```python Python (requests) theme={null}
import requests
response = requests.get(
"https://crazyrouter.com/v1/models",
headers={"Authorization": "Bearer sk-xxx"}
)
models = response.json()["data"]
for model in models:
print(model["id"])
```
```bash cURL theme={null}
curl https://crazyrouter.com/v1/models \
-H "Authorization: Bearer sk-xxx"
```
If you use the OpenAI SDK, `client.models.list()` is effectively calling `GET /v1/models`.
Related pages:
* [Official Model Pricing Methods](/en/reference/official-pricing-methods)
# Search Tokens
Source: https://docs.crazyrouter.com/en/token-management/search
GET /api/token/search
Search tokens by keyword
## Overview
Search for tokens by keyword with fuzzy matching on token names. You can also filter by token fragments.
The `/api/token/*` endpoints are mainly for Crazyrouter dashboard automation around API key management. They require a user `access token` plus the `New-Api-User` header, and are not the normal interface for `sk-xxx` model calls.
## Authentication
Use user-side authentication with these headers:
```text theme={null}
Authorization: Bearer your_access_token
New-Api-User: 1
```
## Request Parameters
Search keyword, matches against token names
Optional. Filter by token string fragment
## Response Format
```json theme={null}
{
"success": true,
"message": "",
"data": [
{
"id": 5,
"name": "Production",
"key": "sk-xxxxxxxx",
"status": 1,
"remain_quota": 50000,
"used_quota": 8000,
"created_time": 1706000000,
"model_limits_enabled": false,
"model_limits": "",
"allow_ips": "",
"group": "default"
}
]
}
```
## Code Examples
```python Python theme={null}
import requests
headers = {
"Authorization": "Bearer your_access_token",
"New-Api-User": "1",
"User-Agent": "Mozilla/5.0"
}
response = requests.get(
"https://crazyrouter.com/api/token/search?keyword=production&token=sk-",
headers=headers
)
tokens = response.json()["data"]
for token in tokens:
print(f"[{token['id']}] {token['name']} - Remaining quota: {token['remain_quota']}")
```
```bash cURL theme={null}
curl "https://crazyrouter.com/api/token/search?keyword=production&token=sk-" \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 1"
```
# Update Token
Source: https://docs.crazyrouter.com/en/token-management/update
PUT /api/token/
Update the configuration of an existing token
## Overview
Modify the name, quota, expiration time, model permissions, and other settings of an existing token.
The `/api/token/*` endpoints are mainly for Crazyrouter dashboard automation around API key management. They require a user `access token` plus the `New-Api-User` header, and are not the normal interface for `sk-xxx` model calls.
## Authentication
Use user-side authentication with these headers:
```text theme={null}
Authorization: Bearer your_access_token
New-Api-User: 1
```
## Request Parameters
Token ID
Token name
Remaining quota
Whether quota is unlimited
Expiration timestamp, `-1` means never expires
Whether to enable the model whitelist
Model restriction config string, for example `["gpt-5.4","claude-sonnet-4-6"]`
Status: 1=enabled, 2=disabled
IP whitelist string
Group
## Response Format
The current endpoint returns the updated token object:
```json theme={null}
{
"success": true,
"message": "",
"data": {
"id": 10,
"name": "Production-Updated",
"status": 1,
"remain_quota": 200000,
"unlimited_quota": false,
"model_limits_enabled": true,
"model_limits": "[\"gpt-5.4\",\"claude-sonnet-4-6\"]",
"allow_ips": "203.0.113.10",
"group": "default"
}
}
```
## Code Examples
```python Python theme={null}
import json
import requests
headers = {
"Authorization": "Bearer your_access_token",
"New-Api-User": "1",
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0"
}
response = requests.put(
"https://crazyrouter.com/api/token/",
headers=headers,
json={
"id": 10,
"name": "Production-Updated",
"remain_quota": 200000,
"model_limits_enabled": True,
"model_limits": json.dumps(["gpt-5.4", "claude-sonnet-4-6"])
}
)
print(response.json())
```
```bash cURL theme={null}
curl -X PUT https://crazyrouter.com/api/token/ \
-H "Authorization: Bearer your_access_token" \
-H "New-Api-User: 1" \
-H "Content-Type: application/json" \
-d '{
"id": 10,
"name": "Production-Updated",
"remain_quota": 200000,
"model_limits_enabled": true,
"model_limits": "[\"gpt-5.4\"]"
}'
```
Updating a token does not regenerate the API key. If you need a new key, delete the token and create a new one.
# Image Upload Guidance
Source: https://docs.crazyrouter.com/en/upload
How to provide image URLs and use model-native upload flows
## Current status
Crazyrouter does not currently expose a public generic image-hosting endpoint.
Do not depend on the following endpoint:
```text theme={null}
POST /api/upload
```
## Recommended approaches
### 1. Use your own object storage or CDN
The best option is to upload files to your own S3 / R2 / OSS / COS / CDN bucket first, then pass the resulting public URL to Crazyrouter endpoints that support image input.
Typical use cases:
* GPT / Claude / Gemini vision
* image editing
* image-to-video
* workflow tool integrations
### 2. Use model-native upload flows
Some models and upstream APIs already support multipart uploads or dedicated upload routes. Use the model-specific endpoint when available.
Examples:
* Midjourney image upload: `POST /mj/submit/upload-discord-images`
* OpenAI-compatible image edits: `POST /v1/images/edits`
* audio transcription: `POST /v1/audio/transcriptions`
### 3. Save files in your own backend first, then send URLs
If users upload local files to your app, your backend should store the file, generate a public URL, and then call Crazyrouter with that URL.
## Example: use a public image URL for vision
```python Python theme={null}
from openai import OpenAI
client = OpenAI(api_key="sk-xxx", base_url="https://crazyrouter.com/v1")
response = client.chat.completions.create(
model="gpt-5.4",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image"},
{"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}
]
}]
)
print(response.choices[0].message.content)
```
```bash cURL theme={null}
curl https://crazyrouter.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxx" \
-d '{
"model": "gpt-5.4",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "Describe this image"},
{"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}
]
}]
}'
```
If the image URL is not publicly reachable, the upstream model usually cannot read it.
If Crazyrouter exposes a public generic upload API again in the future, this page will be updated into a formal endpoint reference.
# Ali Bailian Video API
Source: https://docs.crazyrouter.com/en/video/alibailian
Ali Bailian-compatible video routes. Clients use /alibailian/api/v1/* while Crazyrouter now proxies upstream to official DashScope /api/v1/* endpoints
# Ali Bailian Video API
Crazyrouter exposes Ali Bailian-compatible video routes so applications already using DashScope / Ali Bailian video formats can migrate with minimal path changes.
## What This Page Covers
* This page documents the Ali-compatible public alias exposed by Crazyrouter, so client requests should continue using `/alibailian/api/v1/*`
* Internally, Crazyrouter now talks to the official DashScope upstream through `/api/v1/*`
* If you want Crazyrouter's unified video API rather than the Ali-compatible migration path, use `/v1/video/generations`
* Actual model availability still depends on your token allowlist, pricing configuration, and current production channel bindings; do not assume every upstream Ali model is enabled by default
## Supported Endpoints
* `POST /alibailian/api/v1/services/aigc/video-generation/video-synthesis`
* `GET /alibailian/api/v1/tasks/{task_id}`
## Internal Upstream Mapping
* Public compatibility submit path: `POST /alibailian/api/v1/services/aigc/video-generation/video-synthesis`
* Public compatibility query path: `GET /alibailian/api/v1/tasks/{task_id}`
* Crazyrouter upstream submit path: `POST /api/v1/services/aigc/video-generation/video-synthesis`
* Crazyrouter upstream query path: `GET /api/v1/tasks/{task_id}`
## Authentication
```http theme={null}
Authorization: Bearer YOUR_API_KEY
```
## POST Create Video
```
POST /alibailian/api/v1/services/aigc/video-generation/video-synthesis
```
### Request Body Shape
| Field | Type | Required | Description |
| -------------------------- | ------- | -------- | ---------------------------------------- |
| `model` | string | Yes | Model name, such as `wan2.5-i2v-preview` |
| `input` | object | Yes | Core input payload |
| `input.prompt` | string | No | Positive prompt |
| `input.negative_prompt` | string | No | Negative prompt |
| `input.img_url` | string | No | First-frame image URL or Base64 |
| `input.audio_url` | string | No | Audio file URL |
| `input.template` | string | No | Video effect template |
| `parameters` | object | No | Advanced processing parameters |
| `parameters.resolution` | string | No | Resolution tier, for example `480P` |
| `parameters.duration` | integer | No | Video duration in seconds |
| `parameters.prompt_extend` | boolean | No | Whether to enable prompt enhancement |
| `parameters.watermark` | boolean | No | Whether to add an AI watermark |
| `parameters.audio` | boolean | No | Whether to auto-add audio |
| `parameters.seed` | integer | No | Random seed |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/alibailian/api/v1/services/aigc/video-generation/video-synthesis \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "wan2.5-i2v-preview",
"input": {
"prompt": "Change the lighting",
"img_url": "https://example.com/first-frame.png"
},
"parameters": {
"resolution": "480P",
"prompt_extend": true,
"audio": true
}
}'
```
### Response Example
```json theme={null}
{
"request_id": "ccffb21f-c21e-4eba-861a-6c80e6db6e4d",
"output": {
"task_id": "a55bfe14-6e78-4b9d-b97d-128420399ed1",
"task_status": "PENDING"
}
}
```
## GET Query Task
```
GET /alibailian/api/v1/tasks/{task_id}
```
### Request Example
```bash cURL theme={null}
curl https://crazyrouter.com/alibailian/api/v1/tasks/a55bfe14-6e78-4b9d-b97d-128420399ed1 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example
```json theme={null}
{
"usage": {
"SR": 480,
"duration": 5,
"video_count": 1
},
"output": {
"task_id": "a55bfe14-6e78-4b9d-b97d-128420399ed1",
"end_time": "2025-10-11 19:02:27.297",
"video_url": "https://dashscope-result.example.com/video.mp4",
"orig_prompt": "Change the lighting",
"submit_time": "2025-10-11 18:55:56.952",
"task_status": "SUCCEEDED",
"actual_prompt": "A man in orange clothes flies from right to left on a broom...",
"scheduled_time": "2025-10-11 18:55:57.908"
},
"request_id": "ec8f059e-f2e5-4887-bb43-3306cd38f403"
}
```
## Error Behavior Verified Locally
* the local environment confirmed the create route exists; when a model is unavailable it returns a business error such as `model_not_found` rather than `404`
* the local environment also confirmed the query route exists; a nonexistent task returns:
```json theme={null}
{
"code": "task_not_exist",
"message": "task_not_exist",
"data": null
}
```
This path family is primarily for protocol-compatible migration. The request and response bodies stay much closer to native DashScope / Bailian conventions than to Crazyrouter's unified video schema. It also does not mean every Ali video model is publicly enabled on Crazyrouter; treat current pricing, token allowlists, and live channel bindings as the source of truth.
# Jimeng
Source: https://docs.crazyrouter.com/en/video/jimeng
Use the Jimeng API to generate videos
# Jimeng
Jimeng is ByteDance's video generation service. On Crazyrouter, the recommended public contract is the `/jimeng/*` family. We do not expose the upstream `Action + Version` form as the primary customer-facing API.
## Currently Verified Scope
* `POST /jimeng/submit/videos` is verified for `jimeng-video-3.0` text-to-video
* single-image input and single-image `recamera` are verified
* the currently stable positive-sample mainline is concentrated on `1080P`
* `720P / recamera` is still a `ch119` carrier-level follow-up and is not being expanded into the current public hard contract
* query results prefer Crazyrouter archived media URLs such as `https://media.crazyrouter.com/...`
* the `expired` re-probe path is closed, but naturally expired samples are still a passive background tail item and do not block the mainline contract
## Submit Video Task
```
POST /jimeng/submit/videos
```
### Recommended Public Model
* `jimeng-video-3.0`: current primary public model
### Request Parameters
| Parameter | Type | Required | Description |
| -------------------- | --------- | ------------- | ------------------------------------------------------------------------------------- |
| `model` | string | Yes | Public model name. `jimeng-video-3.0` is recommended |
| `prompt` | string | Conditionally | Strongly recommended for text-to-video; also recommended for `recamera` motion intent |
| `duration` | integer | No | Recommended values: `5` or `10` |
| `aspect_ratio` | string | No | Aspect ratio such as `16:9` or `9:16` |
| `image_url` | string | No | Single-image URL input |
| `binary_data_base64` | string\[] | No | Single-image Base64 input |
| `image_urls` | string\[] | No | Compatibility array form; do not treat it as a public multi-reference hard contract |
| `template_id` | string | No | Single-image `recamera` template, for example `handheld` |
| `camera_strength` | string | No | Single-image `recamera` strength, for example `weak`, `medium`, `strong` |
| `req_key` | string | No | Reserved for debugging or compatibility flows; not recommended for normal integration |
### Text-to-Video Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/jimeng/submit/videos \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "jimeng-video-3.0",
"prompt": "A gentle camera push-in on an orange cat yawning by the window in soft morning light",
"duration": 5,
"aspect_ratio": "9:16"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/jimeng/submit/videos",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "jimeng-video-3.0",
"prompt": "A gentle camera push-in on an orange cat yawning by the window in soft morning light",
"duration": 5,
"aspect_ratio": "9:16"
}
)
print(response.json())
```
### Single-Image `recamera` Example
```json theme={null}
{
"model": "jimeng-video-3.0",
"prompt": "Natural handheld push-in while the subject slightly turns",
"image_url": "https://example.com/portrait.png",
"duration": 5,
"aspect_ratio": "9:16",
"template_id": "handheld",
"camera_strength": "medium"
}
```
### Successful Submit Response
```json theme={null}
{
"id": "2526913314163451526",
"task_id": "2526913314163451526",
"object": "video",
"model": "jimeng-video-3.0",
"status": "",
"progress": 0,
"created_at": 1774570545
}
```
***
## Query Task
```
GET /jimeng/fetch/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/jimeng/fetch/2526913314163451526 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Completed Response Example
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "mp4",
"metadata": null,
"status": "succeeded",
"task_id": "2526913314163451526",
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/27/51/generate/2526913314163451526.mp4"
}
}
```
### Task Status
| Status | Description |
| ------------ | --------------------------------------- |
| `queued` | submitted or waiting in queue |
| `processing` | generation in progress |
| `succeeded` | completed and ready to fetch from `url` |
| `failed` | terminal failure |
The current public docs only commit to single-image input and single-image `recamera`. Do not document `image_urls` as a public multi-reference hard contract, and do not recommend `frames` as a public parameter. Unsupported `frames` values may be accepted at submit time and then fail later at the upstream pipeline stage.
The public doc is intentionally constrained to the verified stable scope: `jimeng-video-3.0 + text-to-video / single-image input / single-image recamera`. Whether `720P / recamera` is expanded later depends on carrier-level sample follow-up rather than additional passthrough code.
# Kling Advanced Features
Source: https://docs.crazyrouter.com/en/video/kling/advanced
Kling advanced features: virtual try-on
# Kling Advanced Features
## Virtual Try-On
```
POST /kling/v1/images/kolors-virtual-try-on
```
Virtual try-on is the only currently exposed Kling advanced capability. This path has completed bounded success verification, including the `task success -> R2 archive -> media.crazyrouter.com` flow.
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------ | ------ | -------- | ----------------------------------------------------------------------- |
| `model_name` | string | No | Common models: `kolors-virtual-try-on-v1`, `kolors-virtual-try-on-v1-5` |
| `human_image` | string | Yes | Person image. URL or Base64 is supported |
| `cloth_image` | string | Yes | Clothing image. URL or Base64 is supported |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/images/kolors-virtual-try-on \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_name": "kolors-virtual-try-on-v1",
"human_image": "https://example.com/person.jpg",
"cloth_image": "https://example.com/jacket.jpg"
}'
```
### Successful Submit Response
```json theme={null}
{
"created_at": 1774585120,
"id": "866361099762425934",
"model": "kolors-virtual-try-on-v1",
"object": "video",
"progress": 0,
"status": "",
"task_id": "866361099762425934"
}
```
## Query Try-On Task
```
GET /kling/v1/images/kolors-virtual-try-on/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/kling/v1/images/kolors-virtual-try-on/866361099762425934 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Completed Response Example
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"status": "succeeded",
"task_id": "866361099762425934",
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/27/50/tryOnGenerate/866361099762425934.png"
}
}
```
Do not document lip sync, video extension, or effects as publicly available Kling endpoints. They are still outside Crazyrouter's public contract.
# Kling Image Generation
Source: https://docs.crazyrouter.com/en/video/kling/images
Use the Kling API to generate images
# Kling Image Generation
```
POST /kling/v1/images/generations
```
The current public docs only commit to the main Kling image-generation path. Do not document undocumented image-side extensions as if they were already a stable public contract.
## Currently Verified Scope
* `kling-v2-5-turbo` image generation has completed bounded verification
* successful results prefer Crazyrouter archived URLs such as `https://media.crazyrouter.com/...png`
## Request Parameters
| Parameter | Type | Required | Description |
| ------------------ | ------- | -------- | -------------------------------------------- |
| `model` | string | No | Common validated example: `kling-v2-5-turbo` |
| `prompt` | string | Yes | Image prompt |
| `negative_prompt` | string | No | Negative prompt |
| `aspect_ratio` | string | No | Such as `1:1`, `16:9`, `9:16` |
| `n` | integer | No | Number of images, default `1` |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
## Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/images/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "kling-v2-5-turbo",
"prompt": "A realistic shiba inu wearing sunglasses",
"negative_prompt": "blurry, low quality",
"aspect_ratio": "1:1",
"n": 1
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/kling/v1/images/generations",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "kling-v2-5-turbo",
"prompt": "A realistic shiba inu wearing sunglasses",
"negative_prompt": "blurry, low quality",
"aspect_ratio": "1:1",
"n": 1
}
)
print(response.json())
```
## Successful Submit Response
```json theme={null}
{
"created_at": 1774536039,
"id": "2037177945839673344",
"model": "kling-v2-5-turbo",
"object": "video",
"progress": 0,
"status": "",
"task_id": "2037177945839673344"
}
```
***
## Query Image Task
```
GET /kling/v1/images/generations/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/kling/v1/images/generations/2037177945839673344 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Completed Response Example
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "png",
"metadata": null,
"status": "succeeded",
"task_id": "2037177945839673344",
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/26/50/imageGenerate/2037177945839673344.png"
}
}
```
Kling image generation is asynchronous. Query the task for terminal output. This page intentionally does not document image-to-image, `image_fidelity`, or other image-side extension parameters as a public hard contract.
# Kling Task Query
Source: https://docs.crazyrouter.com/en/video/kling/query
Query the status and results of Kling video, image-generation, and virtual try-on tasks
# Kling Task Query
## Queryable Task Paths
| Path | Purpose |
| ------------------------------------------------------ | ---------------------------------------- |
| `GET /kling/v1/videos/text2video/{task_id}` | Query a text-to-video task |
| `GET /kling/v1/videos/image2video/{task_id}` | Query an image-to-video task |
| `GET /kling/v1/videos/multi-image2video/{task_id}` | Query a multi-image reference video task |
| `GET /kling/v1/videos/omni-video/{task_id}` | Query an omni-video task |
| `GET /kling/v1/images/generations/{task_id}` | Query an image-generation task |
| `GET /kling/v1/images/kolors-virtual-try-on/{task_id}` | Query a virtual try-on task |
## Response Format
All Kling query endpoints return the same task envelope:
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "mp4",
"metadata": null,
"status": "succeeded",
"task_id": "866168216002236456",
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/26/50/textGenerate/866168216002236456.m4v"
}
}
```
### Queued
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "mp4",
"metadata": null,
"status": "queued",
"task_id": "task_abc123",
"url": ""
}
}
```
### Processing
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "mp4",
"metadata": null,
"status": "processing",
"task_id": "task_abc123",
"url": ""
}
}
```
### Completed
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": null,
"format": "mp4",
"metadata": null,
"status": "succeeded",
"task_id": "866168216002236456",
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/26/50/textGenerate/866168216002236456.m4v"
}
}
```
### Failed
```json theme={null}
{
"code": "success",
"message": "",
"data": {
"error": {
"message": "content moderation failed",
"code": "task_failed"
},
"format": "mp4",
"metadata": null,
"status": "failed",
"task_id": "task_abc123",
"url": ""
}
}
```
## Task Status
| Status | Description |
| ------------ | ------------------------------------------ |
| `queued` | submitted or waiting in queue |
| `processing` | generation in progress |
| `succeeded` | completed and directly fetchable via `url` |
| `failed` | terminal failure |
***
## End-to-End Example
```python Python theme={null}
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://crazyrouter.com"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
# 1. Submit a text-to-video task
resp = requests.post(
f"{BASE_URL}/kling/v1/videos/text2video",
headers=headers,
json={
"model_name": "kling-v2-5-turbo",
"prompt": "A cat chasing butterflies in a garden",
"duration": "5",
"aspect_ratio": "16:9"
}
)
task_id = resp.json()["task_id"]
# 2. Poll for results
while True:
resp = requests.get(
f"{BASE_URL}/kling/v1/videos/text2video/{task_id}",
headers=headers
)
data = resp.json()["data"]
if data["status"] == "succeeded":
print(f"Video URL: {data['url']}")
break
if data["status"] == "failed":
print(f"Failed: {data['error']}")
break
time.sleep(10)
```
Kling standard-video, omni-video, image-generation, and try-on tasks may all return Crazyrouter archived URLs under `media.crazyrouter.com/...`. Client integrations should consume `url` directly instead of depending on upstream raw CDN URLs.
# Kling Video Generation
Source: https://docs.crazyrouter.com/en/video/kling/video
Use Crazyrouter with the official Kling standard-video and omni-video contracts
# Kling Video Generation
Crazyrouter exposes the current public Kling video family through two official model families:
| Route Family | Submit Paths | Fetch Paths | Public Models |
| -------------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| Standard Kling video | `POST /kling/v1/videos/text2video` `POST /kling/v1/videos/image2video` `POST /kling/v1/videos/multi-image2video` | `GET /kling/v1/videos/text2video/{task_id}` `GET /kling/v1/videos/image2video/{task_id}` `GET /kling/v1/videos/multi-image2video/{task_id}` | `kling-v2-5-turbo` `kling-v2-6` `kling-v3` |
| Kling omni-video | `POST /kling/v1/videos/omni-video` | `GET /kling/v1/videos/omni-video/{task_id}` | `kling-v3` `kling-v3` |
All tasks are asynchronous. Successful fetches prefer Crazyrouter archived URLs such as `https://media.crazyrouter.com/...`.
## First-Batch Five Models
| Model | Route Family | Public Capability Surface | Validation Status | Billing Dimension Summary |
| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------- | ---------------------------------------------------------------- |
| `kling-v2-5-turbo` | Standard Kling video | text-to-video, image-to-video, start-end, reference-video | `Beta` | `mode + duration` |
| `kling-v2-6` | Standard Kling video | text-to-video, image-to-video, start-end, reference-video, sound, voice control, motion control | `Beta` | `mode + duration + sound + voice control` |
| `kling-v3` | Standard Kling video | text-to-video, image-to-video, start-end, reference-video, motion control, standard-route element references | `Beta` | `mode + duration + sound`; motion uses a separate billing bucket |
| `kling-v3` | Kling omni-video | omni-video with image / element / video / voice references | `Beta` | `mode + duration + sound + video input` |
| `kling-v3` | Kling omni-video | single-shot omni-video | `Beta` | `mode + duration + video input` |
The customer-facing contract follows the official Kling capability and field definitions. Third-party channels remain internal providers only. Use the live Pricing page as the source of truth for sell-side prices.
The first-batch Kling five-model family is already aligned to the official field surface and pricing matrix, but every capability row is still marked `Beta` for now. After launch, we will use production logs and the daily script to promote rows out of beta one by one.
## Standard Kling Video
```
POST /kling/v1/videos/text2video
POST /kling/v1/videos/image2video
POST /kling/v1/videos/multi-image2video
```
### Recommended Public Models
* `kling-v2-5-turbo`
* `kling-v2-6`
* `kling-v3`
### Text-to-Video Parameters
| Parameter | Type | Required | Description |
| ------------------ | ---------------- | ---------------------- | ------------------------------------------------------------------------------------------- |
| `model_name` | string | Yes | Standard Kling video model |
| `prompt` | string | Yes | Video prompt |
| `image_urls` | array\[string] | No | Official first-frame / first-last-frame input. Recommended when referencing `@element_name` |
| `negative_prompt` | string | No | Negative prompt |
| `duration` | string/integer | No | Common values: `5` or `10` |
| `aspect_ratio` | string | No | Such as `16:9`, `9:16`, `1:1` |
| `mode` | string | No | Generation mode, such as `std` or `pro` |
| `sound` | string / boolean | No | Recommended official values are `on` / `off` |
| `multi_shots` | boolean | No | Official multi-shot switch. The alias `multi_shot` is also accepted |
| `multi_prompt` | array | Conditionally required | Multi-shot prompt list, up to 5 shots |
| `kling_elements` | array | No | `kling-v3` standard-route element references used with `@element_name` |
| `cfg_scale` | number | No | Guidance strength |
| `camera_control` | object | No | Camera control payload |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
### Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/videos/text2video \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_name": "kling-v2-5-turbo",
"prompt": "A cat chasing butterflies in a garden, sunny day, cinematic quality",
"negative_prompt": "blurry, low quality, distorted",
"duration": "5",
"aspect_ratio": "16:9",
"mode": "std"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/kling/v1/videos/text2video",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model_name": "kling-v2-5-turbo",
"prompt": "A cat chasing butterflies in a garden, sunny day",
"duration": "5",
"aspect_ratio": "16:9",
"mode": "std"
}
)
print(response.json())
```
### Successful Submit Response
```json theme={null}
{
"created_at": 1774539107,
"id": "866168216002236456",
"model": "kling-v2-5-turbo",
"object": "video",
"progress": 0,
"status": "",
"task_id": "866168216002236456"
}
```
***
### Image-to-Video Parameters
| Parameter | Type | Required | Description |
| ------------------ | ---------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `model_name` | string | Yes | Standard Kling video model |
| `image_urls` | array\[string] | Preferred | Official first-frame / first-last-frame input. Length `1` means first frame; length `2` means first + last frame |
| `image` | string | Compatibility | Compatibility alias, equivalent to `image_urls[0]` |
| `prompt` | string | No | Motion or camera prompt |
| `image_tail` | string | Compatibility | Compatibility alias, equivalent to `image_urls[1]` |
| `negative_prompt` | string | No | Negative prompt |
| `duration` | string/integer | No | Common values: `5` or `10` |
| `aspect_ratio` | string | No | Output ratio |
| `mode` | string | No | Generation mode |
| `sound` | string / boolean | No | Recommended official values are `on` / `off` |
| `multi_shots` | boolean | No | Official multi-shot switch. The alias `multi_shot` is also accepted |
| `multi_prompt` | array | Conditionally required | Multi-shot prompt list |
| `kling_elements` | array | No | `kling-v3` standard-route element references |
| `cfg_scale` | number | No | Guidance strength |
| `camera_control` | object | No | Camera control payload |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
### Image-to-Video Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/videos/image2video \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_name": "kling-v3",
"prompt": "The person in the image starts smiling and slowly turns their head",
"image": "https://example.com/portrait.jpg",
"duration": "5",
"mode": "std"
}'
```
`image_urls` is the official-first field. `image + image_tail` remain supported as compatibility aliases and are treated as first-frame / last-frame input. Video tasks are asynchronous. Use [Task Query](/en/video/kling/query) to fetch the terminal result.
***
### Multi-Image Reference Video Parameters
```
POST /kling/v1/videos/multi-image2video
```
This route maps to the official standard-family Kling `Reference` capability. Unlike `image2video`, it does not use `image` or `image_tail`; it uses the official `image_list` reference input instead.
| Parameter | Type | Required | Description |
| ------------------ | ---------------- | ---------------------- | ------------------------------------------------------------------- |
| `model_name` | string | Yes | Standard Kling video model |
| `prompt` | string | Yes | Identity and motion prompt for the reference images |
| `image_list` | array | Yes | Official reference image list |
| `negative_prompt` | string | No | Negative prompt |
| `duration` | string/integer | No | Common values: `5` or `10` |
| `aspect_ratio` | string | No | Output ratio |
| `mode` | string | No | Generation mode |
| `sound` | string / boolean | No | Recommended official values are `on` / `off` |
| `multi_shots` | boolean | No | Official multi-shot switch. The alias `multi_shot` is also accepted |
| `multi_prompt` | array | Conditionally required | Multi-shot prompt list |
| `cfg_scale` | number | No | Guidance strength |
| `camera_control` | object | No | Camera control payload |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
### Multi-Image Reference Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/videos/multi-image2video \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_name": "kling-v3",
"prompt": "Keep the same Shiba Inu identity while it runs across a sunny park",
"duration": "5",
"aspect_ratio": "16:9",
"mode": "pro",
"image_list": [
{
"image_id": 1,
"image_url": "https://example.com/reference-1.png"
},
{
"image_id": 2,
"image_url": "https://example.com/reference-2.png"
}
]
}'
```
`multi-image2video` is the standard Kling reference route. If your input is a first frame or a first-last pair, continue using `image2video`. Query reference tasks through `GET /kling/v1/videos/multi-image2video/{task_id}`.
***
## Kling Omni Video
```
POST /kling/v1/videos/omni-video
```
### Public Models
* `kling-v3`
* `kling-v3`
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------ | -------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `model_name` | string | Yes | Only `kling-v3` and `kling-v3` are accepted on this route |
| `prompt` | string | Yes | Official omni prompt that can reference assets from `image_list`, `element_list`, `video_list`, and `voice_list` |
| `sound` | string | No | Official values are `on` / `off` |
| `duration` | string/integer | No | Commonly `5`; max duration depends on the selected model's official capability |
| `aspect_ratio` | string | No | Such as `16:9`, `9:16`, `1:1` |
| `mode` | string | No | Generation mode such as `std` or `pro` |
| `multi_shots` | boolean | No | Official multi-shot switch. The alias `multi_shot` is also accepted |
| `multi_prompt` | array | Conditionally required | Multi-shot prompt list |
| `image_list` | array | No | Official image reference list |
| `element_list` | array | No | Official element reference list |
| `video_list` | array | No | Official video reference list |
| `voice_list` | array | No | Official voice reference list |
| `callback_url` | string | No | Callback URL |
| `external_task_id` | string | No | Custom business task ID |
### Omni Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/kling/v1/videos/omni-video \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model_name": "kling-v3",
"prompt": "<<>> walks toward the camera in a rainy alley",
"sound": "on",
"duration": "5",
"aspect_ratio": "16:9",
"mode": "pro",
"image_list": [
{
"image_id": 1,
"image_url": "https://example.com/reference.png"
}
]
}'
```
`kling-v3` is currently exposed as single-shot omni generation only. `kling-v3` is the broader omni model. The omni route prefers the official `element_list` field and also accepts the compatibility alias `kling_elements`. Fetch omni tasks through `GET /kling/v1/videos/omni-video/{task_id}`.
# Luma
Source: https://docs.crazyrouter.com/en/video/luma
Use the Luma Dream Machine API to generate videos
# Luma
Luma Dream Machine provides high-quality video generation capabilities. Official docs: [docs.lumalabs.ai](https://docs.lumalabs.ai/docs/video-generation)
## Create Video
```
POST /luma/generations
```
### Request Parameters
| Parameter | Type | Required | Description |
| --------------- | ------- | -------- | ----------------------------------- |
| `user_prompt` | string | Yes | Video description prompt |
| `model_name` | string | No | Model name: `ray-v1`, `ray-v2` |
| `duration` | string | No | Video duration (seconds) |
| `resolution` | string | No | Resolution: `540p`, `720p`, `1080p` |
| `expand_prompt` | boolean | No | Whether to auto-expand the prompt |
| `image_url` | string | No | First frame reference image URL |
| `image_end_url` | string | No | Last frame reference image URL |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/luma/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"user_prompt": "A drone shot flying over a tropical island with crystal clear water",
"model_name": "ray-v2",
"duration": "5",
"resolution": "720p",
"expand_prompt": true
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/luma/generations",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"user_prompt": "A drone shot flying over a tropical island",
"model_name": "ray-v2",
"duration": "5",
"resolution": "720p"
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"id": "luma_gen_abc123",
"state": "queued",
"created_at": "2024-03-01T12:00:00Z"
}
```
***
## Image-to-Video
Pass `image_url` as the first frame:
```json theme={null}
{
"user_prompt": "The person in the image starts walking forward",
"model_name": "ray-v2",
"image_url": "https://example.com/portrait.jpg"
}
```
First-last frame mode:
```json theme={null}
{
"user_prompt": "Smooth transition between two scenes",
"model_name": "ray-v2",
"image_url": "https://example.com/start.jpg",
"image_end_url": "https://example.com/end.jpg"
}
```
***
## Query Task
```
GET /luma/generations/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/luma/generations/luma_gen_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example
```json theme={null}
{
"id": "luma_gen_abc123",
"state": "completed",
"created_at": "2024-03-01T12:00:00Z",
"video": {
"url": "https://storage.cdn-luma.com/...",
"download_url": "https://storage.cdn-luma.com/..."
}
}
```
***
## Extend Video
```
POST /luma/generations/{task_id}/extend
```
Extend a completed video.
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/luma/generations/luma_gen_abc123/extend \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"user_prompt": "Continue the drone shot, camera pans to reveal a beach resort"
}'
```
### Task Status
| Status | Description |
| ----------- | ----------- |
| `queued` | Queued |
| `dreaming` | Generating |
| `completed` | Completed |
| `failed` | Failed |
# MiniMax Video
Source: https://docs.crazyrouter.com/en/video/minimax
Use the MiniMax/Hailuo API to generate videos
# MiniMax Video
MiniMax (Hailuo) provides high-quality video generation capabilities.
## Create Video
```
POST /minimax/v1/video_generation
```
### Request Parameters
| Parameter | Type | Required | Description |
| ------------------- | ------ | -------- | ---------------------------------------------- |
| `model` | string | Yes | Model name, e.g. `video-01`, `video-01-live2d` |
| `prompt` | string | Yes | Video description prompt |
| `first_frame_image` | string | No | First frame image URL |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/minimax/v1/video_generation \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "video-01",
"prompt": "A kitten napping in the sunlight, a gentle breeze ruffling its fur"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/minimax/v1/video_generation",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "video-01",
"prompt": "A kitten napping in the sunlight, a gentle breeze ruffling its fur"
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"task_id": "minimax_video_abc123",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}
```
***
## Image-to-Video
```json theme={null}
{
"model": "video-01",
"prompt": "The person in the image starts smiling",
"first_frame_image": "https://example.com/portrait.jpg"
}
```
***
## Query Task
```
GET /minimax/v1/query/video_generation?task_id={task_id}
```
```bash cURL theme={null}
curl "https://crazyrouter.com/minimax/v1/query/video_generation?task_id=minimax_video_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example (Completed)
```json theme={null}
{
"task_id": "minimax_video_abc123",
"status": "Success",
"file_id": "file_abc123",
"base_resp": {
"status_code": 0,
"status_msg": "success"
}
}
```
### Task Status
| Status | Description |
| ------------ | ----------- |
| `Queueing` | Queued |
| `Processing` | Processing |
| `Success` | Succeeded |
| `Fail` | Failed |
# OpenAI Video Format
Source: https://docs.crazyrouter.com/en/video/openai-video
Use the OpenAI-compatible video API format to create, query, and download videos
# OpenAI Video Format
Crazyrouter supports the official OpenAI video API format, compatible with the OpenAI SDK.
## Create Video
```
POST /v1/videos
```
### Request Parameters
| Parameter | Type | Required | Description |
| ------------ | ------- | -------- | ------------------------------------------------- |
| `model` | string | Yes | Model name, e.g. `sora-2`, `sora-2-pro` |
| `prompt` | string | Yes | Video description prompt |
| `size` | string | No | Video size: `1920x1080`, `1080x1920`, `1080x1080` |
| `duration` | integer | No | Video duration (seconds) |
| `image_url` | string | No | Reference image URL |
| `storyboard` | array | No | Storyboard script |
| `private` | boolean | No | Whether to use private mode |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/videos \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "sora-2",
"prompt": "A timelapse of a city skyline from day to night, clouds moving quickly",
"size": "1920x1080",
"duration": 10
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/videos",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "sora-2",
"prompt": "A timelapse of a city skyline from day to night",
"size": "1920x1080",
"duration": 10
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"id": "video_abc123",
"object": "video",
"status": "processing",
"created_at": 1709123456
}
```
***
## Query Video
```
GET /v1/videos/{id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/v1/videos/video_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example (Completed)
```json theme={null}
{
"id": "video_abc123",
"object": "video",
"status": "completed",
"created_at": 1709123456,
"video": {
"url": "https://crazyrouter.com/files/video_abc123.mp4",
"duration": 10,
"width": 1920,
"height": 1080
}
}
```
***
## Download Video
```
GET /v1/videos/{id}/content
```
Download the video file directly.
```bash cURL theme={null}
curl -o output.mp4 https://crazyrouter.com/v1/videos/video_abc123/content \
-H "Authorization: Bearer YOUR_API_KEY"
```
***
## Edit Video
Pass `image_url` in the create request for image-to-video:
```json theme={null}
{
"model": "sora-2",
"prompt": "The scene comes to life with gentle movement",
"image_url": "https://example.com/scene.jpg",
"size": "1920x1080",
"duration": 5
}
```
***
## Storyboard
```json theme={null}
{
"model": "sora-2",
"storyboard": [
{"prompt": "Wide shot of a forest at dawn", "duration": 3},
{"prompt": "A deer walks into frame", "duration": 4},
{"prompt": "Close-up of the deer looking at camera", "duration": 3}
],
"size": "1920x1080"
}
```
***
## Private Mode
Set `private: true` so the generated video won't appear in the public gallery:
```json theme={null}
{
"model": "sora-2",
"prompt": "A confidential product demo video",
"size": "1920x1080",
"private": true
}
```
### Task Status
| Status | Description |
| ------------ | ----------- |
| `processing` | Processing |
| `completed` | Completed |
| `failed` | Failed |
# Video Generation Alias
Source: https://docs.crazyrouter.com/en/video/openai-video-alias-create
POST /v1/video/generations compatibility alias for clients that already depend on this video-generation path
# Video Generation Alias
```
POST /v1/video/generations
```
This is a Crazyrouter compatibility alias for clients or middleware that are already pinned to the `/v1/video/generations` path.
## Authentication
```http theme={null}
Authorization: Bearer YOUR_API_KEY
```
## When To Use It
* your client is hardcoded to `/v1/video/generations`
* you are migrating an older video workflow and do not want to change the path
* you need to preserve compatibility with an existing third-party request shape
For new integrations, prefer:
* `POST /v1/videos`: closer to the official OpenAI video format
* `POST /v1/video/create`: Crazyrouter's unified video format
## Minimal Request Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/generations -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_API_KEY" -d '{
"model": "veo-3.1",
"prompt": "A cinematic shot of waves hitting a cliff at sunset"
}'
```
## Typical Success Response
```json theme={null}
{
"id": "video_task_abc123",
"status": "processing",
"status_update_time": 1709123456
}
```
## Error Response Verified Locally
On the local `http://127.0.0.1:4000` environment, this route was verified to exist. When the model is temporarily unavailable, it returns a business error rather than `404`:
```json theme={null}
{
"code": "get_channel_failed",
"message": "model veo-3.1 is temporarily unavailable, please try again later",
"data": null
}
```
## Notes
* request fields vary by video model and upstream capability
* model availability depends on the token whitelist and current upstream state
* after task creation, query status with `GET /v1/video/generations/{task_id}`
This route is a compatibility alias. It does not guarantee that every video model shares the exact same body schema. If you are starting fresh and do not need legacy path compatibility, prefer `/v1/videos` or `/v1/video/create`.
# Video Task Query Alias
Source: https://docs.crazyrouter.com/en/video/openai-video-alias-query
GET /v1/video/generations/{task_id} compatibility alias for querying video task status
# Video Task Query Alias
```
GET /v1/video/generations/{task_id}
```
Use this route to query tasks created through the compatibility video-generation path. It is the matching query alias for `/v1/video/generations`.
## Authentication
```http theme={null}
Authorization: Bearer YOUR_API_KEY
```
## Request Example
```bash cURL theme={null}
curl https://crazyrouter.com/v1/video/generations/video_task_abc123 -H "Authorization: Bearer YOUR_API_KEY"
```
## Typical Success Response
```json theme={null}
{
"id": "video_task_abc123",
"status": "completed",
"video_url": "https://example.com/video.mp4"
}
```
## Missing-Task Response Verified Locally
On the local `http://127.0.0.1:4000` environment, querying a nonexistent task returns:
```json theme={null}
{
"code": "task_not_exist",
"message": "task_not_exist",
"data": null
}
```
## Common Status Values
| Status | Description |
| ------------ | -------------------------- |
| `processing` | Task is running |
| `completed` | Task finished successfully |
| `failed` | Task failed |
Final result fields can vary slightly by video model and upstream provider. The safest operational pattern is to keep creation and query requests on the same compatibility path family.
# Runway
Source: https://docs.crazyrouter.com/en/video/runway
Use the Runway API for image-to-video generation
# Runway
```
POST /runwayml/v1/image_to_video
```
Use the Runway Gen-3 model to convert images into videos.
## Request Parameters
| Parameter | Type | Required | Description |
| ------------- | ------- | -------- | ----------------------------------- |
| `model` | string | No | Model name, e.g. `gen3a_turbo` |
| `promptImage` | string | Yes | Input image URL |
| `promptText` | string | No | Video description prompt |
| `duration` | integer | No | Video duration (seconds), default 5 |
| `ratio` | string | No | Aspect ratio: `16:9`, `9:16` |
| `watermark` | boolean | No | Whether to add a watermark |
## Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/runwayml/v1/image_to_video \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "gen3a_turbo",
"promptImage": "https://example.com/landscape.jpg",
"promptText": "Camera slowly pans across the landscape, clouds moving in the sky",
"duration": 5,
"ratio": "16:9",
"watermark": false
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/runwayml/v1/image_to_video",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "gen3a_turbo",
"promptImage": "https://example.com/landscape.jpg",
"promptText": "Camera slowly pans across the landscape",
"duration": 5,
"ratio": "16:9"
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"id": "runway_task_abc123",
"status": "PENDING"
}
```
***
## Query Task
```
GET /runwayml/v1/tasks/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/runwayml/v1/tasks/runway_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example (Completed)
```json theme={null}
{
"id": "runway_task_abc123",
"status": "SUCCEEDED",
"output": [
"https://runway-output.s3.amazonaws.com/..."
]
}
```
### Task Status
| Status | Description |
| ----------- | ----------------------- |
| `PENDING` | Waiting to be processed |
| `RUNNING` | Generating |
| `SUCCEEDED` | Succeeded |
| `FAILED` | Failed |
# Seedance
Source: https://docs.crazyrouter.com/en/video/seedance
Use the native Seedance API for video generation
# Seedance
Seedance is ByteDance / Doubao's video generation family. On Crazyrouter, the public contract stays on the native `/volc/v1/*` surface. The old unified-video `seedance-lite` alias is no longer the primary customer-facing protocol.
## Current Public Models
| Model | Current public positioning |
| ------------------------------ | -------------------------------------------------------------------- |
| `doubao-seedance-1-0-lite-t2v` | text-to-video |
| `doubao-seedance-1-0-lite-i2v` | single-image image-to-video |
| `doubao-seedance-1-0-pro` | general higher-quality generation |
| `doubao-seedance-1-0-pro-fast` | general faster generation |
| `doubao-seedance-1-5-pro` | higher-end version with room for later official capability expansion |
| `doubao-seedance-2-0` | official Seedance 2.0 multimodal video generation |
| `doubao-seedance-2-0-fast` | official Seedance 2.0 Fast multimodal video generation |
## Submit a Video Task
```
POST /volc/v1/contents/generations/tasks
```
### Current Public Request Parameters
| Parameter | Type | Required | Description |
| ------------------------- | ------- | ------------- | -------------------------------------------------------------------------------------------------------------- |
| `model` | string | Yes | Public model name. Use one of the canonical model names above |
| `content` | array | Yes | Input content array |
| `content[].type` | string | Yes | Supported values are `text`, `image_url`, `video_url`, `audio_url`, and `draft_task` |
| `content[].text` | string | Conditionally | Required when `type=text` |
| `content[].image_url.url` | string | Conditionally | Required when `type=image_url` |
| `content[].video_url.url` | string | Conditionally | Required when `type=video_url` |
| `content[].audio_url.url` | string | Conditionally | Required when `type=audio_url` |
| `content[].role` | string | Optional | Seedance 2.0 supports `first_frame`, `last_frame`, `reference_image`, `reference_video`, and `reference_audio` |
| `generate_audio` | boolean | Optional | Whether to generate audio on Seedance 2.0 |
| `ratio` | string | Optional | Output aspect ratio such as `16:9` |
| `resolution` | string | Optional | Seedance 2.0 / 2.0 fast currently supports only `480p` and `720p` |
| `duration` | integer | Optional | Seedance 2.0 / 2.0 fast supports `4-15` or `-1` |
| `watermark` | boolean | Optional | Whether to add watermark |
| `seed` | integer | Optional | Random seed |
### Seedance 2.0 Official Capability Boundary
* Supports four input modalities: text, image, video, and audio.
* Supports multimodal references: up to `9` images, `3` videos, and `3` audios, with a mixed file limit of `12`.
* Image formats: `jpeg`, `png`, `webp`, `bmp`, `tiff`, `gif`; each image must stay under `30MB`.
* Video formats: `mp4`, `mov`; up to `3` video references, recommended combined duration in `[2, 15]s`, total file size under `50MB`.
* Audio formats: `mp3`, `wav`; up to `3` audio references, combined duration `<= 15s`, total file size under `15MB`.
* Audio cannot be provided alone. At least `1` image or video reference is required with it.
* Output duration supports `4-15s`, and `-1` can be passed through to let the upstream use its default behavior.
* Supports `480p` and `720p`; `1080p` is currently unsupported on Seedance 2.0 / 2.0 fast.
* `frames` is currently unsupported for Seedance 2.0 / 2.0 fast.
* `camera_fixed` is currently unsupported for Seedance 2.0 / 2.0 fast.
* In the product UI, Seedance 2.0 is currently exposed mainly as “first/last frame” and “omni reference” entry points; on the API side those semantics map to `content[].role` and `content[].type`.
* Upstream compliance currently blocks clearly realistic human-face image or video uploads.
### Official Seedance 2.0 Pricing Truth
| Model | Official billing mode | Official price |
| -------------------------- | --------------------- | --------------------------------------------------------------------------------------------- |
| `doubao-seedance-2-0` | per output token | `28 CNY / 1M output tokens` with video input; `46 CNY / 1M output tokens` without video input |
| `doubao-seedance-2-0-fast` | per output token | `22 CNY / 1M output tokens` with video input; `37 CNY / 1M output tokens` without video input |
MIME, duration, and file-size enforcement for remote URL assets is ultimately handled by the upstream. Crazyrouter currently pre-validates count limits, duration parameter boundaries, the no-audio-only rule, and explicit unsupported fields such as `frames`, `camera_fixed`, and non-480p/720p output requests.
### Text-to-Video Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/volc/v1/contents/generations/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-seedance-1-0-lite-t2v",
"content": [
{
"type": "text",
"text": "A slow push-in shot of a white seagull skimming over the ocean with golden sunset reflections on the waves"
}
]
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/volc/v1/contents/generations/tasks",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "doubao-seedance-1-0-lite-t2v",
"content": [
{
"type": "text",
"text": "A slow push-in shot of a white seagull skimming over the ocean with golden sunset reflections on the waves"
}
]
}
)
print(response.json())
```
### Single-Image Image-to-Video Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/volc/v1/contents/generations/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-seedance-1-0-lite-i2v",
"content": [
{
"type": "text",
"text": "The subject turns naturally while wind lightly moves the hair"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/portrait.png"
}
}
]
}'
```
### Seedance 2.0 Multimodal Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/volc/v1/contents/generations/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-seedance-2-0",
"content": [
{
"type": "text",
"text": "A girl turns back on the beach at sunset, with more cinematic motion and natural ambient sound"
},
{
"type": "image_url",
"image_url": {
"url": "https://example.com/first-frame.png"
},
"role": "reference_image"
},
{
"type": "video_url",
"video_url": {
"url": "https://example.com/reference-video.mp4"
},
"role": "reference_video"
},
{
"type": "audio_url",
"audio_url": {
"url": "https://example.com/reference-audio.mp3"
},
"role": "reference_audio"
}
],
"generate_audio": true,
"ratio": "16:9",
"duration": 11,
"watermark": false
}'
```
### Successful Submit Response
```json theme={null}
{
"id": "cgt_task_abc123",
"task_id": "cgt_task_abc123"
}
```
***
## Query Task
```
GET /volc/v1/contents/generations/tasks/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/volc/v1/contents/generations/tasks/cgt_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Completed Response Example
```json theme={null}
{
"id": "cgt_task_abc123",
"object": "video",
"model": "doubao-seedance-1-0-lite-t2v",
"status": "completed",
"progress": 100,
"created_at": 1774580000,
"completed_at": 1774580030,
"seconds": "5",
"metadata": {
"url": "https://media.crazyrouter.com/task-artifacts/2026/03/28/seedance/cgt_task_abc123.mp4",
"artifact_url": "https://media.crazyrouter.com/task-artifacts/2026/03/28/seedance/cgt_task_abc123.mp4",
"resolution": "720p",
"ratio": "16:9",
"frames_per_second": 24
}
}
```
### Task Status
| Status | Description |
| ------------- | --------------------------------------- |
| `queued` | submitted or waiting in queue |
| `in_progress` | generation in progress |
| `completed` | completed and ready from `metadata.url` |
| `failed` | terminal failure |
The public docs now only commit to the native `/volc/v1/*` route family and canonical model names. The old `seedance-lite` label is retained only as historical context, not as the primary contract for new integrations.
The official Seedance pricing truth is currently tracked as `per_output_token`, not per-second. If the pricing page later shows a normalized platform billing unit, that should be treated as the platform sell-side view rather than the native official unit.
# Sora
Source: https://docs.crazyrouter.com/en/video/sora
Generate videos with OpenAI Sora models through the verified public unified video API, Video Generations API, and OpenAI-compatible video format
# Sora
For public Crazyrouter docs, the recommended verified Sora routes are:
* `POST /v1/video/create` with `GET /v1/video/query`
* `POST /v1/video/generations` with `GET /v1/video/generations/{task_id}`
* `POST /v1/videos` with `GET /v1/videos/{task_id}`
If this is your first Sora integration, start with `POST /v1/video/generations`. It has clearer task-state fields and is now documented in dedicated route pages as part of this update round.
## Model Selection
| Model | Description | Speed | Quality | Recommended Use |
| ------------ | ------------------------------------ | ------ | ------- | ----------------------------------- |
| `sora-2` | Second-generation standard model | Medium | High | Production and day-to-day usage |
| `sora-2-pro` | Second-generation professional model | Slower | Highest | Professional work and finer control |
## Recommended Main Path: Video Generations API
```
POST /v1/video/generations
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/generations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "sora-2",
"prompt": "A serene Japanese garden in spring, with cherry blossoms gently falling",
"size": "1280x720",
"duration": 5
}'
```
Query the task:
```
GET /v1/video/generations/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/v1/video/generations/video_123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### When to use this route
* first-pass Sora integration
* clearer task status and metadata
* teams that want to follow the new dedicated Crazyrouter video compatibility pages
## Unified Video API
```
POST /v1/video/create
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "sora-2",
"prompt": "A cat playing piano in a jazz club, cinematic lighting",
"aspect_ratio": "16:9"
}'
```
Query the task:
```
GET /v1/video/query?task_id=your_task_id
```
```bash cURL theme={null}
curl "https://crazyrouter.com/v1/video/query?task_id=your_task_id" \
-H "Authorization: Bearer YOUR_API_KEY"
```
## OpenAI-Compatible Video Format
```
POST /v1/videos
```
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/videos \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "sora-2",
"prompt": "A cat playing piano in a jazz club, cinematic lighting",
"size": "1920x1080",
"duration": 10
}'
```
Query the task:
```
GET /v1/videos/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/v1/videos/sora_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
## Status And Result Fields
Common task states:
| Status | Meaning |
| ------------- | --------------------- |
| `queued` | Submitted and waiting |
| `in_progress` | Generating |
| `completed` | Finished |
| `failed` | Failed |
Common result fields:
* `url` or `video_url`: video download URL
* `thumbnail_url`: preview thumbnail
* `progress`: generation progress
* `expires_at`: expiration time for the temporary result URL
Result URLs are usually not permanent. Download the video promptly instead of treating the returned URL as long-term storage.
## Recommended Rollout Order
1. Start with `sora-2`
2. Start with a short 5-10 second video
3. Validate one simple text-to-video request first
4. Add higher resolution, longer duration, or more advanced parameters later
5. Switch to `sora-2-pro` only after the basic path is stable
## Practical Notes
* Do not assume every more complex native field is part of the stable public baseline
* If you need route-specific `Video Generations` examples, prefer the new dedicated pages added in this docs round
* If you are only checking connectivity, validate with a short prompt and short duration first
This page keeps the public Sora overview concise. More specific compatibility-route details have been split into dedicated video docs so each route can be maintained more accurately.
# Unified Video API
Source: https://docs.crazyrouter.com/en/video/unified
Crazyrouter unified video generation endpoint, supporting multiple models through a single API format
# Unified Video API
Crazyrouter provides a unified video generation endpoint that supports multiple video models through the same API format.
`Seedance` is no longer recommended on the unified `/v1/video/*` contract. Use the native `/volc/v1/contents/generations/tasks` surface instead. See [Seedance](/en/video/seedance).
## Supported Models
| Model | Description |
| ---------------------------- | ---------------------- |
| `veo-3.1-fast` | Google Veo 3.1 Fast |
| `veo-3.1` | Google Veo 3.1 Quality |
| `grok-video-3` | xAI Grok Video |
| `wan-ai/wan2.1-t2v-14b` | Wan text-to-video |
| `wan-ai/wan2.1-i2v-14b-720p` | Wan image-to-video |
***
## Create Video
```
POST /v1/video/create
```
### Request Parameters
| Parameter | Type | Required | Description |
| -------------- | ------- | -------- | -------------------------------------------------------------- |
| `model` | string | Yes | Model name |
| `prompt` | string | Yes | Video description prompt |
| `aspect_ratio` | string | No | Aspect ratio: `16:9`, `9:16`, `1:1` |
| `size` | string | No | Video size, e.g. `1280x720` |
| `images` | array | No | For the current public image-to-video path, pass one image URL |
| `duration` | integer | No | Video duration (seconds) |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "veo-3.1",
"prompt": "A golden retriever running on the beach, slow motion, cinematic quality",
"aspect_ratio": "16:9"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/video/create",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "veo-3.1",
"prompt": "A golden retriever running on the beach, slow motion, cinematic quality",
"aspect_ratio": "16:9"
}
)
data = response.json()
task_id = data["id"]
print(f"Task ID: {task_id}")
```
### Create Response
```json theme={null}
{
"id": "video_task_abc123",
"status": "processing",
"status_update_time": 1709123456
}
```
***
## Image-to-Video
Pass reference images in the `images` parameter:
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "wan-ai/wan2.1-i2v-14b-720p",
"prompt": "The person in the image starts smiling and waving",
"images": ["https://example.com/portrait.jpg"],
"aspect_ratio": "16:9"
}'
```
***
## Query Task
```
GET /v1/video/query?id={task_id}
```
### Request Example
```bash cURL theme={null}
curl "https://crazyrouter.com/v1/video/query?id=video_task_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Query Response (Processing)
```json theme={null}
{
"id": "video_task_abc123",
"status": "processing",
"status_update_time": 1709123460
}
```
### Query Response (Completed)
```json theme={null}
{
"id": "video_task_abc123",
"status": "completed",
"status_update_time": 1709123520,
"video_url": "https://crazyrouter.com/files/video_abc123.mp4"
}
```
### Task Status
| Status | Description |
| ------------ | ----------- |
| `processing` | Processing |
| `completed` | Completed |
| `failed` | Failed |
***
## Complete Workflow Example
```python Python theme={null}
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://crazyrouter.com"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
# 1. Create video task
resp = requests.post(f"{BASE_URL}/v1/video/create", headers=headers, json={
"model": "veo-3.1",
"prompt": "A golden retriever running on the beach, slow motion",
"aspect_ratio": "16:9"
})
task_id = resp.json()["id"]
print(f"Task created: {task_id}")
# 2. Poll for status
while True:
resp = requests.get(f"{BASE_URL}/v1/video/query?id={task_id}", headers=headers)
result = resp.json()
status = result["status"]
print(f"Status: {status}")
if status == "completed":
print(f"Video URL: {result['video_url']}")
break
elif status == "failed":
print("Video generation failed")
break
time.sleep(10)
```
Video generation typically takes 1-5 minutes. A polling interval of 10 seconds is recommended.
# Veo 3.1
Source: https://docs.crazyrouter.com/en/video/veo
Use Veo 3.1 Fast and Veo 3.1 Quality through the Crazyrouter unified video API
# Veo 3.1
The currently public Crazyrouter Veo 3.1 model names are:
* `veo-3.1-fast`
* `veo-3.1`
These are customer-facing public aliases. Internal canonical provider names are not exposed to customers.
## Via Unified Video API
```
POST /v1/video/create
```
This page only covers the public capability surface that is already released:
* text-to-video
* single-image image-to-video
Provider-native `referenceImages`, style reference, and other Veo-specific modes are not part of the current public contract yet.
### Current Public Models
| Model | Description |
| -------------- | --------------------------------------------------------------- |
| `veo-3.1-fast` | Lower-latency option for getting the first usable result faster |
| `veo-3.1` | Quality-first option for the default public path |
### Capability Status
| Capability / Spec | Status | Notes |
| ------------------------------------------ | ---------- | ------------------------------------------------------------------------ |
| text-to-video `720P / 1080P` | `Verified` | Closed in the current public contract |
| single-image image-to-video `720P / 1080P` | `Verified` | Closed in the current public contract |
| audio-enabled rows | `Beta` | The official capability exists, but the public artifact is still pending |
| `start_end` | `Beta` | Not committed on the current public page |
| `referenceImages` / reference assets | `Beta` | Not committed on the current public page |
| `4K` | `Beta` | Not committed on the current public page |
The Pricing page and this doc use the same status language: `Verified` means there is a current minimal live artifact, while `Beta` means the official capability exists but the public validation set or edge coverage is still being completed.
### Request Parameters
| Parameter | Type | Required | Description |
| -------------- | ------- | -------- | --------------------------------------------------------------------- |
| `model` | string | Yes | `veo-3.1-fast` or `veo-3.1` |
| `prompt` | string | Yes | Video prompt |
| `aspect_ratio` | string | No | Publicly recommended: `16:9` or `9:16` |
| `size` | string | No | Publicly recommended: `720P` or `1080P` |
| `images` | array | No | Pass exactly one image URL for the current public image-to-video flow |
| `duration` | integer | No | Common value: `8` |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "veo-3.1",
"prompt": "A cinematic shot of a spaceship landing on Mars, dust clouds rising, golden hour lighting",
"aspect_ratio": "16:9"
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/v1/video/create",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "veo-3.1",
"prompt": "A cinematic shot of a spaceship landing on Mars",
"aspect_ratio": "16:9"
}
)
task_id = response.json()["id"]
print(f"Task ID: {task_id}")
```
### Response Example
```json theme={null}
{
"id": "veo_task_abc123",
"status": "processing",
"status_update_time": 1709123456
}
```
***
## Single-Image Image-to-Video Example
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/v1/video/create \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "veo-3.1-fast",
"prompt": "The person in the image slowly turns their head and smiles",
"images": ["https://example.com/portrait.jpg"],
"aspect_ratio": "9:16",
"size": "720P"
}'
```
***
## Query Task
```
GET /v1/video/query?id={task_id}
```
```bash cURL theme={null}
curl "https://crazyrouter.com/v1/video/query?id=veo_task_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example (Completed)
```json theme={null}
{
"id": "veo_task_abc123",
"status": "completed",
"status_update_time": 1709123520,
"video_url": "https://crazyrouter.com/files/veo_abc123.mp4"
}
```
Google's official Veo 3.1 docs also describe `reference asset images` and other provider-native capability details. The current Crazyrouter public page intentionally stays narrower: it only commits to text-to-video and single-image image-to-video under `veo-3.1-fast` and `veo-3.1`. Additional Veo capability pages should be published only after the public route and validation artifacts are ready.
# Volcengine
Source: https://docs.crazyrouter.com/en/video/volcengine
Use the Volcengine API to generate videos
# Volcengine
Volcengine provides video generation capabilities from ByteDance.
## Create Video Task
```
POST /volc/v1/contents/generations/tasks
```
### Request Parameters
| Parameter | Type | Required | Description |
| ---------------------- | ------ | -------- | ------------------------ |
| `model` | string | Yes | Model name |
| `content` | object | Yes | Content configuration |
| `content.prompt` | string | Yes | Video description prompt |
| `content.image_url` | string | No | Reference image URL |
| `content.aspect_ratio` | string | No | Aspect ratio |
### Request Examples
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/volc/v1/contents/generations/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "doubao-video",
"content": {
"prompt": "A butterfly fluttering among flowers, macro lens shot",
"aspect_ratio": "16:9"
}
}'
```
```python Python theme={null}
import requests
response = requests.post(
"https://crazyrouter.com/volc/v1/contents/generations/tasks",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"
},
json={
"model": "doubao-video",
"content": {
"prompt": "A butterfly fluttering among flowers, macro lens shot",
"aspect_ratio": "16:9"
}
}
)
print(response.json())
```
### Response Example
```json theme={null}
{
"code": 0,
"message": "success",
"data": {
"task_id": "volc_task_abc123"
}
}
```
***
## Query Task
```
GET /volc/v1/contents/generations/tasks/{task_id}
```
```bash cURL theme={null}
curl https://crazyrouter.com/volc/v1/contents/generations/tasks/volc_task_abc123 \
-H "Authorization: Bearer YOUR_API_KEY"
```
### Response Example (Completed)
```json theme={null}
{
"code": 0,
"message": "success",
"data": {
"task_id": "volc_task_abc123",
"status": "SUCCESS",
"content": {
"video_url": "https://cdn.volcengine.com/videos/...",
"duration": 5
}
}
}
```
### Task Status
| Status | Description |
| ------------ | ----------- |
| `SUBMITTED` | Submitted |
| `PROCESSING` | Processing |
| `SUCCESS` | Succeeded |
| `FAILED` | Failed |
# Wan Video
Source: https://docs.crazyrouter.com/en/video/wan
Wan video family overview. Customers use the Ali Bailian-compatible contract while Crazyrouter can route to official or third-party providers internally
# Wan Video
The Wan family is currently exposed through the Ali Bailian-compatible public contract:
* `POST /alibailian/api/v1/services/aigc/video-generation/video-synthesis`
* `GET /alibailian/api/v1/tasks/{task_id}`
For the full request and task-query schema, see [Ali Bailian Video API](/en/video/alibailian). This page closes only the first batch of public `Wan` models, capabilities, and billing truth.
## First-Batch Models
| Model | Customer-facing capability | Official billing truth | Current state |
| -------------------- | -------------------------- | ---------------------- | ------------- |
| `wan2.5-t2v-preview` | text-to-video | per second | verified |
| `wan2.5-i2v-preview` | image-to-video | per second | verified |
| `wan2.2-t2v-plus` | text-to-video | per second | verified |
| `wan2.2-i2v-plus` | image-to-video | per second | verified |
| `wan2.2-i2v-flash` | image-to-video | per second | verified |
| `wan2.2-kf2v-flash` | first-last-frame video | per second | Beta |
| `wan2.2-s2v` | subject-reference video | per second | Beta |
`wan2.2-kf2v-flash` and `wan2.2-s2v` are already aligned in code and billing capability buckets, but their live artifact closure is still in progress, so they remain Beta.
## Capabilities And Official Prices
| Model | Capability bucket | Resolution | Official price |
| -------------------- | ----------------------- | --------------------- | ----------------------------- |
| `wan2.5-t2v-preview` | text-to-video | `480P / 720P / 1080P` | `¥0.30 / ¥0.60 / ¥1.00 / sec` |
| `wan2.5-i2v-preview` | image-to-video | `480P / 720P / 1080P` | `¥0.30 / ¥0.60 / ¥1.00 / sec` |
| `wan2.2-t2v-plus` | text-to-video | `480P / 1080P` | `¥0.14 / ¥0.70 / sec` |
| `wan2.2-i2v-plus` | image-to-video | `480P / 1080P` | `¥0.14 / ¥0.70 / sec` |
| `wan2.2-i2v-flash` | image-to-video | `480P / 720P / 1080P` | `¥0.10 / ¥0.20 / ¥0.48 / sec` |
| `wan2.2-kf2v-flash` | first-last-frame video | `480P / 720P / 1080P` | `¥0.10 / ¥0.20 / ¥0.48 / sec` |
| `wan2.2-s2v` | subject-reference video | `480P / 720P` | `¥0.50 / ¥0.90 / sec` |
## Protocol Conventions
### 1. Text-to-video
* Key fields: `model`, `input.prompt`, `parameters.resolution`, `parameters.duration`
* Typical models: `wan2.5-t2v-preview`, `wan2.2-t2v-plus`
### 2. Image-to-video
* Key field: `input.img_url`
* Typical models: `wan2.5-i2v-preview`, `wan2.2-i2v-plus`, `wan2.2-i2v-flash`
### 3. First-last-frame video
* Key fields: `input.first_frame_url`, `input.last_frame_url`
* Typical model: `wan2.2-kf2v-flash`
### 4. Subject-reference video
* Key field: `input.image_url`
* Typical model: `wan2.2-s2v`
## Request Examples
### Image-to-video
```bash cURL theme={null}
curl -X POST https://crazyrouter.com/alibailian/api/v1/services/aigc/video-generation/video-synthesis \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"model": "wan2.5-i2v-preview",
"input": {
"prompt": "Make the subject turn toward the camera",
"img_url": "https://example.com/first-frame.png"
},
"parameters": {
"resolution": "720P",
"duration": 5,
"prompt_extend": true,
"audio": true
}
}'
```
### First-last-frame video
```json theme={null}
{
"model": "wan2.2-kf2v-flash",
"input": {
"prompt": "A smooth transition from day to night",
"first_frame_url": "https://example.com/frame-start.png",
"last_frame_url": "https://example.com/frame-end.png"
},
"parameters": {
"resolution": "720P",
"duration": 5
}
}
```
### Subject-reference video
```json theme={null}
{
"model": "wan2.2-s2v",
"input": {
"prompt": "Animate the reference portrait with light natural speaking motion",
"image_url": "https://example.com/portrait.png",
"audio_url": "https://example.com/voice.mp3"
},
"parameters": {
"resolution": "720P",
"duration": 5
}
}
```
## Task Retrieval
Wan remains an async task family. After creation, query:
```http theme={null}
GET /alibailian/api/v1/tasks/{task_id}
```
When `output.task_status` reaches success, use `output.video_url` as the final video result.
## Scope Notes
* The customer-facing contract is the Ali Bailian-compatible path. The old Fal-only route description is no longer the source of truth.
* Crazyrouter can internally route to official, ApiPass, Kie, or other third-party providers, but those providers do not define customer protocols.
* Beta rows can still be shown publicly now; after launch, use production task logs to close live evidence and then remove the Beta label.