lipsyn.cc API
Generate AI lip-sync videos programmatically. Asynchronous, minute-based pricing, webhook or polling delivery.
Contents
Authentication
All API requests require a valid API key sent via the Authorization header:
Authorization: Bearer lip_your_api_key_here
Create and manage API keys in your account dashboard. Each key shows its usage (minutes processed) and last-used timestamp. You can create multiple keys for different applications, and disable or delete them individually.
Minute-Based Pricing
Each API call consumes prepaid minutes from your account. Minutes are deducted based on the output video length and resolution:
| Resolution | Multiplier |
|---|---|
| ≤ 1080p (HD) | 1× video length |
| > 1080p (4K) | 2× video length |
Purchase minute bundles from your account dashboard. Minutes never expire.
Create a Lip-Sync Video
POST https://www.lipsyn.cc/api/lipsync
JSON Request (URL-based media)
{
"audio": {
"uri": "https://example.com/audio.mp3"
// OR use TTS:
// "voice": "en-US-JennyNeural",
// "text": "Hello, this is a lip-sync test."
},
"video": {
"uri": "https://example.com/video.mp4"
// OR use an image:
// "imageUri": "https://example.com/photo.jpg"
// OR use a preset:
// "preset": "https://lipsyn.cc/presets/talking_avatar.mp4"
},
"webhookUrl": "https://your-app.com/webhook",
"language": "en-US"
}Multipart Form Data (file uploads)
POST /api/lipsync Content-Type: multipart/form-data Authorization: Bearer lip_your_api_key_here Fields: audio - Audio file (MP3, WAV, etc.) video - Video file (MP4, MOV, etc.) OR image - Image file (JPG, PNG) presetLink - Preset video URL (instead of video/image) voice - TTS voice name (instead of audio file) text - TTS text (required with voice) language - Language code (default: en-US) webhookUrl - Optional webhook URL
Response (202 Accepted)
{
"success": true,
"videoId": "550e8400-e29b-41d4-a716-446655440000",
"message": "Video queued for processing. Poll GET /api/video/:videoId to check status.",
"pollingUrl": "https://www.lipsyn.cc/api/video/550e8400-e29b-41d4-a716-446655440000"
}Polling for Results
Poll the video status endpoint to check when processing is complete:
GET https://www.lipsyn.cc/api/video/:videoId
Authorization: Bearer lip_your_api_key_here
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "preview_ready", // or "processing", "full_ready", "error"
"videoUrl": "https://...", // preview or full video URL
"fullUrl": "https://...", // full video URL (when status is "full_ready")
"previewUrl": "https://...", // preview URL
"length": 15, // duration in seconds
"height": 720, // video height in pixels
"errorCode": null,
"errorMessage": null
}Status Values
new— Video created, waiting for processingprocessing— Currently being processedpreview_ready— Preview (short version) is available atpreviewUrlfull_ready— Full video is available atfullUrlerror— Processing failed, checkerrorMessage
Poll every 2-5 seconds. Processing typically takes 30 seconds to 5 minutes depending on video length and queue depth.
Webhooks
Pass a webhookUrl in the create request to receive a POST when processing completes. The webhook payload:
POST {your_webhook_url}
Content-Type: application/json
{
"event": "video.completed",
"videoId": "550e8400-e29b-41d4-a716-446655440000",
"status": "full_ready",
"videoUrl": "https://...",
"fullUrl": "https://...",
"previewUrl": "https://...",
"length": 15,
"height": 720
}Your webhook endpoint should return a 200 status to acknowledge receipt. Webhooks are sent on both success and failure (status will be error).
Code Samples
cURL — Create & Poll
# Step 1: Create a lip-sync video
curl -X POST https://www.lipsyn.cc/api/lipsync \
-H "Authorization: Bearer lip_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"audio": { "uri": "https://example.com/audio.mp3" },
"video": { "uri": "https://example.com/video.mp4" },
"webhookUrl": "https://your-app.com/webhook"
}'
# Response: { "videoId": "abc-123", "pollingUrl": "..." }
# Step 2: Poll for results
curl -H "Authorization: Bearer lip_your_api_key_here" \
https://www.lipsyn.cc/api/video/abc-123Python — Polling
import requests, time
API_KEY = "lip_your_api_key_here"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Create video
resp = requests.post(
"https://www.lipsyn.cc/api/lipsync",
headers=HEADERS,
json={
"audio": {"uri": "https://example.com/audio.mp3"},
"video": {"uri": "https://example.com/video.mp4"},
},
)
data = resp.json()
video_id = data["videoId"]
print(f"Video queued: {video_id}")
# Poll until ready
while True:
resp = requests.get(
f"https://www.lipsyn.cc/api/video/{video_id}",
headers=HEADERS,
)
status = resp.json()["status"]
print(f"Status: {status}")
if status == "full_ready":
video_url = resp.json()["fullUrl"]
print(f"Video ready: {video_url}")
# Download the video
r = requests.get(video_url)
with open("output.mp4", "wb") as f:
f.write(r.content)
break
elif status == "error":
print(f"Error: {resp.json()['errorMessage']}")
break
time.sleep(3)Node.js — Webhook Receiver
import express from 'express';
const app = express();
app.post('/webhook', express.json(), (req, res) => {
const { event, videoId, status, videoUrl } = req.body;
if (event === 'video.completed') {
console.log(`Video ${videoId} is ${status}`);
if (status === 'full_ready') {
// Download or process the video
console.log(`Download from: ${videoUrl}`);
}
}
res.status(200).send('OK');
});
app.listen(3000);Python — Create with Webhook
import requests
API_KEY = "lip_your_api_key_here"
resp = requests.post(
"https://www.lipsyn.cc/api/lipsync",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"audio": {"voice": "en-US-JennyNeural", "text": "Hello world!"},
"video": {"imageUri": "https://example.com/photo.jpg"},
"webhookUrl": "https://your-server.com/webhook",
},
)
print(resp.json())
# Response includes videoId — you can also poll as a fallbackPython — File Upload (Multipart)
import requests
API_KEY = "lip_your_api_key_here"
with open("video.mp4", "rb") as vf, open("audio.mp3", "rb") as af:
resp = requests.post(
"https://www.lipsyn.cc/api/lipsync",
headers={"Authorization": f"Bearer {API_KEY}"},
files={
"video": vf,
"audio": af,
},
data={
"webhookUrl": "https://your-server.com/webhook",
},
)
print(resp.json())Error Handling
| Status | Meaning |
|---|---|
| 202 | Accepted — video queued for processing |
| 400 | Bad request — missing or invalid parameters |
| 401 | Unauthorized — invalid or missing API key |
| 402 | Payment required — insufficient minute balance |
| 413 | File too large — max 512 MB |
| 429 | Too many requests — rate limit exceeded |
| 500 | Internal server error |
Rate Limits
- 60 requests per minute per API key
- Max file size: 512 MB per upload
- Max video duration: 120 seconds
- Concurrent processing: 5 videos per account
Questions? Contact support@lipsyn.cc