Generating through a Model Router
Once you’ve created a configuration, you route a generation by calling the generate endpoint for your modality with your config ID in the configId field and a model-agnostic input payload:
| Modality | Endpoint |
|---|---|
| Video | POST /v1/generate/video |
| Image | POST /v1/generate/image |
| Audio | POST /v1/generate/audio |
The router filters to eligible models for that modality, selects one according to your optimization preference, generates the output, and returns the result along with metadata about the model it chose.
Generate video
Section titled “Generate video”Pass your config ID in the configId field and put generation options under input. You don’t specify a model — the router selects one for you.
import RunwayML, { TaskFailedError } from '@runwayml/sdk';
const client = new RunwayML();
// Route a video generation through a Model Router configtry { const task = await client.generate.video .create({ configId: 'preview-fast', input: { // Point this at your own image file referenceImages: [ { uri: 'https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg', role: 'first', }, ], promptText: 'A timelapse on a sunny day with clouds flying by', aspectRatio: '16:9', duration: 5, }, }) .waitForTaskOutput();
console.log('Task complete:', task);} catch (error) { if (error instanceof TaskFailedError) { console.error('The video failed to generate.'); console.error(error.taskDetails); } else { console.error(error); }}from runwayml import RunwayML, TaskFailedError
client = RunwayML()
# Route a video generation through a Model Router configtry: task = client.generate.video.create( config_id='preview-fast', input={ # Point this at your own image file 'reference_images': [ { 'uri': 'https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg', 'role': 'first', }, ], 'prompt_text': 'A timelapse on a sunny day with clouds flying by', 'aspect_ratio': '16:9', 'duration': 5, }, ).wait_for_task_output()
print('Task complete:', task)except TaskFailedError as e: print('The video failed to generate.') print(e.task_details)If you’re not ready to start writing code, you can test the API with cURL.
# Replace the config ID and example URL below with your owncurl -X POST https://api.dev.runwayml.com/v1/generate/video \ -d '{ "configId": "preview-fast", "input": { "referenceImages": [ { "uri": "https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg", "role": "first" } ], "promptText": "A timelapse on a sunny day with clouds flying by", "aspectRatio": "16:9", "duration": 5 } }' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"Generate image
Section titled “Generate image”Same pattern as video: configId plus an input object. Image input fields include promptText, optional referenceImages, aspectRatio, resolution, and outputCount. See the API reference for the full schema.
import RunwayML, { TaskFailedError } from '@runwayml/sdk';
const client = new RunwayML();
// Route an image generation through a Model Router configtry { const task = await client.generate.image .create({ configId: 'preview-fast', input: { promptText: 'A product photo of a ceramic mug on a marble counter, soft daylight', aspectRatio: '1:1', resolution: '2k', }, }) .waitForTaskOutput();
console.log('Task complete:', task);} catch (error) { if (error instanceof TaskFailedError) { console.error('The image failed to generate.'); console.error(error.taskDetails); } else { console.error(error); }}from runwayml import RunwayML, TaskFailedError
client = RunwayML()
# Route an image generation through a Model Router configtry: task = client.generate.image.create( config_id='preview-fast', input={ 'prompt_text': 'A product photo of a ceramic mug on a marble counter, soft daylight', 'aspect_ratio': '1:1', 'resolution': '2k', }, ).wait_for_task_output()
print('Task complete:', task)except TaskFailedError as e: print('The image failed to generate.') print(e.task_details)curl -X POST https://api.dev.runwayml.com/v1/generate/image \ -d '{ "configId": "preview-fast", "input": { "promptText": "A product photo of a ceramic mug on a marble counter, soft daylight", "aspectRatio": "1:1", "resolution": "2k" } }' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"Generate audio
Section titled “Generate audio”Audio uses POST /v1/generate/audio. Set input.type to speech (speak promptText as a script) or audio (treat promptText as a description of the desired sound). Optional fields include voice, referenceAudios, duration, and loop — see the API reference.
import RunwayML, { TaskFailedError } from '@runwayml/sdk';
const client = new RunwayML();
// Route an audio generation through a Model Router configtry { const task = await client.generate.audio .create({ configId: 'preview-fast', input: { type: 'speech', promptText: 'Welcome to the studio. Today we are testing routed audio.', }, }) .waitForTaskOutput();
console.log('Task complete:', task);} catch (error) { if (error instanceof TaskFailedError) { console.error('The audio failed to generate.'); console.error(error.taskDetails); } else { console.error(error); }}from runwayml import RunwayML, TaskFailedError
client = RunwayML()
# Route an audio generation through a Model Router configtry: task = client.generate.audio.create( config_id='preview-fast', input={ 'type': 'speech', 'prompt_text': 'Welcome to the studio. Today we are testing routed audio.', }, ).wait_for_task_output()
print('Task complete:', task)except TaskFailedError as e: print('The audio failed to generate.') print(e.task_details)curl -X POST https://api.dev.runwayml.com/v1/generate/audio \ -d '{ "configId": "preview-fast", "input": { "type": "speech", "promptText": "Welcome to the studio. Today we are testing routed audio." } }' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"Understand the response
Section titled “Understand the response”Every successful response includes metadata describing the routing decision, so you can debug behavior and understand why a model was chosen:
- The model that was actually used.
- The config ID that was applied.
- The optimization preference in effect.
- The realized cost of the generation, in credits.
You’re billed for the model the router selects, at that model’s standard rate. See Pricing for per-model rates.
Validate with a dry run
Section titled “Validate with a dry run”Today you can dry-run a Model Router request from the API or in the Developer Portal — SDK support is coming soon. Use dry-run requests to test a routing decision without generating or charging credits. To do so, call the generate endpoint with dryRun: true (curl or any raw HTTP client):
curl -X POST https://api.dev.runwayml.com/v1/generate/video \ -d '{ "configId": "preview-fast", "dryRun": true, "input": { "referenceImages": [ { "uri": "https://upload.wikimedia.org/wikipedia/commons/8/85/Tour_Eiffel_Wikimedia_Commons_(cropped).jpg", "role": "first" } ], "promptText": "A timelapse on a sunny day with clouds flying by", "aspectRatio": "16:9", "duration": 5 } }' \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $RUNWAYML_API_SECRET" \ -H "X-Runway-Version: 2024-11-06"A dry run returns the same metadata shape as a real generation — the model that would be used, the config ID and preference applied, and an estimated cost based on current pricing — but no asset is generated, stored, or returned, and the request is not billed as a generation. If the request and config together would produce a no eligible model error, the dry run returns that same error, so you see exactly what a real call would do.
Compose a tool loop
Section titled “Compose a tool loop”A reliable pattern for agents and automation:
- Create or update a config with
POST /v1/routers(or patch settings on an existing id). - Optionally dry-run with HTTP
dryRun: trueon the modality endpoint you’ll use live (/v1/generate/video,/v1/generate/image, or/v1/generate/audio) and the sameinputyou plan to use. - Read
routing.model,routing.estimatedCost, androuting.resolvedSettings— adjust the config or input if the choice or cost is wrong. - Call the live generate endpoint (SDK
generate.video.create,generate.image.create, orgenerate.audio.create, or HTTP withoutdryRun), then wait for the task (waitForTaskOutput/wait_for_task_output, or pollGET /v1/tasks/:id). - On a no eligible model error, widen the allowlist, raise that modality’s credit ceiling, or soften aspect/duration — then dry-run again.
Keep the dry-run and live payloads identical except for dryRun, so the routing decision you inspected matches what you bill.
No eligible model
Section titled “No eligible model”A request can fail if no model satisfies the configuration’s constraints and the request together. The error identifies which constraint(s) emptied the eligible pool — for example, your maximum credits per generation and the requested duration leaving nothing eligible.
To resolve it, update the configuration in the Developer Portal to adjust the constraints, commonly by adding additional enabled models or raising the maximum credits per generation for that modality. See Configuring a Model Router for the available settings.