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

# Sora 2 Video Generation (Async)

> Sora 2 Async Video Generation API - Complete 3-step workflow: Submit, Poll, Download

## Overview

The Sora 2 Async API uses a standard asynchronous processing mechanism, ideal for scenarios requiring fine-grained control over the video generation workflow. Unlike the synchronous streaming API, the async API separates video generation into three independent steps, allowing more flexible task management and download timing.

<Info>
  The Async API is particularly suitable for batch processing, background tasks, and scenarios requiring long wait times. If you need real-time progress feedback, we recommend using the [Synchronous Streaming API](/en/api-capabilities/sora-2-video).
</Info>

## Key Features

<CardGroup cols={2}>
  <Card title="Independent Task Management" icon="list-check">
    Get task ID after submission, query status anytime
  </Card>

  <Card title="Flexible Polling Strategy" icon="refresh-cw">
    Customize polling intervals to avoid unnecessary requests
  </Card>

  <Card title="Reliable Video Download" icon="download">
    Independent download after completion, supports resume
  </Card>

  <Card title="Batch Processing Support" icon="layers">
    Submit multiple tasks simultaneously for efficient concurrent processing
  </Card>
</CardGroup>

## Complete Workflow

The Async API follows a 3-step workflow:

```
Step 1: Submit Request
POST /v1/videos
↓
Returns video_id

Step 2: Poll Status (recommended every 30 seconds)
GET /v1/videos/{video_id}
↓
submitted → in_progress → completed

Step 3: Download Video
GET /v1/videos/{video_id}/content
↓
Save MP4 file
```

<Note>
  Typical generation time: 3-5 minutes. Recommended polling interval: 30 seconds, maximum wait time: 10 minutes.
</Note>

## Model Pricing

| Model Name                  | Description              | Resolution               | Price       | Stability             |
| --------------------------- | ------------------------ | ------------------------ | ----------- | --------------------- |
| `sora_video2`               | Default portrait version | 720 × 1280               | \$0.12/call | High                  |
| `sora_video2-landscape`     | Landscape version        | 1280 × 720               | \$0.12/call | High                  |
| `sora_video2-15s`           | Portrait 15s video       | 720 × 1280               | \$0.12/call | High                  |
| `sora_video2-landscape-15s` | Landscape 15s video      | 1280 × 720               | \$0.12/call | High                  |
| `sora-2-pro`                | Pro account version      | 1024 × 1792, 1792 × 1024 | \$0.8/call  | Now working properly! |

<Note>
  * Async call recommended - various errors won't incur charges;
  * Synchronous call supports streaming output to view progress;
  * Video storage valid for 1 day, download promptly;
  * Sora 2 standard versions actually output 704 px (not 720 px), this is the official behavior;
</Note>

## API Endpoint

```
https://api.apiyi.com/v1/videos
```

## Step 1: Submit Video Generation Request

### Request Parameters

| Parameter         | Type   | Required | Description                                                                          |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------ |
| `prompt`          | string | ✅        | Text description for video generation, detailed scene, action, and style recommended |
| `model`           | string | ✅        | Fixed value: `sora-2`                                                                |
| `size`            | string | ✅        | `1280x720` (landscape) or `720x1280` (portrait)                                      |
| `seconds`         | string | ✅        | Video duration, options: `10` or `15`                                                |
| `input_reference` | file   | ❌        | Reference image file (PNG/JPG/JPEG), optional, for image-to-video                    |

### Text-to-Video Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.apiyi.com/v1/videos" \
    -H "Authorization: YOUR_API_KEY" \
    -H "Accept: application/json" \
    -F "prompt=A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky" \
    -F "model=sora-2" \
    -F "size=1280x720" \
    -F "seconds=10"
  ```

  ```python Python theme={null}
  import requests

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

  # Submit text-to-video request
  files = {
      'prompt': (None, 'A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky'),
      'model': (None, 'sora-2'),
      'size': (None, '1280x720'),
      'seconds': (None, '10')
  }

  headers = {
      'Accept': 'application/json',
      'Authorization': API_KEY
  }

  response = requests.post(BASE_URL, headers=headers, files=files)
  result = response.json()
  video_id = result['id']

  print(f"Video ID: {video_id}")
  print(f"Status: {result['status']}")
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');
  const FormData = require('form-data');

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

  async function submitRequest() {
      const formData = new FormData();
      formData.append('prompt', 'A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky');
      formData.append('model', 'sora-2');
      formData.append('size', '1280x720');
      formData.append('seconds', '10');

      const response = await axios.post(BASE_URL, formData, {
          headers: {
              ...formData.getHeaders(),
              'Authorization': API_KEY
          }
      });

      const videoId = response.data.id;
      console.log(`Video ID: ${videoId}`);
      console.log(`Status: ${response.data.status}`);
      return videoId;
  }

  submitRequest();
  ```
</CodeGroup>

### Image-to-Video Examples

Upload a reference image to generate video based on the image.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.apiyi.com/v1/videos" \
    -H "Authorization: YOUR_API_KEY" \
    -H "Accept: application/json" \
    -F "prompt=Animate the animals in the reference image, making them chase around the field" \
    -F "model=sora-2" \
    -F "size=1280x720" \
    -F "seconds=10" \
    -F "input_reference=@/path/to/image.png"
  ```

  ```python Python theme={null}
  import requests

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

  # Submit image-to-video request
  with open('/path/to/image.png', 'rb') as f:
      files = {
          'prompt': (None, 'Animate the animals in the reference image, making them chase around the field'),
          'model': (None, 'sora-2'),
          'size': (None, '1280x720'),
          'seconds': (None, '10'),
          'input_reference': ('image.png', f, 'image/png')
      }

      headers = {
          'Accept': 'application/json',
          'Authorization': API_KEY
      }

      response = requests.post(BASE_URL, headers=headers, files=files)
      result = response.json()
      video_id = result['id']

      print(f"Video ID: {video_id}")
  ```
</CodeGroup>

### Response Format

```json theme={null}
{
  "id": "video_abc123def456",
  "status": "submitted",
  "progress": 0,
  "prompt": "A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky",
  "model": "sora-2",
  "size": "1280x720",
  "seconds": "10",
  "created_at": 1704067200,
  "url": null,
  "completed_at": null
}
```

## Step 2: Poll Video Generation Status

After submitting the request, regularly poll to check video generation status.

### Request Method

```bash theme={null}
GET /v1/videos/{video_id}
```

### Query Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.apiyi.com/v1/videos/video_abc123def456" \
    -H "Authorization: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import requests
  import time

  BASE_URL = "https://api.apiyi.com/v1/videos"
  API_KEY = "YOUR_API_KEY"
  POLL_INTERVAL = 30  # Query every 30 seconds
  MAX_WAIT_TIME = 600  # Maximum wait 10 minutes

  def poll_status(video_id):
      headers = {'Authorization': API_KEY}
      status_url = f"{BASE_URL}/{video_id}"
      start_time = time.time()

      while True:
          elapsed_time = time.time() - start_time

          # Check timeout
          if elapsed_time > MAX_WAIT_TIME:
              print(f"Timeout: waited {MAX_WAIT_TIME} seconds")
              return False

          # Query status
          response = requests.get(status_url, headers=headers)
          result = response.json()
          status = result.get('status')
          progress = result.get('progress', 0)

          print(f"Status: {status}, Progress: {progress}%")

          if status == 'completed':
              print(f"Video generation completed! URL: {result.get('url')}")
              return True
          elif status == 'failed':
              print(f"Video generation failed")
              return False
          elif status in ['submitted', 'in_progress']:
              print(f"Generating, waiting {POLL_INTERVAL} seconds...")
              time.sleep(POLL_INTERVAL)
          else:
              print(f"Unknown status: {status}")
              time.sleep(POLL_INTERVAL)

  # Usage example
  poll_status("video_abc123def456")
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');

  const BASE_URL = 'https://api.apiyi.com/v1/videos';
  const API_KEY = 'YOUR_API_KEY';
  const POLL_INTERVAL = 30000; // 30 seconds
  const MAX_WAIT_TIME = 600000; // 10 minutes

  async function pollStatus(videoId) {
      const startTime = Date.now();

      while (true) {
          const elapsedTime = Date.now() - startTime;

          // Check timeout
          if (elapsedTime > MAX_WAIT_TIME) {
              console.log('Timeout: waited 10 minutes');
              return false;
          }

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

          const { status, progress, url } = response.data;
          console.log(`Status: ${status}, Progress: ${progress}%`);

          if (status === 'completed') {
              console.log(`Video generation completed! URL: ${url}`);
              return true;
          } else if (status === 'failed') {
              console.log('Video generation failed');
              return false;
          }

          // Wait and continue
          await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL));
      }
  }

  // Usage example
  pollStatus('video_abc123def456');
  ```
</CodeGroup>

### Status Descriptions

| Status        | Description                               | Next Action                                 |
| ------------- | ----------------------------------------- | ------------------------------------------- |
| `submitted`   | Request submitted, waiting for processing | Continue polling                            |
| `in_progress` | Video generation in progress              | Continue polling, check progress percentage |
| `completed`   | Video generation completed                | Can download video                          |
| `failed`      | Video generation failed                   | Check error message, resubmit               |

### In-Progress Response Example

```json theme={null}
{
  "id": "video_abc123def456",
  "status": "in_progress",
  "progress": 45,
  "prompt": "A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky",
  "model": "sora-2",
  "size": "1280x720",
  "seconds": "10",
  "created_at": 1704067200,
  "url": null,
  "completed_at": null
}
```

### Completed Response Example

```json theme={null}
{
  "id": "video_abc123def456",
  "status": "completed",
  "progress": 100,
  "prompt": "A cute golden retriever chasing a frisbee on a park lawn, sunny day, background with green trees and blue sky",
  "model": "sora-2",
  "size": "1280x720",
  "seconds": "10",
  "created_at": 1704067200,
  "url": "https://api.apiyi.com/v1/videos/video_abc123def456/content",
  "completed_at": 1704067500
}
```

## Step 3: Download Generated Video

After video generation is complete (`status` is `completed`), you can download the video file.

### Request Method

```bash theme={null}
GET /v1/videos/{video_id}/content
```

### Download Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.apiyi.com/v1/videos/video_abc123def456/content" \
    -H "Authorization: YOUR_API_KEY" \
    -o video.mp4
  ```

  ```python Python theme={null}
  import requests

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

  def download_video(video_id, output_path='video.mp4'):
      headers = {'Authorization': API_KEY}
      content_url = f"{BASE_URL}/{video_id}/content"

      print(f"Starting video download...")
      response = requests.get(content_url, headers=headers, stream=True)

      if response.status_code == 200:
          # Get file size
          total_size = int(response.headers.get('content-length', 0))

          with open(output_path, 'wb') as f:
              if total_size == 0:
                  f.write(response.content)
              else:
                  downloaded = 0
                  for chunk in response.iter_content(chunk_size=8192):
                      if chunk:
                          f.write(chunk)
                          downloaded += len(chunk)
                          percent = (downloaded / total_size) * 100
                          print(f"\rDownload progress: {percent:.1f}%", end='')

          print(f"\nVideo downloaded successfully! Saved to: {output_path}")
          print(f"File size: {total_size} bytes")
          return True
      else:
          print(f"Download failed: {response.status_code}")
          print(f"Response: {response.text}")
          return False

  # Usage example
  download_video("video_abc123def456", "my_video.mp4")
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');
  const fs = require('fs');

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

  async function downloadVideo(videoId, outputPath = 'video.mp4') {
      const contentUrl = `${BASE_URL}/${videoId}/content`;

      console.log('Starting video download...');

      const response = await axios.get(contentUrl, {
          headers: { 'Authorization': API_KEY },
          responseType: 'stream'
      });

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

      return new Promise((resolve, reject) => {
          writer.on('finish', () => {
              console.log(`Video downloaded successfully! Saved to: ${outputPath}`);
              resolve();
          });
          writer.on('error', reject);
      });
  }

  // Usage example
  downloadVideo('video_abc123def456', 'my_video.mp4');
  ```
</CodeGroup>

<Warning>
  Video files may expire after a certain period. It's recommended to download immediately after generation and save locally.
</Warning>

## Best Practices

### Prompt Writing Tips

<Tip>
  A good prompt should include: scene description, subject action, camera style, artistic style.
</Tip>

**Good Example**:

```
A cute golden retriever chasing a red frisbee on green grass, sunny day,
background with blue sky, white clouds and green trees, smooth motion,
close-up camera following the dog's action, cinematic quality, warm tones
```

**Poor Example**:

```
Dog chasing frisbee
```

### Reference Image Recommendations

* **Resolution**: Recommended 1280x720 or higher
* **Format**: PNG or JPG
* **File Size**: \< 10MB
* **Content**: Clear, well-defined subject, good lighting
* **Relevance**: Image content should relate to prompt description

### Polling Strategy Recommendations

<CardGroup cols={2}>
  <Card title="Recommended Settings" icon="check">
    * Polling interval: 30 seconds
    * Maximum wait: 10 minutes (600 seconds)
    * Typical duration: 3-5 minutes
  </Card>

  <Card title="Avoid Settings" icon="x">
    * Polling interval: \< 30 seconds (may trigger rate limiting)
    * Maximum wait: \< 5 minutes (may give up too early)
  </Card>
</CardGroup>

### Error Retry Strategy

```python theme={null}
import time

def retry_with_backoff(func, max_retries=3):
    """Exponential backoff retry strategy"""
    for i in range(max_retries):
        try:
            return func()
        except Exception as e:
            if i == max_retries - 1:
                raise
            wait_time = 2 ** i  # 1s, 2s, 4s
            print(f"Retry {i+1}/{max_retries}, waiting {wait_time} seconds...")
            time.sleep(wait_time)
```

## Quotas and Limits

| Limit            | Value              | Description                               |
| ---------------- | ------------------ | ----------------------------------------- |
| Request Rate     | 10 requests/minute | Exceeding returns 429 error               |
| Concurrent Tasks | 5 tasks            | Number of videos processed simultaneously |
| Video Duration   | 10 or 15 seconds   | Other durations not supported             |
| Image Size       | \< 10MB            | Recommended \< 5MB                        |
| Prompt Length    | \< 1000 characters | Recommended 100-300 characters            |

## Error Handling

### Common Error Codes

| Status Code | Description                | Solution                                        |
| ----------- | -------------------------- | ----------------------------------------------- |
| 200         | Success                    | -                                               |
| 400         | Invalid request parameters | Check if all required parameters are complete   |
| 401         | Authentication failed      | Check if API Key is correct                     |
| 403         | Permission denied          | Check if API Key is valid or balance sufficient |
| 404         | Resource not found         | Check if video\_id is correct                   |
| 429         | Too many requests          | Increase polling interval                       |
| 500         | Server error               | Retry later                                     |

## FAQ

<AccordionGroup>
  <Accordion title="How long does video generation take?">
    Typically 3-5 minutes, depending on server load and video complexity. Recommended polling interval: 30 seconds, maximum wait time: 10 minutes.
  </Accordion>

  <Accordion title="What's the difference between Async API and Sync API?">
    * **Async API**: 3-step workflow (submit→poll→download), suitable for batch processing and background tasks, requires managing polling logic
    * **Sync API**: Streaming output, real-time progress, suitable for scenarios needing immediate feedback

    See: [Synchronous Streaming API Documentation](/en/api-capabilities/sora-2-video)
  </Accordion>

  <Accordion title="Can I submit multiple video generation tasks simultaneously?">
    Yes, up to 5 concurrent tasks are supported. You can submit multiple requests simultaneously and poll their status separately. Be careful not to exceed the request rate limit (10 requests/minute).
  </Accordion>

  <Accordion title="How long are video files stored?">
    It's recommended to download videos immediately after generation to avoid file expiration. Contact technical support for specific storage duration.
  </Accordion>

  <Accordion title="How to handle generation failures?">
    Check the error message in the response. Common causes:

    * Content policy violation (modify prompt or change image)
    * Insufficient quota (recharge or upgrade plan)
    * Invalid parameters (check parameter format and values)
    * Server overload (retry later)
  </Accordion>

  <Accordion title="How to control landscape vs portrait orientation?">
    Control via the `size` parameter:

    * `1280x720`: Landscape
    * `720x1280`: Portrait
  </Accordion>
</AccordionGroup>

## Related Resources

<CardGroup cols={2}>
  <Card title="Synchronous Streaming API" icon="bolt" href="/en/api-capabilities/sora-2-video">
    Real-time progress feedback for interactive applications
  </Card>

  <Card title="API Basics Manual" icon="code" href="/en/api-manual">
    Learn about API authentication, request formats, etc.
  </Card>

  <Card title="FAQ" icon="circle-question" href="/en/faq/model-selection-guide">
    View more frequently asked questions
  </Card>
</CardGroup>
