Developer Dashboard

Video Generation API

The Video Generation API allows you to create AI-generated videos using OpenAI's Sora models and Google's Veo models through the AvalAI platform. Video generation is asynchronous - you submit a request and poll for completion using the status endpoint.

⚠️ IMPORTANT: Connection Interruptions

Video generation and remix operations are asynchronous - the server begins processing your request immediately upon submission. If your connection is interrupted during or after submission, DO NOT immediately retry with a new generation request, as this may result in duplicate charges.

What to do if your connection is interrupted:

  1. Use the List Videos endpoint to retrieve all your videos:

    curl -X GET https://api.avalai.ir/v1/videos/
    -H "Authorization: Bearer $AVALAI_API_KEY"

  2. Check the status field of your most recent video:

    • If status == "failed": The video did not start generating, and no costs will apply. You can safely submit a new request.
    • If status is anything other than "failed" (e.g., "queued", "processing", "completed"): The generation has started or completed, and costs will be charged. Wait for this video to complete instead of creating a duplicate request.

This practice helps you avoid unnecessary credit usage and duplicate video generations.

Endpoints

Create Video

POST https://api.avalai.ir/v1/videos

Submit a video generation request. Returns a job object with a unique ID to track the generation progress.

Retrieve Video

GET https://api.avalai.ir/v1/videos/{video_id}

Retrieve the status and details of a video generation job.

List Videos

GET https://api.avalai.ir/v1/videos

List all video generation jobs for your account. Supports filtering by safety_identifier and request_id query parameters.

Query Parameters:

ParameterTypeDescription
safety_identifierstringFilter videos by safety identifier
request_idstringFilter videos by request ID

Delete Video

DELETE https://api.avalai.ir/v1/videos/{video_id}

Delete a video generation job and its associated content.

Remix Video

POST https://api.avalai.ir/v1/videos/{video_id}/remix

Create a new video based on an existing video with modified parameters.

Retrieve Video Content

GET https://api.avalai.ir/v1/videos/{video_id}/content

Download the generated video file. This endpoint is only available when the video status is "completed".

OpenAI Videos API Compatibility Notes

OpenAI's current Videos API documentation describes a broader Sora production lifecycle: create asynchronous render jobs, monitor with polling or webhooks, download MP4 output and supporting assets, use image references, create reusable characters, extend completed videos, edit existing videos, and queue large render sets through Batch. In AvalAI, treat the endpoints listed above as the supported contract for this route.

OpenAI Videos capabilityAvalAI guidance
Create and poll render jobsSupported through POST /v1/videos, GET /v1/videos/{video_id}, and GET /v1/videos/{video_id}/content.
Image referenceSupported with multipart input_reference; use JPEG, PNG, or WebP and keep the image close to the target size.
Webhooks for completionUse only when AvalAI explicitly enables video webhook events for your account; otherwise poll with backoff.
Characters, extensions, and editsDo not assume /v1/videos/characters, /v1/videos/extensions, or /v1/videos/edits are available until they appear in this reference. Use the documented remix route when it fits your workflow.
Batch video queuesUse Batch API with videos only after AvalAI confirms support for /v1/videos batch requests; otherwise run an application-managed queue.
Long-term asset hostingDownload completed videos promptly and copy them to your own storage; do not rely on generated content URLs as durable storage.

For implementation patterns and prompt guidance, see Video Generation with Sora.

Create Video Request

Request Body

ParameterTypeRequiredDescription
modelstringYesID of the model to use: "sora-2", "sora-2-pro", "gen4.5", "gen4_turbo", "veo-3.1-generate-001", "veo-3.1-fast-generate-001", "veo-3.1-generate-preview", or "veo-3.1-fast-generate-preview"
promptstringYesA text description of the desired video. Maximum length is 1000 characters.
secondsstringNoDuration of the video in seconds. For Sora models the minimum is 4 seconds, and supported values are "4", "8", and "12". Defaults to "4". Use string format.
sizestringNoThe resolution of the generated video. See supported sizes below. Defaults to "720x1280".
input_referencefileNoImage file to use as reference for video generation (multipart/form-data).
safety_identifierstringNoOptional custom identifier for internal tracking. Use this to associate requests with your own systems (e.g., department IDs, project codes, user IDs). Maximum 256 characters. Can be used to filter videos when listing. See User API for more details.

Supported Video Sizes

Sora 2

SizeAspect RatioDescription
720x12809:16Portrait (default)
1280x72016:9Landscape

Sora 2 Pro

SizeAspect RatioDescription
720x12809:16Portrait (default)
1280x72016:9Landscape
1024x17929:16High-resolution portrait
1792x102416:9High-resolution landscape

Veo 3.1 Generate Preview

SizeAspect RatioDescription
720x12809:16Portrait
1280x72016:9Landscape
1080x19209:16High-resolution portrait
1920x108016:9High-resolution landscape

Veo 3.1 Fast Generate Preview

SizeAspect RatioDescription
720x12809:16Portrait
1280x72016:9Landscape
1080x19209:16High-resolution portrait
1920x108016:9High-resolution landscape

Supported Video Durations

For Sora models, the minimum video duration is 4 seconds. The supported values for the seconds parameter are "4", "8", and "12".

⚠️ Warning: Duration must be a multiple of 4 seconds

Video models generally accept durations that are multiples of 4 seconds (e.g., "4", "8", "12"). This is common across most video generation models, though not guaranteed for every model. Requesting an unsupported duration will return a 400 Bad Request error. Always check the individual model's supported values before submitting a request.

Examples

Basic Video Generation

bash
curl -X POST https://api.avalai.ir/v1/videos \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -d '{
  "model": "sora-2",
  "prompt": "A calico cat playing a piano on stage under dramatic spotlights",
  "size": "1280x720",
  "seconds": "4"
}'
python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# Create video generation job
video = client.videos.create(
    model="sora-2",
    prompt="A calico cat playing a piano on stage under dramatic spotlights",
    size="1280x720",
    seconds="4",  # or "8"
)

print(f"Video ID: {video.id}")
print(f"Status: {video.status}")

# Poll for completion
import time

while video.status not in ["completed", "failed"]:
    time.sleep(5)
    video = client.videos.retrieve(video.id)
    print(f"Status: {video.status}")
javascript
import { OpenAI } from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// Create video generation job
let video = await client.videos.create({
  model: "sora-2",
  prompt: "A calico cat playing a piano on stage under dramatic spotlights",
  size: "1280x720",
  seconds: "4",  // or "8"
});

console.log(`Video ID: ${video.id}`);
console.log(`Status: ${video.status}`);

// Poll for completion
while (!["completed", "failed"].includes(video.status)) {
  await new Promise(resolve => setTimeout(resolve, 10000));
  video = await client.videos.retrieve(video.id);
  console.log(`Status: ${video.status}`);
}

if (video.status === "completed") {
  // Get download URL
  console.log(`Video ready! Use GET /v1/videos/${video.id}/content to download`);
}

Video Generation with Image Reference

Note: Download the sample image for testing: monster_original_720p.jpeg

Generate a video using an image as a reference point:

bash
curl -X POST https://api.avalai.ir/v1/videos \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F prompt="The fridge door opens. A cute, chubby purple monster comes out of it." \
  -F model="sora-2" \
  -F size="1280x720" \
  -F seconds="4" \
  -F input_reference="@monster_original_720p.jpeg;type=image/jpeg"
python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# Create video with image reference
video = client.videos.create(
    prompt="The fridge door opens. A cute, chubby purple monster comes out of it.",
    input_reference=open("monster_original_720p.jpeg", "rb"),
    model="sora-2",
    size="1280x720",
    seconds="4",
)

print(f"Video generation started: {video.id}")
javascript
import { OpenAI } from "openai";
import fs from 'fs';

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// Create video with image reference
const video = await client.videos.create({
  prompt: "The fridge door opens. A cute, chubby purple monster comes out of it.",
  input_reference: fs.createReadStream("monster_original_720p.jpeg"),
  model: "sora-2",
  size: "1280x720",
  seconds: "4"
});

console.log(`Video generation started: ${video.id}`);

Retrieve Video Status

Check the status of a video generation job:

bash
curl https://api.avalai.ir/v1/videos/video_abc123 \
  -H "Authorization: Bearer $AVALAI_API_KEY"
python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# Retrieve video status
video = client.videos.retrieve("video_abc123")

print(f"Status: {video.status}")
javascript
import { OpenAI } from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// Retrieve video status
const video = await client.videos.retrieve("video_abc123");

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

List All Videos

Retrieve all video generation jobs:

bash
curl -X GET https://api.avalai.ir/v1/videos \
  -H "Authorization: Bearer $AVALAI_API_KEY"
python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# List all videos
videos = client.videos.list()

for video in videos.data:
    print(f"{video.id}: {video.status}")
javascript
import { OpenAI } from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// List all videos
const videos = await client.videos.list();

videos.data.forEach(video => {
  console.log(`${video.id}: ${video.status}`);
});

Filter Videos by Safety Identifier

Filter videos using the optional safety_identifier parameter. This is useful for retrieving videos associated with specific departments, projects, or internal tracking IDs:

bash
curl -X GET "https://api.avalai.ir/v1/videos?safety_identifier=dept_123abc" \
  -H "Authorization: Bearer $AVALAI_API_KEY"
python
import requests

response = requests.get(
    "https://api.avalai.ir/v1/videos",
    params={"safety_identifier": "dept_123abc"},
    headers={"Authorization": f"Bearer {api_key}"},
)

videos = response.json()
for video in videos["data"]:
    print(f"{video['id']}: {video['safety_identifier']}")
javascript
const response = await fetch(
  "https://api.avalai.ir/v1/videos?safety_identifier=dept_123abc",
  {
    headers: {
      Authorization: `Bearer ${process.env.AVALAI_API_KEY}`,
    },
  }
);

const videos = await response.json();
videos.data.forEach(video => {
  console.log(`${video.id}: ${video.safety_identifier}`);
});

Filter Videos by Request ID

Retrieve a specific video by its request_id. This is useful when you need to find a video based on the request tracking ID:

bash
curl -X GET "https://api.avalai.ir/v1/videos?request_id=019b4797-14a2-79a0-8635-2cf8dd84820c" \
  -H "Authorization: Bearer $AVALAI_API_KEY"
python
import requests

response = requests.get(
    "https://api.avalai.ir/v1/videos",
    params={"request_id": "019b4797-14a2-79a0-8635-2cf8dd84820c"},
    headers={"Authorization": f"Bearer {api_key}"},
)

videos = response.json()
if videos["data"]:
    video = videos["data"][0]
    print(f"Found video: {video['id']}")
javascript
const response = await fetch(
  "https://api.avalai.ir/v1/videos?request_id=019b4797-14a2-79a0-8635-2cf8dd84820c",
  {
    headers: {
      Authorization: `Bearer ${process.env.AVALAI_API_KEY}`,
    },
  }
);

const videos = await response.json();
if (videos.data.length > 0) {
  console.log(`Found video: ${videos.data[0].id}`);
}

Remix Existing Video

Create a variation of an existing video:

bash
curl -X POST https://api.avalai.ir/v1/videos/video_691bab4a12248190b1e9123d8648ff4d/remix \
  -H "Authorization: Bearer $AVALAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Extend the scene with the cat taking a bow to the cheering audience"
  }'
python
from openai import OpenAI

client = OpenAI(
    api_key="avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# Remix an existing video
remixed_video = client.videos.remix(
    video_id="video_691bab4a12248190b1e9123d8648ff4d",
    prompt="Extend the scene with the cat taking a bow to the cheering audience",
)

print(f"Remixed video ID: {remixed_video.id}")

# Then check status with client.videos.retrieve(remixed_video.id)
# And download with GET /v1/videos/{remixed_video.id}/content when completed
javascript
import { OpenAI } from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// Remix an existing video
const remixedVideo = await client.videos.remix({
  videoId: "video_691bab4a12248190b1e9123d8648ff4d",
  prompt: "Extend the scene with the cat taking a bow to the cheering audience"
});

console.log(`Remixed video ID: ${remixedVideo.id}`);

// Then check status with client.videos.retrieve(remixedVideo.id)
// And download with GET /v1/videos/{remixedVideo.id}/content when completed

Delete Video

Remove a video generation job and its content:

bash
curl -X DELETE https://api.avalai.ir/v1/videos/video_abc123 \
  -H "Authorization: Bearer $AVALAI_API_KEY"
python
from openai import OpenAI

client = OpenAI(
    api_key="your-avalai-api-key",
    base_url="https://api.avalai.ir/v1",
)

# Delete video
result = client.videos.delete("video_abc123")
print(f"Video deleted: {result.deleted}")
javascript
import { OpenAI } from "openai";

const client = new OpenAI({
  apiKey: process.env.AVALAI_API_KEY,
  baseURL: "https://api.avalai.ir/v1",
});

// Delete video
const result = await client.videos.delete("video_abc123");
console.log(`Video deleted: ${result.deleted}`);

Delete Response

json
{
  "id": "video_abc123",
  "object": "video.deleted",
  "deleted": true
}

Response Format

Video Object

json
{
  "id": "vid_abc123",
  "object": "video",
  "request_id": "019b47a0-ece8-75b2-8a4c-40fcf4b49479",
  "status": "completed",
  "model": "sora-2",
  "prompt": "A calico cat playing a piano on stage under dramatic spotlights",
  "size": "1280x720",
  "seconds": 4,
  "created_at": "1763419001",
  "completed_at": "1763419063",
  "safety_identifier": "dept_123abc"
}

Response Parameters

ParameterTypeDescription
idstringUnique identifier for the video generation job
objectstringObject type, always "video"
request_idstringGlobal request ID (UUID v7) for tracking and cost lookup. Same as avalai-request-id header but included in response body for easier video management. See Response Headers for more details.
statusstringCurrent status: "queued", "processing", "completed", or "failed"
modelstringThe model used for video generation
promptstringThe prompt used to generate the video
sizestringThe resolution of the generated video
secondsstringDuration of the video in seconds
progressintegerGeneration progress percentage (0-100)
remixed_from_video_idstringID of the original video if this is a remix, null otherwise
safety_identifierstringCustom identifier provided in the request, if any
created_atintegerUnix timestamp when the job was created
completed_atintegerUnix timestamp when the job completed (null if not completed)
expires_atintegerUnix timestamp when the video will expire (null if not set)
errorobjectError details if status is "failed" (null otherwise)

Video List Response

json
{
  "object": "list",
  "data": [
    {
      "id": "video_6949a20bad18819094b7f19168f56cbb",
      "object": "video",
      "request_id": "019b47a0-ece8-75b2-8a4c-40fcf4b49479",
      "created_at": 1766433289,
      "status": "completed",
      "completed_at": 1766433460,
      "error": null,
      "expires_at": 1766519691,
      "model": "sora-2",
      "progress": 100,
      "prompt": "A calico cat playing a piano on stage",
      "remixed_from_video_id": null,
      "seconds": "4",
      "size": null,
      "safety_identifier": "dept_123abc"
    },
    {
      "id": "video_69499f86a61c8190841c731e8bd0b4c8",
      "object": "video",
      "request_id": "019b4797-14a2-79a0-8635-2cf8dd84820c",
      "created_at": 1766432643,
      "status": "completed",
      "completed_at": 1766432819,
      "error": null,
      "expires_at": 1766519046,
      "model": "sora-2",
      "progress": 100,
      "prompt": "A calico cat playing a piano on stage",
      "remixed_from_video_id": null,
      "seconds": "4",
      "size": null
    }
  ],
  "first_id": "video_6949a20bad18819094b7f19168f56cbb",
  "last_id": "video_69499f86a61c8190841c731e8bd0b4c8",
  "has_more": true
}

Available Models

ModelDescriptionMax DurationResolutionsPrice per Second
sora-2Standard quality video generation with natural motion12 seconds720x1280, 1280x720$0.10
sora-2-proHigh-quality video generation with enhanced detail and motion12 seconds720x1280, 1280x720, 1024x1792, 1792x1024$0.30 (standard)
$0.50 (high-res)

Sora 2

  • Fast video generation with natural motion
  • Supports portrait and landscape orientations
  • Ideal for social media and standard applications
  • 720x1280 and 1280x720 resolutions

Sora 2 Pro

  • Enhanced quality with superior detail and motion
  • Extended resolution support including high-resolution outputs
  • Advanced prompt understanding
  • Better temporal coherence and scene composition
  • 1024x1792 and 1792x1024 high-resolution options

Video Generation Status

Video generation is asynchronous and goes through the following statuses:

StatusDescription
queuedJob has been created and is waiting to start
processingVideo is currently being generated
completedVideo generation finished successfully
failedVideo generation failed (see error field for details)

Best Practices

Effective Prompting

  1. Be Specific and Descriptive

    • Include details about subjects, actions, settings, lighting, and camera movement
    • Example: "A golden retriever puppy running through a sunlit meadow, camera following at ground level with shallow depth of field"
  2. Specify Camera Work

    • Mention desired camera movements: "slow zoom out", "tracking shot", "overhead view"
    • Example: "Aerial drone shot descending over a coastal city at sunset"
  3. Include Temporal Elements

    • Describe the sequence of events or changes
    • Example: "A flower blooming in time-lapse from bud to full bloom"
  4. Set the Mood

    • Use descriptive adjectives for atmosphere and emotion
    • Example: "A cozy cabin interior with warm firelight, peaceful and inviting atmosphere"

Using Image References

  • Provide high-quality reference images for better results
  • Images should be clear and well-composed
  • The reference image sets the scene; the prompt describes the motion and changes
  • Example: Upload a landscape photo with prompt "Camera slowly panning left to reveal a hidden waterfall"

Optimization Tips

  1. Start with Shorter Videos - Test with 4-second videos before generating longer content
  2. Poll Efficiently - Use appropriate intervals (e.g., 10 seconds) when polling for completion
  3. Cache Results - Store successful videos to avoid regeneration
  4. Handle Failures Gracefully - Implement retry logic with exponential backoff
  5. Monitor Costs - Track video generation usage, especially for high-resolution Sora 2 Pro videos

Error Handling

The API may return various error codes:

Status CodeDescription
400Bad Request - Invalid parameters (e.g., unsupported size or duration)
401Unauthorized - Invalid API key
403Forbidden - Insufficient permissions or tier access
404Not Found - Video ID does not exist
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server-side error occurred

Error Response Example

json
{
  "error": {
    "message": "Invalid video size for model sora-2. Supported sizes: 720x1280, 1280x720",
    "type": "invalid_request_error",
    "code": "invalid_size"
  }
}

Content Moderation

All video generation requests are subject to content moderation. Prompts that violate the content policy will be rejected. Videos are also analyzed after generation to ensure compliance.

Rate Limits

Video generation has separate rate limits from other API endpoints due to resource intensity:

  • Sora 2: Up to 10 concurrent video generations
  • Sora 2 Pro: Up to 5 concurrent video generations

For more information, see the Rate Limits guide.