Openjutsu Character Swap API Documentation
Playground
Try it on WaveSpeedAI!Openjutsu Character Swap replaces people in existing videos with characters from reference images while preserving the original scene, motion, framing, and audio for character replacement, creative video editing, social content, and production workflows. Ready-to-use REST inference API, best performance, no coldstarts, affordable pricing.
Features
Genjutsu Character Swap (OpenJutsu) replaces people in an existing video with characters from reference images while preserving the original scene, camera movement, performance, and audio.
Use one image to replace the most prominent person, or provide multiple images with role descriptions to control which people should be replaced.
Why Choose This?
- Character replacement — Replace people in an existing video with characters from reference images.
- Up to 4 character images — Replace multiple people in the same scene.
- Role-based matching — Describe who each reference image should replace.
- Performance preserved — Keep the source video’s body motion, timing, framing, and camera movement.
- Original audio preserved — Retain the source soundtrack in the final result.
- Up to 1080p output — Choose
480p,540p,768p, or1080p.
Parameters
| Parameter | Required | Description |
|---|---|---|
| video | Yes | Source video URL. Must be at least 2 seconds long and contain a visible person. Up to the first 15 seconds are processed. |
| images | Yes | Between 1 and 4 character image URLs, one for each person you want to replace. |
| roles | No | Optional descriptions identifying who each image should replace, in the same order as images. Example: the woman in black on the left. |
| resolution | No | Output resolution: 480p, 540p, 768p, or 1080p. Default: 768p. |
| seed | No | Random seed for generation. A negative value uses a random seed. |
How to Use
- Upload a source video — Use a continuous shot with at least one clearly visible person.
- Add character images — Provide one image for each person you want to replace.
- Add roles optional — Describe which person each image should replace when multiple people appear.
- Choose resolution — Select
480p,540p,768p, or1080p. - Set a seed optional — Use a fixed seed when comparing variations.
- Submit — Generate and retrieve the character-swapped video.
Pricing
Pricing is based on the input video duration, selected resolution, and number of character images.
| Resolution | Price per Second |
|---|---|
| 480p | $0.15 |
| 540p | $0.17 |
| 768p | $0.20 |
| 1080p | $0.40 |
Each character image adds $0.02.
Example Costs
| Configuration | Price |
|---|---|
| 10s at 480p + 1 image | $1.52 |
| 10s at 540p + 1 image | $1.72 |
| 10s at 768p + 1 image | $2.02 |
| 10s at 1080p + 1 image | $4.02 |
| 10s at 768p + 2 images | $2.04 |
| 15s at 768p + 1 image | $3.02 |
Videos shorter than 3 seconds are billed as 3 seconds. Videos longer than 15 seconds use and bill only the first 15 seconds.
Best Use Cases
- Character replacement — Replace actors or people while preserving the original performance.
- Creative remixes — Recast existing footage with new characters.
- Marketing content — Adapt existing video performances with different character appearances.
- Storytelling — Reuse motion and cinematography while changing who appears in the scene.
- Multi-character scenes — Replace selected people while leaving others unchanged.
Pro Tips
- Use a continuous source shot with clearly visible people.
- Use one reference image per person you want to replace.
- Describe people by appearance or position rather than by name.
- Use
roleswhen several people appear in the same scene. - Use clear character images with visible facial and clothing details.
- Avoid source footage where mirrors or reflections are important.
Notes
- Input video duration is rounded up to the next whole second for billing.
- The person to replace must be visible in the first frame.
- Each
rolesentry supports up to 200 characters. The number of entries must not exceed the number of input images. - Up to
4character images are supported. - With one image and no
roles, the most prominent person is replaced. - With multiple images and no
roles, images are matched to people by appearance order or left-to-right position. - Source audio is preserved.
- Videos longer than
15seconds use only the first15seconds.
Related Models
- OpenJutsu Character Swap — Replace people in existing videos using character reference images.
- OpenJutsu Object Swap — Replace objects in existing videos while preserving the original scene and motion.
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",
"images": [
"https://interactive-examples.mdn.mozilla.net/media/cc0-images/painted-hand-298-332.jpg"
],
"resolution": "768p"
}
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/wavespeed-ai/openjutsu/character-swap" \
-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 source video. The people in it are replaced by your characters; the scene, motion and original audio are kept. Use a single shot with a person in the first frame. The output follows the video's length, up to 15 seconds. | |
| images | array<string> | Yes | - | 1 ~ 4 items | URLs of the character pictures, one per person to replace (up to 4). With one picture and no roles, the most prominent person is replaced. With several, or with roles, only the people you describe are replaced and everyone else stays as filmed. A picture nobody in the video matches is left out. |
| roles | array<string> | No | - | 0 ~ 4 items | Optional. One short description per picture, in the same order, saying who it replaces, for example "the woman in black on the left". Leave it out and the pictures go to the people in the order they appear in the video, or from left to right when they are on screen together. |
| resolution | string | No | 768p | 480p, 540p, 768p, 1080p | Output resolution. The price per second rises with it. |
| seed | integer | No | - | - | The random seed to use for the generation. A negative value means a random seed will be used. |
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 |