Wan 2.1 Mocha API Documentation
Playground
Try it on WaveSpeedAI!Wan 2.1 MoCha Video-to-Video Character Swap replaces a video’s character using reference images, preserving identity and motion without per-frame pose or depth maps for character replacement, avatar edits, creative videos, and production workflows. Ready-to-use REST inference API, best performance, no coldstarts, affordable pricing.
Features
MoCha AI Video Character Replacement replaces the main character in a video with a new character provided through a reference image. It preserves the source video’s motion, facial expressions, lighting, and camera perspective while transferring the new character identity into the scene.
Unlike traditional workflows, MoCha does not require explicit per-frame structural inputs such as pose maps or depth maps. Provide a source video and a character image, then use an optional prompt to guide the replacement result.
Why Choose This?
-
Character replacement workflow
Replace the main character in a video using a reference image. -
Structure-free input
No pose maps, depth maps, or manual frame-by-frame guidance are required. -
Motion preservation
Preserve the source actor’s body movement, facial expression, timing, and camera perspective. -
Identity consistency
Maintain the new character’s facial identity, appearance, and style across frames. -
Simple setup
Use one character image and one source video without complex preprocessing or rigging. -
Flexible resolution options
Choose480pfor lower-cost processing or720pfor higher-quality output.
Parameters
| Parameter | Required | Description |
|---|---|---|
| image | Yes | Reference image of the new character. Use a clear JPG or PNG image when possible. |
| video | Yes | Source video containing the motion, expression, and camera perspective to preserve. |
| prompt | No | Optional text instruction to guide the replacement result, such as appearance details, preservation requirements, or style direction. |
| resolution | No | Output resolution: 480p or 720p. |
| seed | No | Random seed for reproducible results. Use a fixed seed to reproduce similar outputs. |
How to Use
- Upload a character image — Provide a clear reference image of the new character.
- Upload a source video — Provide the video whose motion, expression, and camera perspective should be preserved.
- Add a prompt optional — Describe what should be preserved or adjusted, such as outfit, lighting, background, or expression style.
- Choose resolution — Use
480pfor lower-cost previews or720pfor higher-quality output. - Set seed optional — Use a fixed seed when reproducibility is needed.
- Submit — Generate the character-replaced video.
Pricing
Pricing is based on input video duration and selected resolution.
Billed duration is rounded up to the next whole second, with a minimum billed duration of 3 seconds and a maximum billed duration of 120 seconds.
| Resolution | Per 5s | Per second | Max billed length |
|---|---|---|---|
| 480p | $0.20 | $0.04 | 120s |
| 720p | $0.40 | $0.08 | 120s |
Example Costs
| Input Duration | Billed Duration | 480p | 720p |
|---|---|---|---|
| 0.5s | 3s | $0.12 | $0.24 |
| 3s | 3s | $0.12 | $0.24 |
| 5s | 5s | $0.20 | $0.40 |
| 30s | 30s | $1.20 | $2.40 |
| 120s | 120s | $4.80 | $9.60 |
| 150s | 120s | $4.80 | $9.60 |
image, prompt, and seed do not add separate charges.
Best Use Cases
- Character replacement — Swap the main character in a video with a new reference character.
- Digital avatar videos — Create character-driven clips from existing performances.
- Advertising and creative production — Replace performers or characters while preserving the original scene motion.
- Film and concept tests — Prototype character variations without reshooting footage.
- Social video creation — Generate character-transformed short videos for creative content.
- Motion-preserving edits — Keep the original timing, action, and camera perspective while changing the character.
Pro Tips
- Use a clear, well-lit reference image with the character’s face and body details visible.
- Match the reference image’s angle, framing, and body orientation to the source video when possible.
- Use a source video with clear subject motion and limited occlusion.
- Keep the source video and reference image visually compatible for smoother replacement.
- Add prompt instructions for what should remain unchanged, such as background, camera movement, lighting, or outfit style.
- Use
480pfor quick tests and720pfor higher-quality output. - For better stability, test with shorter clips before processing longer videos.
Notes
imageandvideoare required.- Billed duration is rounded up and clamped to
3–120seconds. - Videos longer than
120seconds are billed at the 120-second cap. - The model is designed for replacing the main character in the source video.
- Clear subject framing and consistent lighting improve replacement quality.
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'
{
"image": "https://interactive-examples.mdn.mozilla.net/media/cc0-images/painted-hand-298-332.jpg",
"video": "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
"resolution": "480p"
}
JSON
)
# 1. Submit the prediction.
SUBMIT_RESPONSE=$(curl --silent --show-error --fail-with-body \
-X POST "https://api.wavespeed.ai/api/v3/wavespeed-ai/wan-2.1/mocha" \
-H "Authorization: Bearer ${WAVESPEED_API_KEY}" \
-H "Content-Type: application/json" \
-d "${REQUEST_BODY}")
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
' >&2
exit 1
fi
RESULT_URL="https://api.wavespeed.ai/api/v3/predictions/${PREDICTION_ID}/result"
# 2. Poll until the prediction finishes.
while true; do
RESPONSE=$(curl --silent --show-error --fail-with-body \
"${RESULT_URL}" \
-H "Authorization: Bearer ${WAVESPEED_API_KEY}")
RESULT=$(printf '%s' "${RESPONSE}" | jq 'if type == "object" and has("data") then .data else . end')
STATUS=$(printf '%s' "${RESULT}" | jq -r '.status // empty')
case "${STATUS}" in
completed) printf '%s\n' "${RESULT}" | jq '.outputs'; break ;;
failed|cancelled|timeout|deleted) printf '%s\n' "${RESULT}" | jq . >&2; exit 1 ;;
*) sleep 2 ;;
esac
doneParameters
Task Submission Parameters
Request Parameters
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
| image | string | Yes | - | The image for generating the output. | |
| video | string | Yes | - | The video for generating the output. | |
| prompt | string | No | - | The positive prompt for the generation. | |
| resolution | string | No | 480p | 480p, 720p | The resolution of the output video. |
| seed | integer | No | - | - | The random seed to use for the generation. -1 means a random seed will be used. |
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 |