GPT Image 2.5 is LIVE — Flare & Sunburst | Try in Image Generator →

wavespeed-ai/

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.

portrait-transfer
Input
Enable Safety Checker

Idle

$0.2per run·~50 / $10

ExamplesView all

Replace the man in the video with the image. Just change the face. Make the details normally

Let the woman in the image sing the song naturally.

Replace the man in the video with the image I give you. Not only the face, but also the suit.

Replace the man in the video with the image I give you.

Change the man in the video to the image man. change the face and haircut

Related Models

README

MoCha AI Video Character Replacement

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
    Choose 480p for lower-cost processing or 720p for higher-quality output.

Parameters

ParameterRequiredDescription
imageYesReference image of the new character. Use a clear JPG or PNG image when possible.
videoYesSource video containing the motion, expression, and camera perspective to preserve.
promptNoOptional text instruction to guide the replacement result, such as appearance details, preservation requirements, or style direction.
resolutionNoOutput resolution: 480p or 720p.
seedNoRandom seed for reproducible results. Use a fixed seed to reproduce similar outputs.

How to Use

  1. Upload a character image — Provide a clear reference image of the new character.
  2. Upload a source video — Provide the video whose motion, expression, and camera perspective should be preserved.
  3. Add a prompt optional — Describe what should be preserved or adjusted, such as outfit, lighting, background, or expression style.
  4. Choose resolution — Use 480p for lower-cost previews or 720p for higher-quality output.
  5. Set seed optional — Use a fixed seed when reproducibility is needed.
  6. 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.

ResolutionPer 5sPer secondMax billed length
480p$0.20$0.04120s
720p$0.40$0.08120s

Example Costs

Input DurationBilled Duration480p720p
0.5s3s$0.12$0.24
3s3s$0.12$0.24
5s5s$0.20$0.40
30s30s$1.20$2.40
120s120s$4.80$9.60
150s120s$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 480p for quick tests and 720p for higher-quality output.
  • For better stability, test with shorter clips before processing longer videos.

Notes

  • image and video are required.
  • Billed duration is rounded up and clamped to 3–120 seconds.
  • Videos longer than 120 seconds 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.
Note:This website uses AI models provided by third parties. Documentation prices are for reference and may be outdated. The Generate button shows an estimate; the final task charge prevails.

Wan 2.1 Mocha API — Quick start

Grab a WaveSpeedAI API key, then call POST https://api.wavespeed.ai/api/v3/wavespeed-ai/wan-2.1/mocha with your input as JSON. The endpoint returns a prediction id. Start polling the result endpoint around every 2 seconds, increase the interval for long-running tasks, and stop on any terminal status. On completed, read output values from data.outputs. Examples for Wan 2.1 Mocha below.

HTTP example
set -euo pipefail

: "${WAVESPEED_API_KEY:?Set WAVESPEED_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 "Content-Type: application/json" \
  -H "Authorization: Bearer $WAVESPEED_API_KEY" \
  -d "$REQUEST_BODY")

TASK=$(printf '%s' "$SUBMIT_RESPONSE" | jq 'if has("data") then .data else . end')
PREDICTION_ID=$(printf '%s' "$TASK" | jq -r '.id')
if [ -z "$PREDICTION_ID" ] || [ "$PREDICTION_ID" = "null" ]; 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 has("data") then .data else . end')
  STATUS=$(printf '%s' "$RESULT" | jq -r '.status')
  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
done
Node.js example
const submitUrl = "https://api.wavespeed.ai/api/v3/wavespeed-ai/wan-2.1/mocha";
const apiKey = process.env.WAVESPEED_API_KEY;
if (!apiKey) throw new Error('Set WAVESPEED_API_KEY');

async function requestJson(url, options = {}) {
  const response = await fetch(url, options);
  if (!response.ok) throw new Error(await response.text());
  return response.json();
}

// 1. Submit the prediction.
const body = await requestJson(submitUrl, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
        "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"
}),
});
const task = body.data ?? body;
if (!task.id) throw new Error("Submission response did not contain a prediction id");
const resultUrl = `https://api.wavespeed.ai/api/v3/predictions/${task.id}/result`;

// 2. Poll until the prediction finishes.
while (true) {
  const resultBody = await requestJson(resultUrl, {
    headers: { "Authorization": `Bearer ${apiKey}` },
  });
  const result = resultBody.data ?? resultBody;
  if (result.status === "completed") {
    console.log(result.outputs);
    break;
  }
  if (["failed", "cancelled", "timeout", "deleted"].includes(result.status)) throw new Error(JSON.stringify(result));
  await new Promise(resolve => setTimeout(resolve, 2000));
}
Python example
import json
import os
import time
from urllib.request import Request, urlopen

api_key = os.environ["WAVESPEED_API_KEY"]
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
payload = {
    "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"
}

def request_json(url, data=None):
    request = Request(url, data=data, headers=headers, method="POST" if data else "GET")
    with urlopen(request) as response:
        return json.load(response)

# 1. Submit the prediction.
body = request_json("https://api.wavespeed.ai/api/v3/wavespeed-ai/wan-2.1/mocha", json.dumps(payload).encode())
task = body.get("data", body)
if not task.get("id"):
    raise RuntimeError("Submission response did not contain a prediction id")
result_url = f"https://api.wavespeed.ai/api/v3/predictions/{task['id']}/result"

# 2. Poll until the prediction finishes.
while True:
    result_body = request_json(result_url)
    result = result_body.get("data", result_body)
    status = result.get("status")
    if status == "completed":
        print(result.get("outputs", []))
        break
    if status in {"failed", "cancelled", "timeout", "deleted"}:
        raise RuntimeError(result)
    time.sleep(2)

Wan 2.1 Mocha API — Frequently asked questions

What is the Wan 2.1 Mocha API?

Wan 2.1 Mocha is a WaveSpeedAI model for AI inference, exposed as a REST API 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. You can call it programmatically or try it from the playground above.

How do I call the Wan 2.1 Mocha API?

POST your input parameters to the model's REST endpoint (shown in the API tab of this playground) with your WaveSpeedAI API key in the Authorization header. Submission returns a prediction ID. Poll the result endpoint starting around every 2 seconds, increase the interval for long-running tasks, and stop on any terminal status. The playground generates production-oriented Python, JavaScript, and cURL examples with timeouts, transient-error handling, and safe GET retries. Full request/response shape is documented at https://wavespeed.ai/docs/docs-api/wavespeed-ai/wan-2.1-mocha.

How much does Wan 2.1 Mocha cost per run?

Wan 2.1 Mocha starts at $0.20 per run. That figure is the base price — the final charge scales with the parameters you set in the form (output size, length, count, references, or whatever knobs this model exposes), so a higher-quality or larger output costs more than a minimal one. The exact cost for your current input is shown live next to the Generate button before you submit, and the actual per-call charge is recorded on the prediction afterwards.

What inputs does Wan 2.1 Mocha accept?

Key inputs: `prompt`, `image`, `video`, `resolution`, `seed`. The full JSON schema (types, defaults, allowed values) is rendered above the Generate button and mirrored in the API reference at https://wavespeed.ai/docs/docs-api/wavespeed-ai/wan-2.1-mocha.

How long does Wan 2.1 Mocha take to generate?

Median end-to-end generation time on WaveSpeedAI is around 332 seconds per request, based on recent successful runs. Queue time varies with global demand; live status is visible in the prediction record.

Can I use Wan 2.1 Mocha outputs commercially?

Commercial usage rights depend on the model's license, set by its provider (WaveSpeedAI). The license summary appears on the model card above; see WaveSpeedAI's Terms of Service for platform-level conditions.

Wan 2.1 MoCha Video-to-Video Character Swap API on WaveSpeedAI