API Reference

Every public route on api.magicrouter.ai, with parameters, examples, and response shapes. Schema follows the router's apps/router/app/v1/* handlers; bump this page when those change.

Authentication

All endpoints except /v1/models/live and /v1/pricing require an mr-… API key in the Authorization header: `Authorization: Bearer mr-your-key`. Generate and manage keys in the dashboard.

Chat Completions

POST/v1/chat/completionsAPI key (Bearer mr-…)

Create chat completion

OpenAI-compatible chat completion. Streaming (SSE), tool calling, vision (image_url content blocks), and JSON mode all supported. The full body schema mirrors OpenAI's /v1/chat/completions — see https://platform.openai.com/docs/api-reference/chat/create for every field. The router accepts and forwards unknown fields with extra="allow".

NameInTypeDescription
model*bodystringModel slug, e.g. "qwen/qwen3.7-max" or bare "qwen3.6-plus".
messages*bodyarrayStandard OpenAI messages array. `content` may be a string or a list of {type:"text"|"image_url", …} blocks for vision-capable models.
streambodybooleanStream the response as SSE chunks. Default false.
temperaturebodynumber0–2. Default 1.0.
top_pbodynumberNucleus sampling. Default 1.0.
top_kbodynumberForwarded to providers that support it. Ignored otherwise.
max_tokensbodynumberCap on completion tokens.
stopbodystring | string[]Up to 4 stop sequences.
frequency_penaltybodynumber−2.0 to 2.0.
presence_penaltybodynumber−2.0 to 2.0.
repetition_penaltybodynumberAlibaba-specific; forwarded when present.
response_formatbodyobject{ "type": "json_object" } enables JSON mode where supported.
toolsbodyarrayOpenAI tool/function-calling schema.
tool_choicebodystring | object"auto" | "none" | {type:"function", function:{name}}
seedbodynumberForwarded to providers that honor it.
userbodystringOpaque end-user id for abuse tracking.
Example request
curl https://api.magicrouter.ai/chat/completions \
  -H "Authorization: Bearer mr-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen/qwen3.7-max",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": false
  }'
Example response
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1747400000,
  "model": "qwen/qwen3.7-max",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "Hello! How can I help?"},
    "finish_reason": "stop"
  }],
  "usage": {"prompt_tokens": 9, "completion_tokens": 8, "total_tokens": 17}
}

Image Generation

POST/v1/images/generationsAPI key (Bearer mr-…)

Create image

Text-to-image and image-edit on a single endpoint. Pure text-to-image models ignore `image`/`images`; edit models (qwen-image-edit-plus / qwen-image-edit-max) require at least one reference image.

NameInTypeDescription
model*bodystringe.g. "qwen/qwen-image-2.0-pro", "qwen/qwen-image-edit-plus".
prompt*bodystringDescription of the image to generate.
nbodyintegerHow many images to generate. Default 1.
sizebodystringOutput dimensions, e.g. "1024x1024" or "1280*720".
qualitybodystring"standard" | "hd" — model-specific.
response_formatbodystring"url" (default) | "b64_json".
imagebodystringSingle reference image (HTTPS URL or data: URI) for image-to-image/edit models.
imagesbodystring[]1–3 reference images for multi-reference edit models. Takes precedence over `image`.
Example request
curl https://api.magicrouter.ai/images/generations \
  -H "Authorization: Bearer mr-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen/qwen-image-2.0-pro",
    "prompt": "A watercolor mountain village at dawn",
    "size": "1024x1024",
    "n": 1
  }'
Example response
{
  "created": 1747400000,
  "data": [
    { "url": "https://dashscope-result-…/output.png" }
  ]
}

Video Generation (Async)

Video generation is asynchronous: POST returns a task id immediately; GET the task id until status is "succeeded" (then video_url is populated) or "failed". Worst case ~10 min for 1080P / 15s.

POST/v1/videos/generationsAPI key (Bearer mr-…)

Submit video generation

Submit a text-to-video, image-to-video, first+last-frame, reference-image, or reference-video job across the Seedance, Wan, and HappyHorse families. The generation mode is inferred from which inputs you send — there is no separate mode flag. Returns a task id immediately; poll with GET /v1/videos/generations/{id}.

NameInTypeDescription
model*bodystringSeedance: doubao/seedance-2.5 (audio-capable, latest), doubao/seedance-2.0, doubao/seedance-2.0-fast, doubao/seedance-2.0-mini, doubao/seedance-1.5-pro (audio-capable). Wan: wan2.7-t2v, wan2.7-i2v, wan2.7-r2v, wan2.7-videoedit. HappyHorse: happyhorse-1.0-t2v, happyhorse-1.0-i2v.
prompt*bodystringText description of the shot. Sent as the text segment of the request; combine with image / ref_images / input_video for the non-t2v modes.
imagebodystringStarting frame (HTTPS URL or data: URI). Send it alone for image-to-video; the model animates from this frame.
last_imagebodystringOptional end frame. Send image + last_image together for first→last-frame interpolation (Seedance & wan2.7-i2v). Ignored by HappyHorse i2v.
ref_imagesbodystring[]Reference images for subject/style (URLs or data: URIs). Seedance reference-image mode accepts multiple; wan2.7-r2v takes up to 5 (reference_image + reference_video combined), wan2.7-videoedit up to 3.
input_videobodystringReference / source video. Seedance reference-video mode and wan2.7-videoedit source. Must be a public HTTP(S) URL — data: URI is not accepted for video.
durationbodyintegerLength in seconds (5s steps); the vendor rejects unsupported values. Seedance 2.5 = up to 30s; Seedance 2.0 = up to 15s; Wan / HappyHorse typically 3–15s. The API does not cap duration — it forwards your value to the vendor.
resolutionbodystring"480P" | "720P" | "1080P" | "4K". The API accepts all four; Seedance can render up to 4K (vendor-enforced per variant), Wan / HappyHorse cap at 1080P. Defaults to 720P. Pricing is per output tier.
ratiobodystringAspect ratio for text-to-video, e.g. "16:9" | "9:16" | "1:1". Defaults to 16:9. In image / reference modes the aspect is derived from the input frames.
generate_audiobodybooleanGenerate a synchronized audio track for the clip. Seedance 2.5 and Seedance 1.5-pro only; ignored by every other model. Defaults to false.
negative_promptbodystringWhat to avoid. Wan models only — not forwarded to Seedance.
prompt_extendbodybooleanProvider-side prompt rewriting. Wan only — not forwarded to Seedance.
watermarkbodybooleanProvider watermark toggle. Wan only — not forwarded to Seedance.
seedbodyintegerReproducibility seed. Wan where supported — not forwarded to Seedance.
Example request
curl https://api.magicrouter.ai/videos/generations \
  -H "Authorization: Bearer mr-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao/seedance-2.5",
    "prompt": "A panda surfing a tropical wave at sunset, cinematic slow-motion",
    "duration": 5,
    "resolution": "1080P",
    "ratio": "16:9",
    "generate_audio": true
  }'
Example response
{
  "id": "vid-abc123…",
  "status": "processing",
  "video_url": null,
  "created": 1747400000
}
Image-to-video (animate a still)
{
  "model": "doubao/seedance-2.5",
  "prompt": "The astronaut turns and waves at the camera",
  "image": "https://example.com/astronaut.jpg",
  "duration": 5,
  "resolution": "1080P"
}
First → last frame interpolation
{
  "model": "doubao/seedance-2.5",
  "prompt": "Smooth dolly-in between the two framings",
  "image": "https://example.com/frame_start.jpg",
  "last_image": "https://example.com/frame_end.jpg",
  "duration": 5,
  "resolution": "720P"
}
Reference images (subject / style)
{
  "model": "doubao/seedance-2.5",
  "prompt": "This character skateboarding through a neon city",
  "ref_images": [
    "https://example.com/character_a.jpg",
    "https://example.com/character_b.jpg"
  ],
  "resolution": "1080P"
}
Reference video (motion / style transfer)
{
  "model": "doubao/seedance-2.5",
  "prompt": "Same camera move, but on a snowy mountain road",
  "input_video": "https://example.com/reference_clip.mp4",
  "duration": 5,
  "resolution": "720P"
}
Text-to-video with synced audio (Seedance 2.5)
{
  "model": "doubao/seedance-2.5",
  "prompt": "A thunderstorm rolls over the ocean, waves crashing",
  "duration": 10,
  "resolution": "1080P",
  "ratio": "16:9",
  "generate_audio": true
}
GET/v1/videos/generations/{task_id}API key (Bearer mr-…)

Poll video status

Returns the current status of an in-flight or completed task. video_url is set when status="succeeded". On "failed", error_code and error_message describe the upstream rejection.

NameInTypeDescription
task_id*pathstringTask id returned by the submit call.
Example request
curl https://api.magicrouter.ai/videos/generations/vid-abc123 \
  -H "Authorization: Bearer mr-your-key"
Example response
{
  "id": "vid-abc123…",
  "status": "succeeded",
  "video_url": "https://dashscope-result-…/output.mp4",
  "duration_seconds": 5.0,
  "created": 1747400000
}

Audio (Text-to-Speech)

POST/v1/audio/speechAPI key (Bearer mr-…)

Create TTS audio

OpenAI-compatible TTS. Returns the audio bytes directly with the appropriate Content-Type.

NameInTypeDescription
model*bodystringTTS model id (Qwen TTS or compatible).
input*bodystringText to synthesize.
voicebodystringVoice id. Default "alloy".
speedbodynumber0.25–4.0. Default 1.0.
response_formatbodystring"mp3" (default) | "wav" | "opus".
Example request
curl https://api.magicrouter.ai/audio/speech \
  -H "Authorization: Bearer mr-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-tts",
    "input": "Hello from MagicRouter",
    "voice": "alloy",
    "response_format": "mp3"
  }' \
  --output speech.mp3
Example response
(binary audio body; Content-Type: audio/mpeg | audio/wav | audio/opus)

Models

GET/v1/modelsAPI key (Bearer mr-…)

List models (registry)

OpenAI-shaped list of every model in the static registry merged with the live model catalog (static wins on collision). Add ?details=1 to include providers + pricing.

NameInTypeDescription
detailsquerybooleanWhen 1, each entry includes a providers[] array with input_per_m, output_per_m.
Example request
curl https://api.magicrouter.ai/models?details=1 \
  -H "Authorization: Bearer mr-your-key"
Example response
{
  "object": "list",
  "data": [
    {
      "id": "qwen/qwen3.7-max",
      "object": "model",
      "created": 1747400000,
      "owned_by": "qwen3.7",
      "providers": [
        {"input_per_m": 2.5, "output_per_m": 7.5}
      ]
    }
  ]
}
GET/v1/models/livePublic

Live model catalog

Categorized chat / image / video model id lists. Refreshed hourly from the upstream catalog, with video models the upstream compat-mode endpoint doesn't expose patched in. Returns 503 + Retry-After: 10 on a cold cache.

Example request
curl https://api.magicrouter.ai/models/live
Example response
{
  "chat":  ["qwen3.8-max", "qwen3.7-max", "qwen3.6-plus", …],
  "image": ["qwen-image-2.0-pro", "wan2.7-image", …],
  "video": ["happyhorse-1.0-t2v", "wan2.7-t2v", …],
  "total": 72,
  "synced_at": "2026-05-24T05:00:00Z"
}

Pricing

GET/v1/pricingPublic

Get pricing map

Per-model pricing for all providers, in both `intl` (USD) and `cn` (USD converted from CNY). Chat uses input_per_m + output_per_m (per 1M tokens). Images use output_per_m (per image). Videos use output_per_m (per second, flat) + output_per_m_by_tier (per resolution tier). Cache-Control: public, max-age=300, stale-while-revalidate=600.

Example request
curl https://api.magicrouter.ai/pricing
Example response
{
  "models": {
    "qwen/qwen3.7-max": {
      "id": "qwen/qwen3.7-max",
      "modality": "text",
      "family": "qwen3.7",
      "providers": [{
        "intl": { "input_per_m": 2.5, "output_per_m": 7.5 },
        "cn":   { "input_per_m": 1.7647, "output_per_m": 5.2941 }
      }]
    }
  }
}

Credits & Billing

GET/v1/credits/balanceAPI key (Bearer mr-…)

Get credit balance

Current credit balance for the authenticated user. /v1/billing/balance is an alias of this endpoint.

Example request
curl https://api.magicrouter.ai/credits/balance \
  -H "Authorization: Bearer mr-your-key"
Example response
{ "balance": 12.345, "auto_topup_enabled": false }
GET/v1/billing/balanceAPI key (Bearer mr-…)

Get balance (alias)

Alias of /v1/credits/balance. Identical response shape.

GET/v1/billing/transactionsAPI key (Bearer mr-…)

List recent transactions

Paginated list of the user's credit transactions, newest first.

NameInTypeDescription
limitqueryinteger1–500. Default 50.
offsetqueryinteger≥0. Default 0.
Example request
curl "https://api.magicrouter.ai/billing/transactions?limit=10" \
  -H "Authorization: Bearer mr-your-key"
GET/v1/billing/analyticsAPI key (Bearer mr-…)

Usage analytics

Aggregates the user's usage_events over a rolling window into by-day, by-model, by-source breakdowns. Powers the dashboard's usage graphs.

NameInTypeDescription
daysqueryinteger1–365. Default 30.
Example request
curl "https://api.magicrouter.ai/billing/analytics?days=30" \
  -H "Authorization: Bearer mr-your-key"
Example response
{
  "window_days": 30,
  "by_day":    [{ "day": "2026-05-23", "requests": 412, "tokens_in": 18203, "tokens_out": 6442 }],
  "by_model":  [{ "model": "qwen/qwen3.6-plus", "requests": 200, "cost": 0.0834 }],
  "by_source": [{ "source": "sdk", "requests": 380, "cost": 0.42 }]
}
* required. All endpoints live under https://api.magicrouter.ai. Authenticated endpoints accept the API key as Authorization: Bearer mr-….
MagicRouter — One-Stop Marketplace for Tokens at the Best Price