Lip syncVideo
Lip sync re-dub
Swaps the voice in your clip and matches the lips to the new audio.
- Price
- 108 crper clip · basic · varies with length or size
- Usual time
- ≈ 4 min
- Model id
video.lipsync
Playground
- Mode
- basic, lite
- Takes
- Video, Audio
No example of this model yet. These are its real settings.
# 0. Upload your file first and put the id it prints in params.
curl -s -X POST https://staglight.ai/api/v1/uploads \
-H "Authorization: Bearer $STAGLIGHT_API_KEY" -F file=@your-file | jq -r .id
# 1. Create the job. It is charged once and refunded if it fails.
JOB_ID=$(curl -s -X POST https://staglight.ai/api/v1/jobs \
-H "Authorization: Bearer $STAGLIGHT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"op": "video.lipsync",
"params": {
"video": "med_your_upload_id",
"audio": "med_your_upload_id",
"own_footage": true,
"mode": "basic"
}
}' | jq -r .id)
# 2. Poll until it finishes. Each call waits up to 30 seconds.
while :; do
JOB=$(curl -s "https://staglight.ai/api/v1/jobs/$JOB_ID?wait=30" -H "Authorization: Bearer $STAGLIGHT_API_KEY")
case "$(echo "$JOB" | jq -r .status)" in queued|running) ;; *) break ;; esac
done
# 3. Download the result from outputs[0].download_url.
DOWNLOAD_URL=$(echo "$JOB" | jq -r '.outputs[0].download_url')
curl -L -o result.mp4 "$DOWNLOAD_URL"
import os, uuid, requests
BASE = "https://staglight.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['STAGLIGHT_API_KEY']}"}
# 0. Upload your file first and put the id it prints in params.
with open("your-file", "rb") as f:
print(requests.post(f"{BASE}/uploads", headers=HEADERS, files={"file": f}, timeout=300).json()["id"])
# 1. Create the job. It is charged once and refunded if it fails.
r = requests.post(f"{BASE}/jobs", timeout=60,
headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
json={
"op": "video.lipsync",
"params": {
"video": "med_your_upload_id",
"audio": "med_your_upload_id",
"own_footage": True,
"mode": "basic"
}
})
r.raise_for_status()
job = r.json()
# 2. Poll until it finishes. Each call waits up to 30 seconds.
while job["status"] in ("queued", "running"):
job = requests.get(f"{BASE}/jobs/{job['id']}", headers=HEADERS,
params={"wait": 30}, timeout=60).json()
# 3. Download the result from outputs[0].download_url.
print(job["outputs"][0]["download_url"] if job["outputs"] else job["data"] or job["error"])
// Node 18 or newer. Save as run.mjs: top-level await needs a module.
const BASE = "https://staglight.ai/api/v1";
const headers = { Authorization: `Bearer ${process.env.STAGLIGHT_API_KEY}` };
// 0. Upload your file first and put the id it prints in params.
// const form = new FormData(); form.append('file', yourFile);
// const { id } = await (await fetch(`${BASE}/uploads`, { method: 'POST', headers, body: form })).json();
// 1. Create the job. It is charged once and refunded if it fails.
let res = await fetch(`${BASE}/jobs`, {
method: "POST",
headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
"op": "video.lipsync",
"params": {
"video": "med_your_upload_id",
"audio": "med_your_upload_id",
"own_footage": true,
"mode": "basic"
}
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
let job = await res.json();
// 2. Poll until it finishes. Each call waits up to 30 seconds.
while (job.status === "queued" || job.status === "running") {
job = await (await fetch(`${BASE}/jobs/${job.id}?wait=30`, { headers })).json();
}
// 3. Download the result from outputs[0].download_url.
console.log(job.outputs[0]?.download_url ?? job.data ?? job.error);
{
"id": "job_19a2b3c4d5e6f7a8b9c0d1",
"op": "video.lipsync",
"status": "queued",
"credits": 108,
"title": "",
"params": {
"video": "med_your_upload_id",
"audio": "med_your_upload_id",
"own_footage": true,
"mode": "basic"
},
"progress": null,
"outputs": [],
"data": null,
"error": null,
"run_id": null,
"source": "api",
"created_at": "2026-11-06T12:00:00Z",
"finished_at": null,
"eta_seconds": 210
}
What it costs
108 cr at the default length here. The price follows the length of your text or file, and the exact price shows before the job runs.
The playground shows the exact price for your settings. A job is charged once when it is accepted, and refunded if it fails. The price is checked again with your file before it runs.
Parameters
| Name | Type | Default | Allowed |
|---|---|---|---|
videorequiredVideo |
media id |
Video | |
audiorequiredAudio |
media id |
Audio | |
own_footagerequiredI confirm this footage is mine or licensed |
boolean |
||
modeMode |
enum |
basic |
basic, lite |
separate_vocalIsolate the voice in the audio |
boolean |
false |
Send these inside params. Files are media ids from POST /api/v1/uploads. View documentation
More models
-
Real output Video
Kling AI / Kling 3.0
3 to 15 s video from text or your first frame.
53 crper clip · 5 s · std
-
Real output Video
Kling AI / Kling 4.0
3 to 30 s video with sound from text or your reference pictures, in 720p or 1080p.
107 crper clip · 5 s · 720p
-
Real output Video
Kling AI / Kling 3.0 Motion Control
The character in your image copies the motion in your video.
150 crper clip · 720p · varies with length or size