
"Sora 2 API Tutorial: How to Generate Videos with OpenAI's Latest Model"
OpenAI's Sora 2 represents a major leap in AI video generation. Building on the original Sora, this updated model produces higher-quality videos with better motion coherence, longer durations, and more precise prompt following. For developers looking to integrate AI video generation into their applications, Sora 2's API opens up powerful possibilities.
This tutorial walks you through everything you need to get started with the Sora 2 API — from setup to production-ready code.
What Is Sora 2?#
Sora 2 is OpenAI's second-generation text-to-video model. It generates realistic videos from text descriptions, supporting various resolutions, aspect ratios, and durations.
Key Capabilities#
| Feature | Sora 2 |
|---|---|
| Max Duration | 60 seconds |
| Resolutions | 480p, 720p, 1080p |
| Aspect Ratios | 16:9, 9:16, 1:1 |
| Frame Rate | 24fps, 30fps |
| Text-to-Video | ✅ |
| Image-to-Video | ✅ |
| Video Extension | ✅ |
| Style Control | ✅ |
| Camera Control | ✅ (basic) |
Sora 2 vs Other Video AI Models#
| Feature | Sora 2 | Veo 3 | Kling 2.0 | Luma Ray 2 |
|---|---|---|---|---|
| Max Duration | 60s | 30s | 10s | 10s |
| Max Resolution | 1080p | 4K | 1080p | 1080p |
| Motion Quality | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Text Adherence | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| API Available | ✅ | ✅ | ✅ | ✅ |
| Price (per video) | $0.10-0.50 | $0.05-0.25 | $0.03-0.15 | $0.03-0.10 |
Getting Started with Sora 2 API#
Option 1: Direct OpenAI API#
You need an OpenAI API key with video generation access enabled. Note that Sora 2 API access may require a usage tier upgrade.
Option 2: Via Crazyrouter (Recommended)#
Crazyrouter provides access to Sora 2 alongside other video models (Veo 3, Kling, Luma) through a unified API — often at lower prices.
# Set your API key
export CRAZYROUTER_API_KEY="your-api-key"
Text-to-Video Generation#
Python Example#
import requests
import time
import os
API_KEY = os.environ["CRAZYROUTER_API_KEY"]
BASE_URL = "https://api.crazyrouter.com/v1"
def generate_video(prompt: str, duration: int = 5, resolution: str = "720p",
aspect_ratio: str = "16:9") -> str:
"""Generate a video from a text prompt using Sora 2."""
# Step 1: Submit generation request
response = requests.post(
f"{BASE_URL}/videos/generations",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"prompt": prompt,
"duration": duration,
"resolution": resolution,
"aspect_ratio": aspect_ratio,
"n": 1
}
)
response.raise_for_status()
task = response.json()
task_id = task["id"]
print(f"Task submitted: {task_id}")
# Step 2: Poll for completion
while True:
status_response = requests.get(
f"{BASE_URL}/videos/generations/{task_id}",
headers={"Authorization": f"Bearer {API_KEY}"}
)
status = status_response.json()
if status["status"] == "completed":
video_url = status["data"][0]["url"]
print(f"Video ready: {video_url}")
return video_url
elif status["status"] == "failed":
raise Exception(f"Generation failed: {status.get('error', 'Unknown error')}")
print(f"Status: {status['status']}... waiting")
time.sleep(10)
# Generate a video
video_url = generate_video(
prompt="A golden retriever running through a field of sunflowers at sunset, "
"cinematic lighting, slow motion, 4K quality",
duration=10,
resolution="1080p"
)
Node.js Example#
const API_KEY = process.env.CRAZYROUTER_API_KEY;
const BASE_URL = 'https://api.crazyrouter.com/v1';
async function generateVideo(prompt, options = {}) {
const { duration = 5, resolution = '720p', aspectRatio = '16:9' } = options;
// Submit generation request
const submitResponse = await fetch(`${BASE_URL}/videos/generations`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'sora-2',
prompt,
duration,
resolution,
aspect_ratio: aspectRatio,
n: 1,
}),
});
const task = await submitResponse.json();
console.log(`Task submitted: ${task.id}`);
// Poll for completion
while (true) {
const statusResponse = await fetch(
`${BASE_URL}/videos/generations/${task.id}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const status = await statusResponse.json();
if (status.status === 'completed') {
console.log(`Video ready: ${status.data[0].url}`);
return status.data[0].url;
}
if (status.status === 'failed') {
throw new Error(`Generation failed: ${status.error || 'Unknown'}`);
}
console.log(`Status: ${status.status}... waiting`);
await new Promise((r) => setTimeout(r, 10000));
}
}
// Generate a video
const url = await generateVideo(
'A futuristic city at night with flying cars and neon lights, cyberpunk style, rain',
{ duration: 10, resolution: '1080p' }
);
cURL Example#
# Submit video generation
curl -X POST https://api.crazyrouter.com/v1/videos/generations \
-H "Authorization: Bearer $CRAZYROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-2",
"prompt": "Ocean waves crashing on a rocky coastline at sunrise, aerial drone shot",
"duration": 5,
"resolution": "720p",
"aspect_ratio": "16:9"
}'
# Check status (replace TASK_ID)
curl https://api.crazyrouter.com/v1/videos/generations/TASK_ID \
-H "Authorization: Bearer $CRAZYROUTER_API_KEY"
Image-to-Video Generation#
Sora 2 can animate a static image into a video:
import base64
def image_to_video(image_path: str, prompt: str, duration: int = 5) -> str:
"""Animate a static image into a video."""
with open(image_path, "rb") as f:
image_b64 = base64.b64encode(f.read()).decode()
response = requests.post(
f"{BASE_URL}/videos/generations",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"prompt": prompt,
"image": f"data:image/png;base64,{image_b64}",
"duration": duration,
"resolution": "720p"
}
)
response.raise_for_status()
task = response.json()
# Poll for completion (same as above)
return poll_for_completion(task["id"])
# Animate a product photo
video_url = image_to_video(
"product_photo.png",
"Camera slowly orbits around the product, studio lighting, white background",
duration=5
)
Prompt Engineering for Sora 2#
Effective Prompt Structure#
[Subject] + [Action] + [Setting] + [Style] + [Camera] + [Lighting]
Good Prompt Examples#
prompts = {
"cinematic": (
"A lone astronaut walking across the surface of Mars, "
"red dust swirling around their boots, Earth visible in the sky, "
"cinematic wide shot, golden hour lighting"
),
"product": (
"A sleek smartphone rotating 360 degrees on a reflective surface, "
"studio lighting, dark background, product showcase style"
),
"nature": (
"Time-lapse of a flower blooming in a garden, "
"macro close-up, soft natural lighting, shallow depth of field"
),
"social_media": (
"A coffee cup being poured with latte art forming, "
"top-down view, warm cafe lighting, Instagram aesthetic, 9:16 vertical"
),
}
Tips for Better Results#
- Be specific about motion: "walking slowly" vs "running" vs "standing still"
- Specify camera movement: "static shot", "slow pan left", "tracking shot"
- Include lighting details: "golden hour", "studio lighting", "neon lights"
- Mention style: "cinematic", "documentary", "anime", "photorealistic"
- Keep it focused: One clear subject and action per generation
Sora 2 Pricing#
Official OpenAI Pricing#
| Resolution | Duration | Price per Video |
|---|---|---|
| 480p | 5s | $0.10 |
| 720p | 5s | $0.20 |
| 720p | 10s | $0.35 |
| 1080p | 5s | $0.30 |
| 1080p | 10s | $0.50 |
| 1080p | 30s | $1.20 |
| 1080p | 60s | $2.00 |
Crazyrouter Pricing#
| Resolution | Duration | Price | Savings |
|---|---|---|---|
| 480p | 5s | $0.07 | 30% |
| 720p | 5s | $0.14 | 30% |
| 720p | 10s | $0.25 | 29% |
| 1080p | 5s | $0.21 | 30% |
| 1080p | 10s | $0.35 | 30% |
Cost Comparison with Other Video Models#
| Model | 720p 5s | 1080p 10s | Best For |
|---|---|---|---|
| Sora 2 | $0.20 | $0.50 | Highest quality, long videos |
| Veo 3 | $0.10 | $0.25 | Good quality, cost-effective |
| Kling 2.0 | $0.05 | $0.15 | Budget-friendly |
| Luma Ray 2 | $0.05 | $0.10 | Fast generation |
All available through Crazyrouter with additional discounts.
Production Best Practices#
Error Handling and Retries#
import time
from typing import Optional
def generate_video_robust(prompt: str, max_retries: int = 3,
**kwargs) -> Optional[str]:
"""Generate video with retry logic and error handling."""
for attempt in range(max_retries):
try:
return generate_video(prompt, **kwargs)
except requests.exceptions.HTTPError as e:
if e.response.status_code == 429:
wait_time = 2 ** attempt * 30 # Exponential backoff
print(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)
elif e.response.status_code >= 500:
print(f"Server error. Retrying in 10s...")
time.sleep(10)
else:
raise
except Exception as e:
print(f"Attempt {attempt + 1} failed: {e}")
if attempt < max_retries - 1:
time.sleep(10)
return None
Webhook-Based Completion (No Polling)#
# If supported, use webhooks instead of polling
response = requests.post(
f"{BASE_URL}/videos/generations",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
},
json={
"model": "sora-2",
"prompt": "A cat playing piano, funny, viral video style",
"duration": 5,
"webhook_url": "https://your-app.com/api/video-callback"
}
)
Frequently Asked Questions#
What is Sora 2?#
Sora 2 is OpenAI's second-generation text-to-video AI model. It generates realistic videos up to 60 seconds long from text descriptions, supporting multiple resolutions and aspect ratios.
How much does Sora 2 API cost?#
Pricing ranges from 2.00 (1080p, 60s) per video. Through Crazyrouter, you can save approximately 30% on all Sora 2 generations.
Is Sora 2 better than Veo 3?#
Sora 2 produces longer videos (up to 60s vs 30s) with excellent motion coherence. Veo 3 offers 4K resolution and is more cost-effective. The best choice depends on your specific needs.
Can I use Sora 2 for commercial projects?#
Yes, videos generated through the API can be used commercially according to OpenAI's usage policies. Always review the latest terms of service.
How long does Sora 2 take to generate a video?#
Generation time varies: 5-second clips take 1-3 minutes, while 60-second videos can take 10-15 minutes. Use webhooks for production workflows to avoid polling.
Can I access Sora 2 without an OpenAI account?#
Yes! Through Crazyrouter, you can access Sora 2 and other video models with a single API key — no separate OpenAI account required.
Summary#
Sora 2 sets a new standard for AI video generation with its combination of quality, duration, and versatility. Whether you're building a content creation platform, marketing tool, or creative application, the API makes it accessible to integrate into any workflow.
For the best experience and pricing, access Sora 2 through Crazyrouter — along with Veo 3, Kling, Luma, and 300+ other AI models through a single API key.
Get started now: Sign up at Crazyrouter and generate your first AI video today.


