Higgsfield Genjutsu
One clip, three modes: motion transfer, object swap and restyle. 4 to 30 seconds, up to 1080p.
Higgsfield Genjutsu takes a finished clip and changes the reality in it without reshooting the motion.
Motion transfer builds a new scene from your photos — a character, a place, a style — and keeps the original motion, camera and timing.
Object swap changes a chosen person, outfit, product or object. The rest of the shot stays as filmed.
Restyle applies a chosen visual style and keeps the clip’s motion and original audio. Photos are optional: without them the style is applied to whoever is already in the frame.
The video is at least 4 seconds; longer than 30 seconds is trimmed to 30. Resolution is 480p, 720p or 1080p. The prompt is optional. Every mode costs the same, per second of your clip.
One model, higgsfield-genjutsu · ~3 min. The mode is the input.mode field.
Modes
One ID, higgsfield-genjutsu. input.mode chooses what happens to the clip. Omitted, it is motion transfer. The official ids work too: higgsfield/genjutsu/object-swap/v1.0 and higgsfield/genjutsu/restyle/v1.0 select the mode, so mode can be left out.
mode | What it does | What to send |
|---|---|---|
motion-transfer | Motion, camera and timing come from the video; the look comes from the photos | video_url + image_urls (1–8) |
object-swap | Replaces a person, outfit or object in the clip. The rest of the shot stays | video_url + image_urls (1–8) |
restyle | The same clip in a chosen style. The source motion and audio stay | video_url + preset_id. image_urls — optional, up to 5 |
Shared by all three: the video is at least 4 seconds, longer than 30 seconds is trimmed to 30, and the result has the same length. prompt may be omitted. resolution: 480p, 720p (default) or 1080p. The mode does not change the price.
Object swap needs a source frame of at least 409,600 pixels (width × height). Ordinary HD is fine; a tiny preview is not.
Styles for restyle
Style list: GET https://mixmedia.tech/api/v1/genjutsu/presets. No key. preset_id is the item's id, not its name and not the preview image.
{
"code": 200,
"msg": "success",
"data": {
"items": [
{
"id": "c2143317-f28d-4c3c-a0b8-39bd547e08a7",
"name": "Cel-Shaded CG Anime",
"preview_url": "https://…/style.webp"
}
]
}
}
The list changes. If a saved preset_id is no longer accepted, fetch the list again and use a current id.
Price
| Resolution | Price per second of your video |
|---|---|
| 480p | $0.414 |
| 720p | $0.886 |
| 1080p | $2.122 |
- Price = per-second price × clip length, rounded up to $0.001. Charged when the task is created and fully refunded if it fails.
- You pay per second of your video (4 to 30 s). A clip longer than 30 s is trimmed to 30; the result has the same length.
promptmay be omitted.
Media limits
| Type | Limits |
|---|---|
| Images | 1–8 for motion transfer and object swap; 0–5 for restyle. JPG / PNG / WebP; public https or files/upload — up to 30 MB per file |
| Video | one clip, video_url; 4 s to 30 s (longer is trimmed to 30); MP4 / MOV → MP4 on the server; upload ≤ 200 MB |
Photos — public https or upload; video and audio — files/upload only.
Parameters (field input)
| Parameter | Description | Values (default in bold) |
|---|---|---|
mode | Mode: motion-transfer copies motion onto your photos, object-swap replaces a person or object, restyle keeps the clip and applies a style. Omit it when calling an official model id: …/object-swap/v1.0 and …/restyle/v1.0 select the mode themselves | motion-transfer · object-swap · restyle |
prompt | What happens in the clip: scene, motion, camera, light, style | text, up to 10000 chars (optional, default empty) |
video_url | Motion video (MP4): one clip, at least 4 s. Longer than 30 s is trimmed to 30. Upload it via files/upload first | "https://…" |
image_urls | Character photos (https): look, face, clothes | ["https://…"], up to 8 |
preset_id | Style for restyle: a UUID from GET /api/v1/genjutsu/presets. Not used by the other modes | style UUID, required when mode is restyle |
resolution | Video resolution | 480p · 720p · 1080p |
Examples
Motion transfer
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"higgsfield-genjutsu","input":{"mode":"motion-transfer","prompt":"Keep the face from the photo, take the motion from the video","video_url":"https://mixmedia.tech/files/<id>.mp4","image_urls":["https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"],"resolution":"720p"}}'
import os, requests
r = requests.post(
"https://mixmedia.tech/api/v1/jobs/createTask",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"model": "higgsfield-genjutsu",
"input": {
"mode": "motion-transfer",
"prompt": "Keep the face from the photo, take the motion from the video",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"image_urls": [
"https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
],
"resolution": "720p"
}
},
)
print(r.json()) # {"code": 200, "data": {"taskId": "..."}}
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"model": "higgsfield-genjutsu",
"input": {
"mode": "motion-transfer",
"prompt": "Keep the face from the photo, take the motion from the video",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"image_urls": [
"https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
],
"resolution": "720p"
}
}),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
Object swap
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"higgsfield-genjutsu","input":{"mode":"object-swap","prompt":"Replace the person with the character in the photo","video_url":"https://mixmedia.tech/files/<id>.mp4","image_urls":["https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"],"resolution":"720p"}}'
import os, requests
r = requests.post(
"https://mixmedia.tech/api/v1/jobs/createTask",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"model": "higgsfield-genjutsu",
"input": {
"mode": "object-swap",
"prompt": "Replace the person with the character in the photo",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"image_urls": [
"https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
],
"resolution": "720p"
}
},
)
print(r.json()) # {"code": 200, "data": {"taskId": "..."}}
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"model": "higgsfield-genjutsu",
"input": {
"mode": "object-swap",
"prompt": "Replace the person with the character in the photo",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"image_urls": [
"https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
],
"resolution": "720p"
}
}),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
Restyle
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"higgsfield-genjutsu","input":{"mode":"restyle","video_url":"https://mixmedia.tech/files/<id>.mp4","preset_id":"<preset_id>","resolution":"720p"}}'
import os, requests
r = requests.post(
"https://mixmedia.tech/api/v1/jobs/createTask",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"model": "higgsfield-genjutsu",
"input": {
"mode": "restyle",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"preset_id": "<preset_id>",
"resolution": "720p"
}
},
)
print(r.json()) # {"code": 200, "data": {"taskId": "..."}}
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"model": "higgsfield-genjutsu",
"input": {
"mode": "restyle",
"video_url": "https://mixmedia.tech/files/<id>.mp4",
"preset_id": "<preset_id>",
"resolution": "720p"
}
}),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
Create and result
POST /api/v1/jobs/createTaskwithmodelandinput.- Poll
GET /api/v1/jobs/recordInfo?taskId=…every 3–5 s (or a callback).
Successful createTask (HTTP 200)
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_...",
"task_id": "task_...",
"status": "submitted"
}
}
Completed task (recordInfo)
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_...",
"task_id": "task_...",
"state": "success",
"status": "completed",
"costUsd": "0.384",
"refunded": false,
"resultJson": {
"videos": [
{
"url": "https://…/out.mp4"
}
],
"duration": 8
}
}
}
Aliases: task_id = taskId; status: pending / processing / completed / failed alongside state. Clip URL is in resultJson. size is an alias of aspect_ratio in input.
Photos can be any public https links or uploads via files/upload. Videos and audio — via files/upload only.
Error handling
API responses are JSON {"code", "msg", "data"}; errors also have a string error field (type). On /api/v1/* the HTTP status matches body code.
Example response bodies
400
{
"code": 400,
"msg": "input.duration: must be between 4 and 30, or \"auto\" / -1",
"data": null,
"error": "invalid_request_error"
}
401
{
"code": 401,
"msg": "Authentication failed. Please check your API key",
"data": null,
"error": "authentication_error"
}
402
{
"code": 402,
"msg": "Insufficient balance. Please top up and try again. Available: $0.01, required: $0.015. Top up at https://mixmedia.tech/cabinet/billing",
"data": {
"balance": "0.0100",
"required": "0.0150",
"currency": "USD",
"topUpUrl": "https://mixmedia.tech/cabinet/billing"
},
"error": "payment_required"
}
429
{
"code": 429,
"msg": "Rate limit exceeded: 10 createTask/upload requests per 10 s per key. Retry after 8s",
"data": null,
"error": "rate_limit_error"
}
500
{
"code": 500,
"msg": "Internal server error",
"data": null,
"error": "server_error"
}
Codes on createTask / upload
| code | error | Meaning | What to do |
|---|---|---|---|
| 400 | invalid_request_error | Invalid parameter or body | See msg |
| 400 | unsupported_model | Unknown model | Model list |
| 400 | nsfw_content_detected | Moderation / content policy — msg / failMsg is the upstream text verbatim | Read the refusal text, change the prompt or files |
| 401 | authentication_error | Missing or invalid key | Check the key |
| 402 | payment_required | Not enough balance | Top up |
| 403 | permission_error | No access | Contact support |
| 429 | rate_limit_error | Too many requests | Wait for Retry-After |
| 505 | model_disabled | Model temporarily disabled | Pick another |
| 500 | server_error | Our failure | Retry later |
Example msg values: Authentication failed. Please check your API key (401); Insufficient balance. Please top up and try again… (402).
Task errors (recordInfo)
If the task was created and then failed: state: "fail" (alias status: "failed"), failCode / failMsg, and error: { code, message, type }. Money is refunded (refunded: true).
| failCode | error.type | Meaning |
|---|---|---|
| 400 | nsfw_content_detected / invalid_request_error | Moderation — failMsg is upstream text verbatim |
| 422 | invalid_request_error | The model rejected the parameters (length, mode, resolution, file) |
| 501 | server_error | The model could not generate (failMsg) |
| 504 | timeout_error | Timed out — retry |
| 500 / 503 | server_error | Service temporarily unavailable |
Rate limits
| What | Limit |
|---|---|
| createTask and upload | 20 per 10 s per key |
| recordInfo / list / balance | 100 per 10 s per key |
Over the limit — HTTP 429 and Retry-After.