Use rb.video() to generate videos. All video generation is asynchronous — submit a task, then poll for results. The SDK's .task() method handles polling automatically.

Quick start

import { RouterBrain } from '@router-brain/sdk';

const rb = new RouterBrain('sk-your-api-key');

// Submit task + auto-poll until complete
const result = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: 'Cinematic push-in shot of a night city street, neon lights, rain reflections',
  resolution: '720p',
  ratio: '16:9',
}).task({ pollInterval: 3000 });

console.log(result.task_status);   // 'success'
console.log(result.data[0]?.url);  // generated video URL

Submit a task only

If you want to handle polling yourself:

const created = await rb.video({
  model: 'wan2.1-t2v-turbo',
  prompt: 'A robot inspecting a Mars base',
  resolution: '720p',
}).json();

console.log(created.task_id); // use this to poll /video/v1/tasks/:task_id

Multi-modal input

rb.video() supports text, image, video, and audio input. Strings are treated as URLs. Objects use the VideoURL structure with a type role.

// Image-to-video
const imageResult = await rb.video({
  model: 'kling-v2-1-turbo',
  prompt: 'Make the person turn their head and smile',
  image: 'https://example.com/portrait.jpg',
  resolution: '720p',
}).task();

// Video reference input (Seedance modality_tokens billing uses this)
const videoResult = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: 'Continue from the reference video, keep characters and scene consistent',
  video: { type: 'reference_video', url: 'https://example.com/clip.mp4' },
  resolution: '720p',
}).task();

// Multiple reference images
const multiResult = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: 'Smooth transition between two reference frames',
  image: ['https://example.com/frame1.jpg', 'https://example.com/frame2.jpg'],
  resolution: '720p',
}).task();

Cancel polling

Pass an AbortSignal to stop polling.

const controller = new AbortController();
setTimeout(() => controller.abort(), 120000);

try {
  const result = await rb.video({
    model: 'wan2.1-t2v-turbo',
    prompt: '...',
  }).task({ signal: controller.signal });
} catch (err) {
  console.error('Task aborted or failed:', (err as Error).message);
}

Available methods

MethodReturnsWhen to use
json()Promise<VideoResponseJson>Submit a task — get task_id
task(opts?)Promise<VideoTaskResponseJson>Submit + auto-poll until success, failure, or cancellation
httpStatus()Promise<number>Check HTTP status before calling .json()

Request parameters

ParameterTypeRequiredDescription
modelstringYesModel code, e.g. wan2.1-t2v-turbo
promptstringYesText prompt
imagestring | string[] | VideoURL | VideoURL[]NoReference image(s)
videostring | string[] | VideoURL | VideoURL[]NoReference video(s)
audiostring | string[] | VideoURL | VideoURL[]NoReference audio
ratiostringNoAspect ratio: 16:9, 9:16, 1:1
resolutionstringNoResolution: 480p, 720p, 1080p, 4k
upstream_optionsRecord<string, any>NoProvider-specific parameters
headersRecord<string, string | string[]>NoCustom HTTP headers

Driver-specific parameters

Seedance (upstream_options)

const result = await rb.video({
  model: 'doubao-seedance-1-0-pro-250528',
  prompt: '...',
  upstream_options: {
    duration: 5,
    watermark: false,
    service_tier: 'default',
    seed: 42,
    generate_audio: true,
  },
}).task();

Bailian (upstream_options)

const result = await rb.video({
  model: 'kling-v2-1-turbo',
  prompt: '...',
  upstream_options: {
    duration: 5,
    watermark: false,
    seed: 123,
  },
}).task();

Task response structure

interface VideoTaskResponseJson {
  task_id: string;
  task_status: 'pending' | 'running' | 'success' | 'failed' | 'cancelled';
  model: string;
  created: number | null;    // timestamp (ms)
  updated: number | null;    // timestamp (ms)
  completed: number | null;  // timestamp (ms)
  data: VideoTaskData[];     // [{ url: "..." }] on success
  error: VideoTaskError | null; // { code, message } on failure
}

Billing methods

MethodDriverUnit
durationBailiancredits/second of output video
modality_tokensSeedancecredits/token, with separate prices for requests with vs. without video input

Use rb.models('video') and rb.endpoints('video', code) to inspect pricing:

const models = await rb.models('video', { q: 'seedance' });
console.log(models.data[0].pricing);

const detail = await rb.endpoints('video', 'doubao-seedance-1-0-pro-250528');
for (const ep of detail.endpoints) {
  console.log(ep.billing_method, ep.pricing);
}

See also

Video generation API · Error handling · Custom headers