Skip to content

Media generation (video, images, music) ​

NordRouter can generate images, video, and music using the same sk-nr-… key and balance as text models. Pay per generation, with no tokens or packages.

Send requests from your backend only, not from the browser

You cannot call /media/* directly from the browser — the request will fail the CORS check and return Failed to fetch.

This is intentional. The endpoint requires your key in the Authorization header, and everything sent to the browser is visible to anyone who opens developer tools: your key will be exposed, allowing others to spend your balance. No headers in fetch can prevent this.

The correct flow:

browser → your server (the key stays here) → nordrouter.com

The generated file is served via a regular link — you can use it directly in <img src> or <video src> on your page without any additional configuration.

How it works ​

Generation is asynchronous (video and music take anywhere from a few seconds to a couple of minutes):

  1. Create a job — POST /media/generate with the model and parameters.
  2. Wait for the result — poll GET /media/job/:id until status becomes done.
  3. Retrieve the file — via result_url (a link on nordrouter.com).

1. Create a job ​

bash
curl https://nordrouter.com/media/generate \
  -H "Authorization: Bearer sk-nr-YOUR-KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "image/nano-banana-2",
    "input": { "prompt": "a cozy cabin in a winter forest, watercolor", "resolution": "2k" }
  }'

Response:

json
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
  "poll": "https://nordrouter.com/media/job/beefb531-…" }

Errors always use the same format: { "error": "понятный текст", "code": "missing_param" }. Use code to branch in your code (invalid_input, missing_param, unknown_model, insufficient_balance, rate_limited, no_auth…); error is a human-readable message.

2. Wait for the result ​

bash
curl https://nordrouter.com/media/job/beefb531-…
json
{ "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }

status: processing → done (or failed). The generated file is available at result_url.

🎵 Suno generates two tracks per job: the first is in result_url, the second in result_url_2 (the same link format). The price is per job and includes both tracks.

Webhooks (instead of polling) ​

To avoid polling, include the callback_url field in POST /media/generate, and we will send you the result via a POST request when the job finishes:

bash
curl https://nordrouter.com/media/generate \
  -H "Authorization: Bearer sk-nr-YOUR-KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "image/nano-banana-2",
    "input": { "prompt": "…" },
    "callback_url": "https://your-server.com/webhooks/nordrouter",
    "callback_secret": "ваш-секрет"
  }'

When the job reaches done/failed, a POST request is sent to callback_url with the same body returned by GET /media/job/:id, plus an event field:

json
{ "event": "media.completed", "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…", "cost_usd": 0.052, "error": null }

event: media.completed or media.failed.

Signature verification. If you set callback_secret, the X-NR-Signature header will contain sha256=<hmac> — an HMAC-SHA256 of the request body using your secret. Verify it to confirm that the request came from us:

python
import hmac, hashlib
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, request.headers["X-NR-Signature"])

Requirements and reliability:

  • callback_url must use https:// and a public address (internal/private IPs are rejected with a 400 error).
  • Up to 4 delivery attempts with increasing delays; return 2xx, otherwise we will retry.
  • Webhooks do not disable polling — you can combine both or use GET /media/job/:id as a fallback.

Learn more

For the job lifecycle, signature verification examples, and delivery reliability, see Jobs and webhooks.

3. List models and prices ​

GET /media/models returns the available models, their parameters, and estimated costs:

json
{ "models": [
    { "id": "image/nano-banana-2", "type": "image",
      "fields": [ {"name":"prompt","type":"textarea"}, {"name":"resolution","type":"select","options":["1k","2k","4k"]},
                  {"name":"safety_filter","type":"bool","default":true} ],
      "est_usd": 0.052 }
  ], "retention_days": 14 }

Full reference

For all models with their input parameters and prices, see Media: all models and billing.

Models ​

95 models are available — the full, up-to-date list with parameters and pricing is always available at GET /media/models. Main families:

TypeFamilyModes≈ price
🖼 ImagesNano Banana / 2 / Pro (image/nano-banana*)text→image, editing, up to 4Kfrom $0.025
🖼Imagen 4 Fast / Ultra (image/imagen4*)text→imagefrom $0.025
🖼GPT Image 1.5 / 2 (image/gpt-image-*)text→image, editing, up to 4Kfrom $0.025
🖼Flux 2 Pro / Flex (image/flux2-*)text→image, editingfrom $0.03
🖼Seedream v4 / 4.5 / 5 Lite (image/seedream-*)text→image, editingfrom $0.04
🖼Ideogram v3 / Character (image/ideogram-*)text, remix, characterfrom $0.02
🖼Qwen / Wan Image / Grok / Z-Imagetext→image, editingfrom $0.01
🛠 UtilitiesTopaz / Recraft (image/*upscale*, image/recraft-remove-bg)upscaling up to 8K, background removalfrom $0.01
🎬 VideoVeo 3.1 Lite / Fast / Quality (video/veo-3.1-*)text/photo→videofrom $0.19
🎬Kling 2.1 → 3.0 (video/kling-*)text/photo→video, motion, avatars, up to 4K and 15sfrom $0.16
🎬Wan 2.2 → 2.7 (video/wan-*)text/photo/video→video, speech-to-videofrom $0.25
🎬Seedance 1.5 / 2 / Fast / Mini (video/seedance-*)text/photo→video, up to 4K, audiofrom $0.06
🎬Hailuo 02 / 2.3 (video/hailuo-*)text/photo→videofrom $0.08
🎬HappyHorse 1.0 / 1.1 (video/happyhorse-*)text/photo/reference→video, video editingfrom $0.70
🎬Grok Video / 1.5 (video/grok-*)text/photo→video, up to 30sfrom $0.06
🎬Gemini Omni (video/gemini-omni)video with audio, up to 4Kfrom $0.39
🗣 AvatarsKling Avatar, OmniHuman, InfiniteTalk, Lip Syncphoto+audio→talking videofrom $0.19
🎵 MusicSuno V6 / V6 Wild / V6 Mini (music/suno-*)text/style→2 tracks, cover, continuation, vocals, stems, sounds~$0.08
🎙 SpeechElevenLabs Turbo / Multilingual (audio/elevenlabs-*)text→speech, voice isolationfrom $0.04 / 1000 chars

Parameters ​

Parameters depend on the model — the exact list is in /media/models (the fields field: name, type, options, default). Names use a consistent style (snake_case), and values are lowercase. Common parameters:

  • prompt — description (for all generative models).
  • resolution — 1k/2k/4k (images) or 480p/720p/768p/1080p/4k (video). Pricing depends on resolution.
  • aspect_ratio — 1:1, 16:9, 9:16, etc.; models with size selection also support 1:1-hd.
  • duration — video duration in seconds (5/10 for most models, up to 15 for Kling 3.0 and Wan 2.7, up to 30 for Grok). Video is billed per second.
  • audio — audio track in the video (true/false). Audio costs extra — the estimate from /media/estimate accounts for this.
  • mode / quality / render_mode — quality level (Kling 3.0 standard/pro/4k, GPT Image medium/high, Ideogram fast/balanced/quality).
  • safety_filter — adult content filter (enabled by default).
  • enhance_prompt — the model expands the prompt with more detail (Qwen, Flux 3).
  • file_format — file format (png/jpeg for images, glb/obj/fbx/stl/usdz for 3D).
  • image — input image (editing, photo→video; pass a direct link or upload via /media/upload).
  • video_url / audio_url — input video/audio (video-edit, lip sync, avatars).

Music: title, style, instrumental, version (v6, v6-wild, v6-mini), advanced (fine-tuning: custom title, style, and duration), exclude_styles, vocal (female/male), continue_from (the second to continue from); for sounds — loop, bpm, tonality; stem separation — mode (vocals, stems, track) and track (which track to extract). Fine-grained style controls: style_weight, weirdness, audio_weight (0…1).

Speech: text, voice (a short voice name from options, such as james, bella, Zephyr), speed; for Gemini models — style, pace, accent, voice_description, scene, temperature. A dialogue with two voices:

json
{ "model": "audio/gemini-3.1-flash-tts",
  "input": {
    "voices": [ { "voice": "Kore", "style": "newscaster" }, { "voice": "Puck", "pace": "fast" } ],
    "dialogue": [ { "speaker": 1, "text": "Hello! Our guest today is…" }, { "speaker": 2, "text": "Thanks for having me." } ]
  } }

To get the exact price for a specific configuration before running it, call POST /media/estimate with the same model + input.

Previous parameter names still work

On October 19, 2026, parameter names and values were standardized (snake_case, lowercase values). If your integration passes names and values from the previous version of the documentation, no changes are needed: the server accepts them too, with the same results and pricing. Only the new names and values appear in /media/models and this documentation.

🧊 3D Models ​

Generate 3D models from text or a photo. The output is GLB (plus OBJ, FBX, STL, USDZ, USD, or 3MF, depending on the model) and a preview image: each job returns multiple files, each with its own extension.

Use the same calls as for other media: POST /media/generate and poll GET /media/job/{id}.

bash
curl -X POST https://nordrouter.com/media/generate   -H "Authorization: Bearer $NR_KEY" -H "Content-Type: application/json"   -d '{"model":"3d/tripo-text","input":{"prompt":"ceramic mug, matte glaze"}}'
idinput≈ pricefeatures
3d/tripo-text, 3d/tripo-imagetext, photofrom $0.31lowest cost, quad mesh, PBR
3d/hunyuan-rapid-text, -imagetext, photofrom $0.43fast, 5 file formats
3d/seed3d-imagephotofrom $0.50GLB, OBJ, USD, USDZ
3d/hunyuan-pro-text, -imagetext, photofrom $0.71up to 1.5 million polygons
3d/meshy-text, -image, -multi-imagetext, photo, up to 4 viewsfrom $0.94textures up to 8K, character pose

Photo as a texture. The 3d/meshy-* models accept a separate image (texture_photo) or a material description (texture_text) — the texture is specified independently of the geometry. 3d/meshy-multi-image takes up to four views of the same object for more accurate geometry.

The price is known only after generation

3D generation is billed based on the resources actually used, so the exact amount is known only after the model has been generated. We reserve the maximum possible cost, then charge the actual amount and refund the difference once the calculation is complete. The final amount is always available in the cost_usd field.

In the studio, these models are marked with a badge, and generation starts only after you agree.

This takes time. 3D generation takes anywhere from half a minute to several minutes — longer than an image or a short video. You do not need to keep the job open: its status is saved, and webhooks are available.

Pricing and Storage ​

  • Your USD balance is charged the actual generation cost — the exact amount is available in cost_usd after completion.
  • Failed generations are not billed — the reserved amount is refunded automatically.
  • Files are stored on our servers for a limited time (see retention_days in /media/models) — download them to keep them.