Quickstart
create your first lipsync generation in minutes
Create your API Key
Create your API key from the Dashboard. You will use this key to securely access the Sync API.
Make your first generation
The following example shows how to make a lipsync generation using the Sync API.
Install dependencies
pip install requests
Make your first generation
Copy the following code into a file called quickstart.py
and replace YOUR_API_KEY_HERE
with your generated API key.
import requests
import time
# ---------- UPDATE API KEY ----------
api_key = "YOUR_API_KEY_HERE" # Replace with your Sync.so API key
# ----------[OPTIONAL] UPDATE INPUT VIDEO AND AUDIO URL ----------
video_url = "https://synchlabs-public.s3.us-west-2.amazonaws.com/david_demo_shortvid-03a10044-7741-4cfc-816a-5bccd392d1ee.mp4" # URL to your source video
audio_url = "https://synchlabs-public.s3.us-west-2.amazonaws.com/david_demo_shortaud-27623a4f-edab-4c6a-8383-871b18961a4a.wav" # URL to your audio file
# ----------------------------------------
api_url = "https://api.sync.so/v2/generate"
headers = {
"x-api-key": api_key,
"Content-Type": "application/json"
}
def submit_generation():
payload = {
"model": "lipsync-1.9.0-beta",
"options": {
"output_format": "mp4"
},
"input": [
{"type": "video", "url": video_url},
{"type": "audio", "url": audio_url}
]
}
response = requests.post(api_url, json=payload, headers=headers, timeout=30)
if response.status_code == 201:
print("Generation submitted successfully, job id:", response.json()["id"])
return response.json()["id"]
else:
print(response.text)
raise Exception(f"Failed to submit generation: {response.status_code}")
def poll_job(job_id):
poll_url = f"{api_url}/{job_id}"
while True:
response = requests.get(poll_url, headers=headers, timeout=10)
try:
result = response.json()
status = result["status"]
except:
print(response.text)
raise Exception(f"Failed to poll job: {response.status_code}")
terminal_statuses = ['COMPLETED', 'FAILED', 'REJECTED', 'CANCELLED']
if status in terminal_statuses:
if status == 'COMPLETED':
generated_video_url = result["outputUrl"]
print(f"Job {job_id} completed!")
print(f"Generated video URL: {generated_video_url}")
break
else:
print(f"Job {job_id} failed with status: {status}")
print(response.text)
break
else:
time.sleep(10)
print("Starting lip sync generation job...")
job_id = submit_generation()
poll_job(job_id)
Run the script:
python quickstart.py
Done!
It may take a few minutes for the generation to complete. You should see the generated video URL in the terminal post completion.
Install dependencies
npm install
Make your first generation
Copy the following code into a file called quickstart.js
and replace YOUR_API_KEY_HERE
with your generated API key.
// ---------- UPDATE API KEY ----------
const apiKey = "YOUR_API_KEY_HERE"; // Replace with your Sync.so API key
// ----------[OPTIONAL] UPDATE VIDEO AND AUDIO URL ----------
const videoUrl = "https://synchlabs-public.s3.us-west-2.amazonaws.com/david_demo_shortvid-03a10044-7741-4cfc-816a-5bccd392d1ee.mp4"; // URL to your source video
const audioUrl = "https://synchlabs-public.s3.us-west-2.amazonaws.com/david_demo_shortaud-27623a4f-edab-4c6a-8383-871b18961a4a.wav"; // URL to your audio file
// ----------------------------------------
const apiUrl = "https://api.sync.so/v2/generate";
const headers = {
"x-api-key": apiKey,
"Content-Type": "application/json"
};
async function submitGeneration() {
const payload = {
model: "lipsync-1.9.0-beta",
options: {
output_format: "mp4"
},
input: [
{ type: "video", url: videoUrl },
{ type: "audio", url: audioUrl }
]
};
try {
const response = await fetch(apiUrl, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
});
if (response.status === 201) {
const data = await response.json();
console.log("Generation submitted successfully, job id:", data.id);
return data.id;
} else {
const errorText = await response.text();
console.log(errorText);
throw new Error(`Failed to submit generation: ${response.status}`);
}
} catch (error) {
console.error("Error submitting job:", error);
throw error;
}
}
async function pollJob(jobId) {
const pollUrl = `${apiUrl}/${jobId}`;
while (true) {
try {
const response = await fetch(pollUrl, { headers });
const result = await response.json();
const status = result.status;
const terminalStatuses = ['COMPLETED', 'FAILED', 'REJECTED', 'CANCELLED'];
if (terminalStatuses.includes(status)) {
if (status === 'COMPLETED') {
const generatedVideoUrl = result.outputUrl;
console.log(`Job ${jobId} completed!`);
console.log(`Generated video URL: ${generatedVideoUrl}`);
break;
} else {
console.log(`Job ${jobId} failed with status: ${status}`);
console.log(JSON.stringify(result, null, 2));
break;
}
} else {
await new Promise(resolve => setTimeout(resolve, 10000));
}
} catch (error) {
console.error("Error polling job:", error);
throw error;
}
}
}
async function main() {
console.log("Starting lip sync generation job...");
try {
const jobId = await submitGeneration();
await pollJob(jobId);
} catch (error) {
console.error("Error in main process:", error);
}
}
main();
Run the script:
node quickstart.js
Done!
You should see the generated video URL in the terminal.
Well done! You’ve just made your first lipsync generation with sync.so!
Ready to unlock the full potential of sync.so? Dive into our interactive Playground to experiment with all available models, or explore our comprehensive API Documentation to take your lip-sync generations to the next level!