Bytedance Seedance 2.5 Motion Control API Documentation
Playground
Try it on WaveSpeedAI!Transfer the motion of a reference video onto a character with Seedance 2.5. Your character, from a picture or a short description, performs the same movements, gestures and camera motion as the video, in 480p, 720p or 1080p for up to 30 seconds. Ready-to-use REST inference API, best performance, no coldstarts, affordable pricing.
Features
Seedance 2.5 Motion Control transfers the motion of a reference video onto a character. Your character performs the same movements, gestures, timing and camera motion as the person in the video, while the background, framing and pacing of the video are kept.
Why Choose This?
-
Faithful motion transfer - Dance, gestures, walking, turning and full-body action carry over from the reference video to your character.
-
Character identity from your pictures - Face and hairstyle come from the first image. Add outfit, prop or location pictures, up to 30 images in total, to change what the character wears or where the scene takes place.
-
Video-driven timing and camera - Duration, framing and camera movement follow the reference video, so the result drops straight into your cut.
-
Native audio - Generate synchronized audio, or keep the original soundtrack of the reference video.
-
Up to 1080p, up to 30 seconds - Choose 480p for fast previews or 1080p for final delivery.
Parameters
| Parameter | Required | Description |
|---|---|---|
| video | Yes | URL of the motion reference video, 4 to 30 seconds. Only the first 30 seconds of a longer video are used, and a shorter video is billed as 4 seconds. |
| reference_images | No | Reference image URLs, up to 30. The first image is the character who performs the motion; a clear picture with a visible face works best. Add further pictures of an outfit, props or a location to use them in the shot. |
| prompt | No* | Optional extra direction; leave empty to transfer the motion as it is. *Required when no reference image is given: describe the character who replaces the person in the video. |
| resolution | No | Output resolution: 480p, 720p, or 1080p. Default: 720p. |
| generate_audio | No | Generate synchronized audio for the output. When set to false, the reference video’s audio track is kept. Default: true. |
The output duration and aspect ratio follow the reference video.
How to Use
- Upload the motion video — Provide a clip of the movement you want to copy, 4 to 30 seconds.
- Add reference pictures (optional) — The first picture is the character who performs the motion; add outfit, prop or location pictures after it. No picture? Describe the character in the prompt.
- Add direction if needed — Leave
promptempty, or add a short instruction. - Choose resolution — Select
480p,720p, or1080p. - Submit — Generate the video. API requests are asynchronous; poll the result endpoint until the video URL is available.
Tips for Better Results
- Use a motion video with one clearly visible performer and a stable camera.
- Pick a character image whose pose and framing are close to the first frame of the video (full body for full-body motion).
- Keep the character’s face and clothing clearly visible in the image.
- No picture? Describe the character in the prompt, for example a knight in silver armor. This works for human-like characters. For animals or objects, add a picture of the character instead.
- Extra reference pictures are used where they fit: an outfit changes what the character wears, a location replaces the setting. Anything they do not cover stays as in the video.
- Avoid heavily occluded limbs in the reference video; fast, complex motion is easier to follow when the performer stays in frame.
Pricing
Charges are based on the duration of the reference video, rounded up to whole seconds, with a 4-second minimum and a 30-second maximum.
| Resolution | Per second | 5 seconds | 10 seconds | 30 seconds |
|---|---|---|---|---|
| 480p | $0.22 | $1.10 | $2.20 | $6.60 |
| 720p | $0.44 | $2.20 | $4.40 | $13.20 |
| 1080p | $1.10 | $5.50 | $11.00 | $33.00 |
For example, a 3.2-second clip is billed as 4 seconds, and a 8.04-second clip is billed as 9 seconds.
Related Models
- Seedance 2.5 Talking Avatar - animate a portrait from an audio recording.
- Seedance 2.5 Video Edit - edit an existing video with a prompt.
Authentication
For authentication details, please refer to the Authentication Guide.
API Endpoints
Submit Task & Query Result
set -euo pipefail
export WAVESPEED_API_KEY="your-api-key"
REQUEST_BODY=$(cat <<'JSON'
{
"video": "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
"resolution": "720p",
"generate_audio": true
}
JSON
)
# 1. Submit the prediction once. Never retry this request automatically:
# a retry after an unclear failure can create a second, billed task.
CHECK='The task may already exist. Check History or the predictions list before submitting again.'
if ! SUBMIT_RESPONSE=$(curl --silent --show-error --fail-with-body \
--connect-timeout 10 --max-time 60 \
-X POST "https://api.wavespeed.ai/api/v3/bytedance/seedance-2.5/motion-control" \
-H "Authorization: Bearer ${WAVESPEED_API_KEY}" \
-H "Content-Type: application/json" \
-d "${REQUEST_BODY}"); then
printf 'Submit failed. %s\n' "${CHECK}" >&2
exit 1
fi
TASK=$(printf '%s' "${SUBMIT_RESPONSE}" | jq 'if type == "object" and has("data") then .data else . end')
PREDICTION_ID=$(printf '%s' "${TASK}" | jq -r '.id // empty')
if [ -z "${PREDICTION_ID}" ]; then
printf 'Submission response did not contain a prediction id. %s\n' "${CHECK}" >&2
exit 1
fi
RESULT_URL="https://api.wavespeed.ai/api/v3/predictions/${PREDICTION_ID}/result"
# 2. Poll until the prediction reaches a final status.
BODY_FILE=$(mktemp)
trap 'rm -f "${BODY_FILE}"' EXIT
while true; do
# Transient errors (429, 5xx) are retried, honoring Retry-After.
HTTP_CODE=$(curl --silent --show-error --fail-with-body \
--connect-timeout 10 --max-time 60 --retry 5 --retry-delay 2 \
--output "${BODY_FILE}" --write-out '%{http_code}' \
"${RESULT_URL}" \
-H "Authorization: Bearer ${WAVESPEED_API_KEY}" || true)
case "${HTTP_CODE}" in
2??) ;;
000|429|5??) # dropped connection or temporary error: keep polling
printf 'Task %s: HTTP %s, polling again in 10s\n' "${PREDICTION_ID}" "${HTTP_CODE}" >&2
sleep 10; continue ;;
*) printf 'Task %s: HTTP %s\n' "${PREDICTION_ID}" "${HTTP_CODE}" >&2
cat "${BODY_FILE}" >&2; exit 1 ;;
esac
RESULT=$(jq 'if type == "object" and has("data") then .data else . end' "${BODY_FILE}")
STATUS=$(printf '%s' "${RESULT}" | jq -r '.status // empty')
case "${STATUS}" in
completed) printf '%s\n' "${RESULT}" | jq '.outputs'; break ;;
failed|cancelled|timeout|deleted)
printf 'Task %s ended with status %s\n' "${PREDICTION_ID}" "${STATUS}" >&2
printf '%s\n' "${RESULT}" | jq . >&2; exit 1 ;;
*) sleep 2 ;;
esac
doneRetry temporary errors only while polling, never the submit request. Errors, retries and timeouts
Parameters
Task Submission Parameters
Request Parameters
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
| video | string | Yes | - | URL of the motion reference video, 4 to 30 seconds. Only the first 30 seconds of a longer video are used, and a shorter video is billed as 4 seconds. The result follows its duration, camera and background. | |
| reference_images | array<string> | No | - | 0 ~ 30 items | Optional reference image URLs. The first image is the character who performs the motion. Add pictures of an outfit, props or a location to use them in the shot (30 images at most). Without any image, describe the character in the prompt. |
| prompt | string | No | - | Optional extra direction for the result. Required when no reference image is given: describe the character who replaces the person in the video. | |
| resolution | string | No | 720p | 480p, 720p, 1080p | Output video resolution. |
| generate_audio | boolean | No | true | - | Whether to generate native audio for the output. Defaults to true. When set to false, the reference video's audio track is preserved on the output instead. |
Every model also accepts the global request options enable_sync_mode and enable_base64_output; see their pages for details.
Response Parameters
| Parameter | Type | Description |
|---|---|---|
| code | integer | HTTP status code (e.g., 200 for success) |
| message | string | Status message (e.g., “success”) |
| data.id | string | Unique identifier for the prediction, Task Id |
| data.model | string | Model ID used for the prediction |
| data.outputs | array | Output values, usually URL strings; some models return text strings or structured result objects (empty when status is not completed) |
| data.urls | object | Object containing related API endpoints |
| data.status | string | Task status. completed is successful; failed, cancelled, timeout, and deleted are failure terminal statuses. |
| data.created_at | string | ISO timestamp of when the request was created (e.g., “2023-04-01T12:34:56.789Z”) |
| data.error | string | Error message (empty if no error occurred) |
| data.timings | object | Object containing timing details |
| data.timings.inference | integer | Inference time in milliseconds |
Result Request Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | string | Yes | - | Task ID |
Result Response Parameters
| Parameter | Type | Description |
|---|---|---|
| code | integer | HTTP status code (e.g., 200 for success) |
| message | string | Status message (e.g., “success”) |
| data | object | The prediction data object containing all details |
| data.id | string | Unique identifier for the prediction |
| data.model | string | Model ID used for the prediction |
| data.outputs | array<string | object> | Array of generated outputs (empty when status is not completed). Items are usually URL strings, but may be text strings or structured result objects, depending on the model. |
| data.urls | object | Object containing related API endpoints |
| data.status | string | Status: completed is successful; failed, cancelled, timeout, and deleted are failure terminal statuses |
| data.created_at | string | ISO timestamp of when the request was created |
| data.error | string | Error message (empty if no error occurred) |
| data.timings | object | Object containing timing details |
| data.timings.inference | integer | Inference time in milliseconds |