> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yelinai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Async API

> Veo-3.1 async video generation API with task queue for better stability

**Async Endpoint:** `https://api.yelinai.com/v1/videos`**Workflow:** Three steps (Create Task → Query Status → Get Video)**Advantages:** More Stable | Task Queue | Long Tasks Support | No Charge on Failure

## Why Choose Async API?

## Higher Stability

Based on task queue, avoids long connection timeout issues

## No Charge on Failure ⭐

**Major Advantage**: No charge for any failure

* ✓ Content violation → No charge
* ✓ Queue timeout → No charge
* ✓ Generation failed → No charge

Sync API charges as long as request succeeds (HTTP 200), even if generation fails!

## Flexible Polling

Query task status and progress anytime

## Batch Processing

Suitable for batch generation and background tasks

## Sync vs Async Comparison

| Feature               | Sync API                            | Async API (Recommended)      |
| --------------------- | ----------------------------------- | ---------------------------- |
| **Workflow**          | Single request waits for completion | Create task then poll        |
| **Endpoint**          | `/v1/chat/completions`              | `/v1/videos`                 |
| **Model Selection**   | Via model parameter                 | Via model parameter          |
| **Image-to-Video**    | Supports URL and Base64             | Supports URL                 |
| **Charge on Failure** | Charges even if generation fails    | ⭐ No charge on failure       |
| **Stability**         | Depends on long connections         | ⭐⭐⭐⭐⭐ More stable            |
| **Progress View**     | Streaming output                    | Poll progress percentage     |
| **Timeout Handling**  | Needs long timeout                  | Tasks run independently      |
| **Use Cases**         | Quick testing, real-time feedback   | Production, batch generation |

**Recommend using Async API**, especially in production environments or when batch generating videos for better stability.

## Quick Start

Async workflow consists of three steps:

1

Create Video Task

POST request to create task, get task ID

2

Query Task Status

Periodically poll for generation progress

3

Download Video

Get video file after task completes

### Complete Example

Step 1: Create Task (Text-to-Video)

Step 1: Create Task (Image-to-Video - Single Image)

Step 1: Create Task (Image-to-Video - First/Last Frame)

Step 2: Query Status

Step 3: Get Video

```
curl -X POST "https://api.yelinai.com/v1/videos" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1",
    "prompt": "A cute cat playing with a ball in a sunny garden"
  }'

# Response example
{
  "id": "video_abc123",
  "object": "video",
  "created": 1762181811,
  "status": "queued",
  "model": "veo-3.1"
}
```

## API Endpoints

### 1. Create Video Task

**POST** `https://api.yelinai.com/v1/videos`Create a new video generation task

#### Request Parameters

| Parameter         | Type   | Required | Description                                                                               |
| ----------------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
| `model`           | string | ✓        | Model name (see model list below)                                                         |
| `prompt`          | string | ✓        | Video generation prompt                                                                   |
| `input_reference` | file   | ❌        | Image file, supports 1-2 images (2 images for first/last frame mode, multipart/form-data) |

#### Available Models

| Model Name                  | Aspect    | Speed    | Image-to-Video | Price          |
| --------------------------- | --------- | -------- | -------------- | -------------- |
| `veo-3.1`                   | Portrait  | Standard | ❌              | \$0.25/request |
| `veo-3.1-fl`                | Portrait  | Standard | ✅              | \$0.25/request |
| `veo-3.1-fast`              | Portrait  | Fast     | ❌              | \$0.15/request |
| `veo-3.1-fast-fl`           | Portrait  | Fast     | ✅              | \$0.15/request |
| `veo-3.1-landscape`         | Landscape | Standard | ❌              | \$0.25/request |
| `veo-3.1-landscape-fl`      | Landscape | Standard | ✅              | \$0.25/request |
| `veo-3.1-landscape-fast`    | Landscape | Fast     | ❌              | \$0.15/request |
| `veo-3.1-landscape-fast-fl` | Landscape | Fast     | ✅              | \$0.15/request |

**Model Naming Convention:**

* `landscape` = Landscape (16:9)
* `fast` = Fast version (cheaper)
* `fl` = Supports frame-to-video (image-to-video)

**First/Last Frame Feature**Image-to-video models (with `-fl` suffix) support uploading 2 images:

* **First image**: Video start frame
* **Second image**: Video end frame

The API will automatically generate a smooth transition animation from start frame to end frame.

#### Response Fields

| Field     | Type    | Description                                   |
| --------- | ------- | --------------------------------------------- |
| `id`      | string  | Unique task identifier for subsequent queries |
| `object`  | string  | Fixed as `"video"`                            |
| `model`   | string  | Model used                                    |
| `status`  | string  | Task status: `"queued"`                       |
| `created` | integer | Creation timestamp                            |

### 2. Query Task Status

**GET** `https://api.yelinai.com/v1/videos/{video_id}`Query the current status of a video generation task

#### Path Parameters

| Parameter  | Type   | Required | Description                         |
| ---------- | ------ | -------- | ----------------------------------- |
| `video_id` | string | ✓        | Task ID returned when creating task |

#### Response Fields

| Field     | Type    | Description             |
| --------- | ------- | ----------------------- |
| `id`      | string  | Task ID                 |
| `object`  | string  | Fixed as `"video"`      |
| `model`   | string  | Model used              |
| `status`  | string  | Task status (see below) |
| `prompt`  | string  | Original prompt         |
| `created` | integer | Creation timestamp      |

#### Task Status Description

| Status       | Description         | Next Action               |
| ------------ | ------------------- | ------------------------- |
| `queued`     | Task queued         | Continue polling          |
| `processing` | Generating          | Continue polling          |
| `completed`  | Generation complete | Call get content endpoint |
| `failed`     | Generation failed   | Check error message       |

### 3. Get Video Content

**GET** `https://api.yelinai.com/v1/videos/{video_id}/content`Get the actual content of a completed video

#### Path Parameters

| Parameter  | Type   | Required | Description |
| ---------- | ------ | -------- | ----------- |
| `video_id` | string | ✓        | Task ID     |

#### Response Fields

| Field        | Type    | Description              |
| ------------ | ------- | ------------------------ |
| `id`         | string  | Task ID                  |
| `object`     | string  | Fixed as `"video"`       |
| `status`     | string  | Task status              |
| `model`      | string  | Model used               |
| `prompt`     | string  | Original prompt          |
| `url`        | string  | Video download URL       |
| `duration`   | integer | Video duration (seconds) |
| `resolution` | string  | Video resolution         |
| `created`    | integer | Creation timestamp       |

**Important**Video URLs are typically valid for **24 hours**. Please download and save locally promptly!

## Complete Code Examples

### Python Example (with Polling Logic)

```
import requests
import time
import os

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.yelinai.com/v1"

# Step 1: Create video task
def create_video_task(prompt, model="veo-3.1", image_paths=None):
    """Create video generation task

    Args:
        prompt: Video generation prompt
        model: Model name
        image_paths: Image path(s), can be:
            - None: Text-to-video
            - str: Single image path
            - list: Multiple image paths (first/last frame mode, max 2)
    """
    url = f"{BASE_URL}/videos"
    headers = {"Authorization": f"Bearer {API_KEY}"}

    if image_paths:
        # Convert to list for uniform handling
        if isinstance(image_paths, str):
            image_paths = [image_paths]

        # Image-to-Video: Use multipart/form-data to upload images
        files = []
        for path in image_paths:
            if not os.path.exists(path):
                raise FileNotFoundError(f"Image file not found: {path}")
            files.append(("input_reference", (os.path.basename(path), open(path, 'rb'), "image/jpeg")))

        data = {"model": model, "prompt": prompt}
        response = requests.post(url, headers=headers, files=files, data=data)

        # Close file handles
        for _, (_, f, _) in files:
            f.close()
    else:
        # Text-to-Video: Use JSON format
        headers["Content-Type"] = "application/json"
        data = {"model": model, "prompt": prompt}
        response = requests.post(url, headers=headers, json=data)

    response.raise_for_status()
    return response.json()

# Step 2: Poll for status
def wait_for_video(video_id, poll_interval=5, timeout=600):
    """Wait for video generation to complete"""
    url = f"{BASE_URL}/videos/{video_id}"
    headers = {"Authorization": f"Bearer {API_KEY}"}
    start_time = time.time()

    while True:
        # Check timeout
        if time.time() - start_time > timeout:
            raise TimeoutError(f"Video generation timeout ({timeout}s)")

        # Query status
        response = requests.get(url, headers=headers)
        response.raise_for_status()
        task = response.json()

        status = task["status"]
        print(f"Status: {status}")

        if status == "completed":
            return task
        elif status == "failed":
            raise Exception("Generation failed")

        # Wait and retry
        time.sleep(poll_interval)

# Step 3: Get video content
def get_video_content(video_id):
    """Get video content and URL"""
    url = f"{BASE_URL}/videos/{video_id}/content"
    headers = {"Authorization": f"Bearer {API_KEY}"}

    response = requests.get(url, headers=headers)
    response.raise_for_status()
    return response.json()

# Step 4: Download video
def download_video(video_url, save_path="video.mp4"):
    """Download video file"""
    response = requests.get(video_url, stream=True)
    response.raise_for_status()

    with open(save_path, 'wb') as f:
        for chunk in response.iter_content(chunk_size=8192):
            if chunk:
                f.write(chunk)

    print(f"Video saved to: {save_path}")

# Complete workflow
def generate_video_async(prompt, model="veo-3.1"):
    """Complete async video generation workflow"""
    print("1. Creating video task...")
    task = create_video_task(prompt, model)
    video_id = task["id"]
    print(f"   Task ID: {video_id}")

    print("\n2. Waiting for video generation...")
    completed_task = wait_for_video(video_id)
    print("   Generation complete!")

    print("\n3. Getting video content...")
    content = get_video_content(video_id)
    video_url = content["url"]
    print(f"   Video URL: {video_url}")

    print("\n4. Downloading video...")
    download_video(video_url)
    print("\n✅ Done!")

# Usage example
if __name__ == "__main__":
    # Text-to-video - Portrait standard
    # Text-to-video - Portrait standard
    generate_video_async(
        prompt="A cute cat playing with a ball in a sunny garden",
        model="veo-3.1"
    )

    # Image-to-Video - Single image mode
    # task = create_video_task(
    #     prompt="Make this cat blink slowly",
    #     model="veo-3.1-fl",
    #     image_paths="test.jpg"
    # )

    # Image-to-Video - First/Last frame mode (2 images)
    # First image = start frame, Second image = end frame
    # task = create_video_task(
    #     prompt="Smoothly transition from start to end frame with dynamic effects",
    #     model="veo-3.1-landscape-fl",
    #     image_paths=["start_frame.jpg", "end_frame.jpg"]
    # )
```

### JavaScript/Node.js Example

```
const axios = require('axios');
const fs = require('fs');

const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.yelinai.com/v1';

// Create video task
async function createVideoTask(prompt, model = 'veo-3.1') {
  const response = await axios.post(`\`$\{BASE_URL}/videos`, {
    model,
    prompt
  }, {
    headers: { 'Authorization': `Bearer \`$\{API_KEY}` }
  });

  return response.data;
}

// Poll for status
async function waitForVideo(videoId, pollInterval = 5000, timeout = 600000) {
  const startTime = Date.now();

  while (true) {
    // Check timeout
    if (Date.now() - startTime > timeout) {
      throw new Error(`Video generation timeout (\`$\{timeout/1000}s)`);
    }

    // Query status
    const response = await axios.get(`\`$\{BASE_URL}/videos/\`$\{videoId}`, {
      headers: { 'Authorization': `Bearer \`$\{API_KEY}` }
    });

    const task = response.data;
    const { status } = task;

    console.log(`Status: \`$\{status}`);

    if (status === 'completed') {
      return task;
    } else if (status === 'failed') {
      throw new Error('Generation failed');
    }

    // Wait and retry
    await new Promise(resolve => setTimeout(resolve, pollInterval));
  }
}

// Get video content
async function getVideoContent(videoId) {
  const response = await axios.get(`\`$\{BASE_URL}/videos/\`$\{videoId}/content`, {
    headers: { 'Authorization': `Bearer \`$\{API_KEY}` }
  });

  return response.data;
}

// Download video
async function downloadVideo(videoUrl, savePath = 'video.mp4') {
  const response = await axios.get(videoUrl, { responseType: 'stream' });

  const writer = fs.createWriteStream(savePath);
  response.data.pipe(writer);

  return new Promise((resolve, reject) => {
    writer.on('finish', () => {
      console.log(`Video saved to: \`$\{savePath}`);
      resolve();
    });
    writer.on('error', reject);
  });
}

// Complete workflow
async function generateVideoAsync(prompt, model = 'veo-3.1') {
  try {
    console.log('1. Creating video task...');
    const task = await createVideoTask(prompt, model);
    const videoId = task.id;
    console.log(`   Task ID: \`$\{videoId}`);

    console.log('\n2. Waiting for video generation...');
    await waitForVideo(videoId);
    console.log('   Generation complete!');

    console.log('\n3. Getting video content...');
    const content = await getVideoContent(videoId);
    const videoUrl = content.url;
    console.log(`   Video URL: \`$\{videoUrl}`);

    console.log('\n4. Downloading video...');
    await downloadVideo(videoUrl);
    console.log('\n✅ Done!');

  } catch (error) {
    console.error('Error:', error.message);
  }
}

// Usage example
generateVideoAsync(
  'A cute cat playing with a ball in a sunny garden',
  'veo-3.1'
);
```

## Best Practices

Polling Interval Settings

**Recommended polling interval: 5-10 seconds**

```
# Recommended
poll_interval = 5  # Query every 5 seconds

# Not recommended
poll_interval = 1  # Too frequent, wastes requests
poll_interval = 30 # Too slow, poor user experience
```

**Reasons:**

* Video generation typically takes 2-5 minutes
* 5-10 seconds provides timely feedback
* Avoids excessive requests

Timeout Handling

**Recommended timeout: 10 minutes (600 seconds)**

```
def wait_for_video(video_id, timeout=600):
    start_time = time.time()

    while True:
        if time.time() - start_time > timeout:
            # Handle timeout
            print(f"Task {video_id} timed out, can query later")
            break

        # Query logic...
```

**Note:**

* Task timeout doesn’t auto-cancel
* Can continue querying the same video\_id later
* Tasks are valid for 24 hours

Error Retry Strategy

**Recommended retry logic:**

```
def create_video_with_retry(prompt, model, max_retries=3):
    for i in range(max_retries):
        try:
            return create_video_task(prompt, model)
        except Exception as e:
            if i < max_retries - 1:
                print(f"Creation failed, retrying in 5s... ({i+1}/{max_retries})")
                time.sleep(5)
            else:
                raise
```

**Retry scenarios:**

* ✓ Network error → Retry
* ✓ Service busy (503) → Retry
* ✗ Content violation → Don’t retry, modify prompt
* ✗ Insufficient balance → Don’t retry, top up first

Batch Generation Optimization

**Concurrency control suggestions:**

```
import concurrent.futures

def batch_generate_videos(prompts, model="veo-3.1", max_workers=5):
    """Batch generate videos with concurrency control"""
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        # Create all tasks
        future_to_prompt = {
            executor.submit(create_video_task, prompt, model): prompt
            for prompt in prompts
        }

        video_ids = []
        for future in concurrent.futures.as_completed(future_to_prompt):
            task = future.result()
            video_ids.append(task['id'])

        # Wait for all tasks concurrently
        futures = [executor.submit(wait_for_video, vid) for vid in video_ids]
        results = [f.result() for f in concurrent.futures.as_completed(futures)]

        return results
```

**Suggestions:**

* Task creation: Can be highly concurrent (10-30)
* Status query: Recommend concurrency ≤ 10
* Video download: Recommend concurrency ≤ 5

## Pricing

Async API has **same pricing** as Sync API, charged per request.

| Model Type               | Price          | With \$100 top-up |
| ------------------------ | -------------- | ----------------- |
| Standard (veo-3.1 etc.)  | \$0.25/request | ≈ ¥1.7/request    |
| Fast (veo-3.1-fast etc.) | \$0.15/request | ≈ ¥1.0/request    |

**Billing Rules:**

* ✓ Only charge when video **successfully generates** (status = “completed”)
* ✗ Failure, timeout, cancellation **no charge**
* ✗ Content safety failure **also no charge** (major difference from sync API ⭐)
* ✗ Status queries are free

**Major advantage of Async API**: No charge for failures of any kind, including content safety review failures. Sync API charges as long as request succeeds, even if generation ultimately fails.

## FAQ

How long are tasks valid?

**Task validity: 24 hours**

* Can query task status anytime within 24 hours after creation
* Video files are stored for 24 hours after generation completes
* Tasks and videos are automatically cleaned up after 24 hours

**Recommendations:**

* Download immediately after video generation completes
* Don’t rely on server for long-term storage

Why am I getting 404 when querying?

**Possible reasons:**

1. **Incorrect video\_id** - Check if copied completely
2. **Task expired** - Over 24 hours
3. **Network issue** - Retry the request

**Solution:**

```
try:
    response = requests.get(f"{BASE_URL}/videos/{video_id}", headers=headers)
    task = response.json()
except requests.exceptions.HTTPError as e:
    if e.response.status_code == 404:
        print("Task doesn't exist or has expired")
    else:
        raise
```

Can I mix async and sync APIs?

**Yes, they’re completely independent**The two API systems are completely separate:

* Different endpoints
* Different workflows
* Same pricing
* Share the same API Key and balance

**Usage recommendations:**

* Quick testing → Use Sync API
* Production → Use Async API (more stable)
* Batch generation → Use Async API

How to choose the right model?

**Choose based on needs:**

| Need                           | Recommended Model                          |
| ------------------------------ | ------------------------------------------ |
| Quick testing                  | `veo-3.1-fast`                             |
| Standard portrait video        | `veo-3.1`                                  |
| Standard landscape video       | `veo-3.1-landscape`                        |
| Image-to-video (portrait)      | `veo-3.1-fl`                               |
| Image-to-video (landscape)     | `veo-3.1-landscape-fl`                     |
| Batch generation (cost-saving) | `veo-3.1-fast` or `veo-3.1-landscape-fast` |

## Error Handling

### Common Error Codes

| HTTP Code | Error Type            | Description                     | Solution                          |
| --------- | --------------------- | ------------------------------- | --------------------------------- |
| 400       | Bad Request           | Request parameter error         | Check parameter format and values |
| 401       | Unauthorized          | Invalid API Key                 | Check Authorization header        |
| 402       | Payment Required      | Insufficient balance            | Top up and retry                  |
| 404       | Not Found             | Task doesn’t exist              | Check video\_id or task expired   |
| 429       | Too Many Requests     | Request too frequent            | Reduce polling frequency          |
| 500       | Internal Server Error | Server error                    | Retry later                       |
| 503       | Service Unavailable   | Service temporarily unavailable | Wait and retry                    |

### Error Response Format

```
{
  "error": {
    "code": "invalid_api_key",
    "message": "Invalid API key provided",
    "type": "authentication_error"
  }
}
```

## Technical Support

## Need Help?

If you have questions, feel free to contact us:

* **Email:** [threezhang.cn@gmail.com](mailto:threezhang.cn@gmail.com)
* **WeChat:** Kikivivikids
* **Telegram:** [https://t.me/laozhang\_cn](https://t.me/laozhang_cn)
* **Docs:** []()

## Next Steps

## Sync API

View sync calling method (OpenAI compatible)

## Code Examples

View more application examples

## Model Overview

Learn about Veo-3.1 model details

## Troubleshooting

View more Q\&A
