# Seedance 2.5 Video to Video > Turn existing footage into a new video — restyle, restage, reframe or extend a clip you already have, steering it with up to 10 source videos named in the prompt. ## Overview - **Endpoint**: `https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video` - **Model ID**: `bytedance/seedance-v2.5/video-to-video` - **Category**: video-to-video - **Kind**: inference - **Tags**: video, video-to-video, reference-video, video-editing, video-extension, video-restyle, motion-control, video generation, audio, bytedance, seedance, seedance 2.5, 30-second-video ## Pricing - **Estimated Price**: $12.53 average per output ## Request Lifecycle This model runs on the ModelRunner **asynchronous queue API** — a single POST does not return the output. Every call requires an `Authorization: Key $MODEL_RUNNER_KEY` header. Run three steps: 1. **Submit** — `POST https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video` with a JSON body holding the input fields at the top level. The body may also include a reserved top-level `metadata` object — a flat string map (max 16 keys, key ≤64 / value ≤512 chars) stored on the request for your own tagging. It is never sent to the model; filter your request history with `GET https://queue.modelrunner.run/requests?metadata=` (exact key=value matches, AND-ed). The response carries request handles only (no output yet): ```json { "status": "IN_QUEUE", "request_id": "<21-char id>", "status_url": "https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video/requests//status", "response_url": "https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video/requests/", "cancel_url": "https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video/requests//cancel" } ``` 2. **Poll status** — `GET ` until `status` is `COMPLETED`. Possible values are `IN_QUEUE`, `IN_PROGRESS`, `COMPLETED`, `FAILED`, `CANCELLED`. A `FAILED` request responds with HTTP 400 and an `error` field. 3. **Read result** — `GET `. Returns the finished request, including the generated `output`: ```json { "id": "", "status": "COMPLETED", "output": ..., "input": ... } ``` The JavaScript and Python SDKs below perform steps 2–3 for you. In any language without an SDK (Swift, Go, Kotlin, etc.) you must implement the polling loop and the final result fetch yourself — see the cURL example for the full flow. ### Input Schema - **`prompt`** (`string`, _required_): Describe the result you want and what to take from each reference. Address the reference assets positionally as @Video1..@Video10, @Image1..@Image30 and @Audio1..@Audio10, numbered by their order in reference_videos, reference_images and reference_audios: with one source clip and one product photo, 'Match the camera movement and pacing of @Video1, but restage it on a sunlit desert roadside at midday; the rider pulls up on the motorcycle from @Image1' borrows the motion from the clip and the subject from the image. A reference the prompt never names is usually ignored, so name every one you send. - **`duration`** (`integer`, _optional_): Length of the generated clip in seconds, from 4 to 30. Leave at -1 (the default) to let the model choose a whole-second length close to the source footage. Billing counts this alongside the duration of the source clips you send. - Default: `-1` - **`resolution`** (`resolution`, _optional_): Output resolution of the clip. 720p meters more tokens per second of video than 480p, so it costs more. - Default: `"720p"` - Options: `"480p"`, `"720p"` - **`aspect_ratio`** (`aspect_ratio`, _optional_): Frame shape of the generated clip. The source footage does not dictate the framing on this variant, so pick the shape you want - a 1280x720 (16:9) source asked for 9:16 came back as a 480x854 portrait clip. Use adaptive to keep the source's own shape instead. - Default: `"16:9"` - Options: `"16:9"`, `"4:3"`, `"1:1"`, `"3:4"`, `"9:16"`, `"21:9"`, `"adaptive"` - **`generate_audio`** (`boolean`, _optional_): Generate a synchronized soundtrack (dialogue, ambience and sound effects) together with the picture. Set false for a silent clip; the price is the same either way. - Default: `true` - **`reference_audios`** (`array`, _optional_): Experimental: up to 10 short audio references for the generated soundtrack, addressed as @Audio1, @Audio2 and so on. Each clip 2-30 seconds, 30 seconds combined at most; WAV or MP3, under 15 MB each. The clips are accepted and add nothing to the price, but their effect on the finished soundtrack has not been verified - treat the field as experimental. They cannot be sent on their own: at least one reference video is always required. - **`reference_images`** (`array`, _optional_): Optional: up to 30 reference images that steer identity, wardrobe, product, location or style alongside the source footage. Addressed as @Image1, @Image2 and so on, numbered by their order in this array. JPEG, PNG, WebP, BMP, TIFF or GIF; 300-6000 px on a side, aspect ratio between 1:2.5 and 2.5:1, under 30 MB each. A still image has no duration, so reference images add nothing to the price. - **`reference_videos`** (`array`, _required_): 1 to 10 source clips - the footage this generation is built from, and where its motion, camera movement and pacing come from. The first entry is @Video1 in the prompt, the second @Video2, and so on. MP4 or MOV (H.264/H.265 video, AAC or MP3 audio), 2-30 seconds per file and no more than 30 seconds COMBINED across all files, 300-6000 px per side, aspect ratio between 0.4 and 2.5, 24-60 fps, under 200 MB each. Billing counts the duration of everything you send here as well as the length of the clip you get back, so a 30-second source costs about as much again as a 30-second output - trim each clip to the part that matters. ### Output Schema _No `Output` schema properties are available._ ## Default Example **Input** ```json { "prompt": "Match the camera movement and pacing of @Video1, but restage it on a sunlit desert roadside at midday — the cherry-red cafe racer from @Image1 parked alone on cracked asphalt, heat shimmer rising off the road and dust drifting past in the dry air", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "reference_images": [ "https://media.modelrunner.ai/6M3U2hs7xUtWJGZmjkvuN.jpeg" ], "reference_videos": [ "https://media.modelrunner.ai/6m0I6xs8DL2oaJhQoD8x9.mp4" ] } ``` **Output** ```json "https://media.modelrunner.ai/M4VsYugfiHJgIlF1kWvcz.mp4" ``` ## Usage Examples ### cURL The queue API is asynchronous: submit the request, poll `status_url` until it is `COMPLETED`, then read the result from `response_url`. Requires `jq`. ```bash # 1. Submit the request (returns request handles, not the output) SUBMIT=$(curl --silent --request POST \ --url https://queue.modelrunner.run/bytedance/seedance-v2.5/video-to-video \ --header "Authorization: Key $MODEL_RUNNER_KEY" \ --header "Content-Type: application/json" \ --data '{ "prompt": "Match the camera movement and pacing of @Video1, but restage it on a sunlit desert roadside at midday — the cherry-red cafe racer from @Image1 parked alone on cracked asphalt, heat shimmer rising off the road and dust drifting past in the dry air", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "reference_images": [ "https://media.modelrunner.ai/6M3U2hs7xUtWJGZmjkvuN.jpeg" ], "reference_videos": [ "https://media.modelrunner.ai/6m0I6xs8DL2oaJhQoD8x9.mp4" ] }') STATUS_URL=$(echo "$SUBMIT" | jq -r '.status_url') RESPONSE_URL=$(echo "$SUBMIT" | jq -r '.response_url') # 2. Poll until the request leaves the queue / in-progress state while true; do STATUS=$(curl --silent --url "$STATUS_URL" \ --header "Authorization: Key $MODEL_RUNNER_KEY" | jq -r '.status') echo "Status: $STATUS" case "$STATUS" in COMPLETED) break ;; FAILED|CANCELLED) echo "Request $STATUS"; exit 1 ;; esac sleep 1 done # 3. Read the finished request, including the generated output curl --silent --url "$RESPONSE_URL" \ --header "Authorization: Key $MODEL_RUNNER_KEY" ``` ### JavaScript ```javascript import { modelrunner } from "@modelrunner/client"; const result = await modelrunner.subscribe("bytedance/seedance-v2.5/video-to-video", { input: { "prompt": "Match the camera movement and pacing of @Video1, but restage it on a sunlit desert roadside at midday — the cherry-red cafe racer from @Image1 parked alone on cracked asphalt, heat shimmer rising off the road and dust drifting past in the dry air", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "reference_images": [ "https://media.modelrunner.ai/6M3U2hs7xUtWJGZmjkvuN.jpeg" ], "reference_videos": [ "https://media.modelrunner.ai/6m0I6xs8DL2oaJhQoD8x9.mp4" ] } }); console.log(result.data); ``` ### Python ```python import asyncio import modelrunner_ai async def main(): response = await modelrunner_ai.submit_async( "bytedance/seedance-v2.5/video-to-video", arguments={ "prompt": "Match the camera movement and pacing of @Video1, but restage it on a sunlit desert roadside at midday — the cherry-red cafe racer from @Image1 parked alone on cracked asphalt, heat shimmer rising off the road and dust drifting past in the dry air", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "reference_images": [ "https://media.modelrunner.ai/6M3U2hs7xUtWJGZmjkvuN.jpeg" ], "reference_videos": [ "https://media.modelrunner.ai/6m0I6xs8DL2oaJhQoD8x9.mp4" ] } ) result = await response.get() print(result["output"]) asyncio.run(main()) ``` ## Additional Resources - [Playground](https://modelrunner.ai/models/bytedance/seedance-v2.5/video-to-video) - [OpenAPI Schema](https://modelrunner.ai/models/bytedance/seedance-v2.5/video-to-video/openapi.json) - [LLM Instructions](https://modelrunner.ai/models/bytedance/seedance-v2.5/video-to-video/llms.txt)