Developer API

Lipsync API Platform

Generate lip-sync videos programmatically with our powerful REST API

API Keys

Manage your API authentication keys

Give your API key a memorable name (optional)

Login Required

Please log in to create and manage API keys.

Pricing That Works For You

Get started with flexible and competitive pricing plans

API Pricing

Pay as you go

Note: API credits and user credits operate independently and are not interchangeable.

Price
Credits

Notes:

Minimum charge: 5 seconds per generation
480p resolution: 2 credits per second
720p resolution: 4 credits per second
lipsync-image/video/multi 1080p: 6 credits per second, 30-credit minimum
lipsync-image/video/multi 2k: 7 credits per second, 35-credit minimum
lipsync-image/video/multi 4k: 8 credits per second, 40-credit minimum
talking-avatar: 720p/1080p/2k/4k cost 4/6/8/9 credits per rounded-up audio second
lipsync-video: If the video is longer than the audio it will be trimmed; if the audio is longer than the video it will be auto-extended. Billing uses audio length for trim cases and video length for extend cases.
lipsync-image-multi: If order is "meanwhile". Billing uses the maximum audio length; otherwise, it uses the sum of "left_audio" and "right_audio" lengths.
Example 1:
3-second audio at 720p = 5 seconds × 4 = 20 credits
(minimum charge applies)
Example 2:
10-second audio at 480p = 10 × 2 = 20 credits

Authentication

Secure your API requests

Include your API key as an Authorization header in all requests:

Authorization: Bearer sk_XXXX_YYYY

Available Endpoints

RESTful API endpoints

POST/api/v1/lipsync-video

Video-to-video lipsync (replace audio in existing video)

POST/api/v1/lipsync-image

Image + audio → single-speaker talking avatar

POST/api/v1/talking-avatar

Image + audio + prompt -> expression and motion controlled talking avatar

POST/api/v1/lipsync-image-multi

Image + dual audio → multi-speaker avatar (conversation/dialogue)

GET/api/v1/jobs/{requestId}

Query job status and retrieve result

Current API Scope

Input, privacy, model coverage, and production notes

Inputs are URL-based

The public API currently accepts media URLs in JSON. Direct multipart file upload and asset-upload endpoints are not available yet. Signed or temporary URLs are supported as long as our workers and the generation provider can fetch them while the job is running.

API outputs are private

API jobs are stored with private visibility. The web Public toggle does not apply to API requests, and there is currently no API parameter to publish a generation.

Model selection

Select the workflow by endpoint: lipsync-image, lipsync-video, or lipsync-image-multi. Use talking-avatar for the expression and motion control image model.

No OpenAPI file yet

This page is the current API reference. A machine-readable OpenAPI/Swagger specification is not currently published.

Unsupported controls

Aspect ratio, guidance scale, and audio guidance are not exposed as API parameters for the current lip-sync endpoints.

Batch jobs

Submit one API request per generation. For large production batches, keep input URLs valid until completion and contact support before running very high concurrency.

Detailed API Parameters

Complete endpoint specifications

All endpoints share a common structure with optional webhook parameter and model-specific formState parameters.

POST /api/v1/lipsync-video

Replace the audio in an existing video with new audio while maintaining lip-sync

Top-level Parameters:
webhookoptional

Your callback URL (HTTPS). We POST the result here when complete.

formStaterequired

Object containing all generation parameters (see below).

formState Parameters:
videorequired

Public URL to source video (MP4, MOV, etc.)

audiorequired

Public URL to speech/replacement audio (MP3, WAV, etc.)

resolutionrequired

"360p", "480p", "720p", "1080p", "2k", or "4k"

mask_imageoptional

Public URL to mask image (constrains lip-sync area to masked region)

promptoptional

Text prompt for style guidance

seedoptional

Integer random seed for reproducibility

Async Workflow

Choose how to receive your results

All API calls are asynchronous. You have two options to retrieve results:

For 1080p, 2k, and 4k jobs, webhook and polling responses return only the final upscaled video result.

Option 1: Webhook (Recommended)

Provide a webhook URL in the JSON body. We will POST the result to your endpoint when the job completes.

Webhook URLs must be public HTTPS URLs. If delivery fails, we retry up to 5 times with exponential backoff.

Benefits:
  • No need to poll repeatedly
  • Instant notification when job completes
  • More efficient for long-running jobs (30-120 seconds typical)

Option 2: Polling

Omit the webhook parameter and use the returned requestId to poll GET /api/v1/jobs/{requestId} every 5-10 seconds until status is 'completed'.

Use when:
  • You cannot expose a public webhook endpoint
  • Testing or debugging

Example with Webhook:

POST /api/v1/lipsync-image
Authorization: Bearer sk_XXXX_YYYY
Content-Type: application/json

{
  "webhook": "https://your-app.example.com/webhooks/lipsync",
  "formState": {
    "image": "https://.../face.png",
    "audio": "https://.../voice.mp3",
    "resolution": "720p",
    "seed": 42
  }
}

// Immediate Response:
{
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "message": "Task submitted successfully. Use requestId to query job status."
}

// Later, when job completes, we POST to your webhook:
POST https://your-app.example.com/webhooks/lipsync
Content-Type: application/json

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "model": "lipsync-image",
  "status": "completed",
  "output": "https://.../result.mp4",
  "error": "",
  "executionTime": 12345,
  "timings": null
}

Talking Avatar Request Example:

POST /api/v1/talking-avatar
Authorization: Bearer sk_XXXX_YYYY
Content-Type: application/json

{
  "webhook": "https://your-app.example.com/webhooks/lipsync",
  "formState": {
    "image": "https://.../character.png",
    "audio": "https://.../speech.mp3",
    "prompt": "Warm presentation style, natural facial expression, subtle head motion",
    "resolution": "1080p"
  }
}

// Completed webhook or polling response:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "model": "talking-avatar",
  "status": "completed",
  "output": "https://.../result.mp4",
  "error": "",
  "executionTime": 12345,
  "timings": null
}

Example without Webhook (Polling):

// Step 1: Submit job (no webhook parameter)
POST /api/v1/lipsync-image
Authorization: Bearer sk_XXXX_YYYY
Content-Type: application/json

{
  "formState": {
    "image": "https://.../face.png",
    "audio": "https://.../voice.mp3",
    "resolution": "720p"
  }
}

// Immediate Response:
{
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "message": "Task submitted successfully. Use requestId to query job status."
}

// Step 2: Poll for status (repeat every 5-10 seconds)
GET /api/v1/jobs/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer sk_XXXX_YYYY

// Response while processing:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "model": "lipsync-image",
  "status": "processing",
  "output": null,
  "error": "",
  "executionTime": null,
  "timings": null
}

// Response when completed:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "model": "lipsync-image",
  "status": "completed",
  "output": "https://.../result.mp4",
  "error": "",
  "executionTime": 12345,
  "timings": null
}

// Response if failed:
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "model": "lipsync-image",
  "status": "failed",
  "output": null,
  "error": "Generation failed. Please try again later.",
  "executionTime": null,
  "timings": null
}

Complete Code Examples

Ready-to-use integration examples

01Node.js with Webhook (Recommended)

import fetch from 'node-fetch';
import express from 'express';

const API_KEY = 'Bearer sk_XXXX_YYYY';
const BASE_URL = 'https://lipsync.studio/api/v1';

// Set up webhook server to receive results
const app = express();
app.use(express.json());

app.post('/webhooks/lipsync', (req, res) => {
  const { id, status, output, error, model } = req.body;
  
  console.log('Job update received.');
  console.log('Job ID:', id);
  console.log('Model:', model);
  console.log('Status:', status);
  if (status === 'completed') {
    console.log('Video URL:', output);
  } else if (status === 'failed') {
    console.error('Error:', error);
  }
  
  // TODO: Save output URL to your database, send notification, etc.
  
  res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

// Submit job with webhook
async function submitJobWithWebhook() {
  const webhookUrl = 'https://your-public-domain.com/webhooks/lipsync';
  
  const res = await fetch(`${BASE_URL}/lipsync-image`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': API_KEY
    },
    body: JSON.stringify({
      webhook: webhookUrl,
      formState: {
        image: 'https://example.com/portrait.jpg',
        audio: 'https://example.com/speech.mp3',
        resolution: '720p'
      }
    })
  });
  
  const data = await res.json();
  console.log('Job submitted:', data.requestId);
  console.log('Waiting for webhook callback...');
  
  // You don't need to poll! The result will be POSTed to your webhook.
}

submitJobWithWebhook();