> For the documentation index, fetch https://sync.so/docs/llms.txt. Append .md to a page URL for Markdown. Documentation-search MCP: https://sync.so/docs/_mcp/server.

# Quickstart

> Get started with the sync. labs lip sync API in minutes. Create your first AI lip sync generation using Python or TypeScript SDKs.

Generate your first lip-synced video with the Sync Labs API in about 5 minutes. This guide walks you through creating an API key, installing the SDK, and submitting a generation request.

### Quick reference

|                             |                                                                                                                                                                   |
| :-------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Generation time**         | Most generations complete within a few minutes, depending on model and input length                                                                               |
| **Supported video formats** | MP4 via public URL, direct upload (subject to plan and proxy limits), or asset ID — [all supported formats](/compatibility-and-tips/media-formats-support)        |
| **Supported audio formats** | WAV or MP3 via public URL, direct upload (subject to plan and proxy limits), or asset ID — [all supported formats](/compatibility-and-tips/media-formats-support) |
| **Default model**           | sync-3 — our most powerful lip sync model                                                                                                                         |
| **Free trial**              | 3 generations/month on free accounts, max 20s per generation (sync-3: 1 generation/month, 15s max), no credit card required                                       |
| **SDK requirements**        | Python 3.8+ (`pip install syncsdk`) or Node.js 18+ (`npm i @sync.so/sdk`)                                                                                         |

### How do I create an API key?

Create your API key from the [Dashboard](https://sync.so/settings/api-keys). You will use this key to securely access the Sync Labs API.

### Make your first generation

The following example shows how to make a lipsync generation using the Sync Labs API.

#### Python

#### Install Sync Labs SDK

```bash
pip install syncsdk
```

#### Make your first generation

Copy the following code into a file `quickstart.py` and set `SYNC_API_KEY` environment variable with your generated API key.

**`quickstart.py`**

```python quickstart.py
import time
from sync import Sync
from sync.common import Audio, GenerationOptions, Video
from sync.core.api_error import ApiError

# ----------[OPTIONAL] UPDATE INPUT VIDEO AND AUDIO URL ----------
# URL to your source video
video_url = "https://assets.sync.so/docs/example-video.mp4"
# URL to your audio file
audio_url = "https://assets.sync.so/docs/example-audio.wav"
# ----------------------------------------

sync = Sync()

print("Starting lip sync generation job...")

try:
    response = sync.generations.create(
        input=[Video(url=video_url), Audio(url=audio_url)],
        model="sync-3",
        options=GenerationOptions(sync_mode="cut_off"),
        output_file_name="quickstart"
    )
except ApiError as e:
    print(f'create generation request failed with status code {e.status_code} and error {e.body}')
    exit()

job_id = response.id
print(f"Generation submitted successfully, job id: {job_id}")

generation = sync.generations.get(job_id)
status = generation.status
while status not in ['COMPLETED', 'FAILED', 'REJECTED']:
    print('polling status for generation', job_id)
    time.sleep(10)
    generation = sync.generations.get(job_id)
    status = generation.status

if status == 'COMPLETED':
    print('generation', job_id, 'completed successfully, output url:', generation.output_url)
else:
    print('generation', job_id, 'failed')
```

Run the script:

```bash
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.

#### TypeScript

#### Install dependencies

```bash
npm i @sync.so/sdk
```

#### Make your first generation

Copy the following code into a file `quickstart.ts` and set `SYNC_API_KEY` environment variable with your generated API key.

**`quickstart.ts`**

```typescript quickstart.ts
import { SyncClient, SyncError } from "@sync.so/sdk";

// ----------[OPTIONAL] UPDATE INPUT VIDEO AND AUDIO URL ----------
// URL to your source video
const videoUrl = "https://assets.sync.so/docs/example-video.mp4";
// URL to your audio file
const audioUrl = "https://assets.sync.so/docs/example-audio.wav";
// ----------------------------------------

const sync = new SyncClient();

async function main() {
    console.log("Starting lip sync generation job...");

    let jobId: string;
    try {
        const response = await sync.generations.create({
            input: [
                {
                    type: "video",
                    url: videoUrl,
                },
                {
                    type: "audio",
                    url: audioUrl,
                },
            ],
            model: "sync-3",
            options: {
                sync_mode: "cut_off",
            },
            outputFileName: "quickstart"
        });
        jobId = response.id;
        console.log(`Generation submitted successfully, job id: ${jobId}`);
    } catch (err) {
        if (err instanceof SyncError) {
            console.error(`create generation request failed with status code ${err.statusCode} and error ${JSON.stringify(err.body)}`);
        } else {
            console.error('An unexpected error occurred:', err);
        }
        return;
    }

    let generation;
    let status;
    while (status !== 'COMPLETED' && status !== 'FAILED' && status !== 'REJECTED') {
        console.log(`polling status for generation ${jobId}...`);
        try {
            await new Promise(resolve => setTimeout(resolve, 10000));
            generation = await sync.generations.get(jobId);
            status = generation.status;
        } catch (err) {
            if (err instanceof SyncError) {
                console.error(`polling failed with status code ${err.statusCode} and error ${JSON.stringify(err.body)}`);
            } else {
                console.error('An unexpected error occurred during polling:', err);
            }
            status = 'FAILED';
        }
    }

    if (status === 'COMPLETED') {
        console.log(`generation ${jobId} completed successfully, output url: ${generation?.outputUrl}`);
    } else {
        console.log(`generation ${jobId} failed`);
    }
}

main(); 
```

Run the script:

```bash
npx tsx quickstart.ts -y
```

#### 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 lipsync? Dive into our interactive [Studio](https://sync.so/login) to experiment with all available models, or explore our [API Documentation](/api-reference) to take your lip-sync generations to the next level!

### Generate from a still image

With `sync-3`, replace the video input with an image and keep the audio input. Submit this JSON body to `POST /v2/generate`, then poll the returned generation ID as above. Replace the image URL with a direct URL to your own image:

```json
{
  "model": "sync-3",
  "input": [
    { "type": "image", "url": "https://example.com/portrait.jpg" },
    { "type": "audio", "url": "https://assets.sync.so/docs/example-audio.wav" }
  ]
}
```

You can also [upload your image as an asset](/developer-guides/asset-uploads) and use its `assetId` instead of `url`. See [sync-3](/models/sync-3) for image requirements and plan limits.

## Frequently Asked Questions

#### How long does a generation take?

Generation time depends on the model and input length. Most generations complete within a few minutes. You can poll the generation status using the SDK or set up webhooks to receive a notification when the job finishes. The terminal statuses are COMPLETED, FAILED, or REJECTED.

#### Can I test for free?

You can create a Sync Labs account and get an API key from the dashboard to start experimenting. Free accounts get 3 generations per month with a 20-second max duration, including at most 1 sync-3 generation with a 15-second max duration. The quickstart example uses sample video and audio URLs so you can test the workflow immediately.

#### What if my API key doesn't work?

Verify that the SYNC\_API\_KEY environment variable is set correctly before running your script. Ensure the key has not been revoked in your dashboard. A missing or invalid key returns a 401 Unauthorized error. You can create a new key from the API Keys page at any time.

## Quickstart Reference

### Prerequisites

* Sync Labs API key (create at [https://sync.so/settings/api-keys](https://sync.so/settings/api-keys))
* Python 3.7+ or Node.js 16+
* A source video or image URL and an audio URL

### SDK Install Commands

| Language   | Package Manager | Command                 |
| ---------- | --------------- | ----------------------- |
| Python     | pip             | `pip install syncsdk`   |
| Python     | poetry          | `poetry add syncsdk`    |
| Python     | uv              | `uv add syncsdk`        |
| TypeScript | npm             | `npm i @sync.so/sdk`    |
| TypeScript | yarn            | `yarn add @sync.so/sdk` |
| TypeScript | pnpm            | `pnpm add @sync.so/sdk` |

### Common Pitfalls

* Forgetting to set the `SYNC_API_KEY` environment variable before running the script
* Not polling for completion -- generations are asynchronous and require polling `GET /v2/generate/{id}` or using webhooks
* Using an invalid or expired API key (results in 401 Unauthorized)
* Audio exceeding 300 seconds (5 minutes) maximum duration

### Generation Statuses

| Status    | Meaning                                                     |
| --------- | ----------------------------------------------------------- |
| COMPLETED | Generation succeeded, `output_url` is available             |
| FAILED    | Generation failed, check error details                      |
| REJECTED  | Generation was rejected (invalid input or policy violation) |