lipsyn.cc API

Generate AI lip-sync videos programmatically. Asynchronous, minute-based pricing, webhook or polling delivery.

Getting Started: Create an API key in your account settings, then purchase prepaid minutes. Each lip-sync render consumes minutes based on video length and resolution. Manage API keys →

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:

ResolutionMultiplier
Below 720p1× video length
720p and higher2× 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"
  },
  "width": 1280,                  // optional requested output width in pixels
  "height": 720,                  // optional requested output height in pixels
  "webhookUrl": "https://your-app.com/webhook",
  "language": "en-US"
}

Optional width and height request output dimensions in pixels. For example, use 1280 × 720 for landscape or 720 × 1280 for portrait. The API accepts dimensions rather than named resolution presets. If omitted, it uses the source dimensions and processing defaults. For multipart requests, pass width and height as numeric form fields.

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, MP4, M4A, WAV, FLAC, AAC, OGG, WEBM, MPG, MPEG)
  video       - Video file (MP4, M4V, WebM, MPG, MPEG) OR
  image       - Image file (JPG, JPEG, PNG, GIF, WEBP)
  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)
  width       - Optional output width in pixels
  height      - Optional output height in pixels
  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": 3,                    // numeric status code (see below)
  "videoUrl": "https://...",      // preview or full video URL
  "fullUrl": "https://...",       // full video URL (when status is 5)
  "previewUrl": "https://...",    // preview URL
  "length": 15,                   // duration in seconds
  "height": 720,                  // video height in pixels
  "errorCode": null,
  "errorMessage": null
}

Status Values

  • 0 — New — Video created, waiting for processing
  • 2 — Processing — Currently being processed
  • 3 — Preview Ready — Preview is available at previewUrl
  • 5 — Full Ready — Full video is available at fullUrl
  • 99 — Error — Processing failed, check errorMessage

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 (same API key)
curl -H "Authorization: Bearer lip_your_api_key_here" \
  https://www.lipsyn.cc/api/video/abc-123

Python — 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 (same API key works for both endpoints)
while True:
    resp = requests.get(
        f"https://www.lipsyn.cc/api/video/{video_id}",
        headers=HEADERS,
    )
    video = resp.json()
    status = video["status"]
    print(f"Status code: {status}")

    if status == 5:  # FULL_PROCESSED
        video_url = video["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 == 99:  # ERROR
        print(f"Error: {video['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 fallback

Python — 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

StatusMeaning
202Accepted — video queued for processing
400Bad request — missing or invalid parameters
401Unauthorized — invalid or missing API key
402Payment required — insufficient minute balance
413File too large — max 512 MB
429Too many requests — rate limit exceeded
500Internal server error

Rate Limits

  • 60 requests per minute per API key
  • Max file size: 512 MB per upload
  • Max source video and audio duration: 120 minutes; avatar duration: 5 minutes
  • Concurrent processing: 5 videos per account

Full examples: Clone the lipsyn-cc/api-examples repo for complete Python and Node.js client libraries with ready-to-run examples.

Questions? Contact support@lipsyn.cc