curl --request POST \
--url https://api.apiyi.com/v1/videos \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "sora-2",
"prompt": "A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion"
}
'{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}Text-to-Video API Reference
Sora 2 text-to-video API reference and live playground — JSON request body, async three-step flow, flexible 4 / 8 / 12 second durations.
curl --request POST \
--url https://api.apiyi.com/v1/videos \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "sora-2",
"prompt": "A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion"
}
'{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}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.
Bearer sk-xxx), enter a prompt, choose model / size / seconds, and send.input_reference, request body is application/json. To animate from a reference image (image-to-video), use the Image-to-Video endpoint (same path + multipart upload).- Step 1 (this page):
POST /v1/videos→ returnsvideo_id+status: "queued" - Step 2: Poll
GET /v1/videos/{video_id}untilstatus: "completed" - Step 3: Download from
GET /v1/videos/{video_id}/content(returns the MP4 file)
Code Samples
Python (OpenAI SDK Drop-In)
from openai import OpenAI
import time
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.apiyi.com/v1"
)
# Step 1: Submit the task
video = client.videos.create(
model="sora-2",
prompt="A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion",
seconds="8",
size="1280x720"
)
print(f"Video ID: {video.id}, status: {video.status}")
# Step 2: Poll status
while True:
video = client.videos.retrieve(video.id)
print(f"Status: {video.status}, progress: {getattr(video, 'progress', 0)}%")
if video.status == "completed":
break
if video.status == "failed":
raise RuntimeError(f"Generation failed: {video}")
time.sleep(15)
# Step 3: Download the video
content = client.videos.download_content(video.id)
content.write_to_file("output.mp4")
print("Saved: output.mp4")
Python (Raw requests)
import requests
import time
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.apiyi.com/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Step 1: Submit (JSON body)
resp = requests.post(
f"{BASE_URL}/videos",
headers={**HEADERS, "Content-Type": "application/json"},
json={
"model": "sora-2",
"prompt": "A serene Japanese garden with cherry blossoms, koi pond, traditional bridge, golden hour, ultra detailed",
"seconds": "8",
"size": "1280x720"
},
timeout=30 # The POST is just enqueueing; 30 seconds is enough
).json()
video_id = resp["id"]
print(f"Video ID: {video_id}, status: {resp['status']}")
# Step 2: Poll (max wait 15 minutes)
deadline = time.time() + 900
while time.time() < deadline:
status_resp = requests.get(f"{BASE_URL}/videos/{video_id}", headers=HEADERS).json()
print(f"Status: {status_resp['status']}, progress: {status_resp.get('progress', 0)}%")
if status_resp["status"] == "completed":
break
if status_resp["status"] == "failed":
raise RuntimeError(f"Generation failed: {status_resp}")
time.sleep(15)
# Step 3: Download
with requests.get(f"{BASE_URL}/videos/{video_id}/content", headers=HEADERS, stream=True) as r:
r.raise_for_status()
with open("output.mp4", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
print("Saved: output.mp4")
cURL
{/* Step 1: Submit the task */}
curl -X POST "https://api.apiyi.com/v1/videos" \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "sora-2",
"prompt": "A futuristic cityscape at night with neon lights and flying vehicles, cyberpunk style, cinematic",
"seconds": "8",
"size": "1280x720"
}'
{/* Step 2: Poll status (replace video_id) */}
curl -X GET "https://api.apiyi.com/v1/videos/video_abc123" \
-H "Authorization: Bearer sk-your-api-key"
{/* Step 3: Download the video file */}
curl -X GET "https://api.apiyi.com/v1/videos/video_abc123/content" \
-H "Authorization: Bearer sk-your-api-key" \
-o output.mp4
Node.js (fetch)
import fs from 'node:fs';
const API_KEY = 'sk-your-api-key';
const BASE_URL = 'https://api.apiyi.com/v1';
// Step 1: Submit
const submitResp = await fetch(`${BASE_URL}/videos`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`
},
body: JSON.stringify({
model: 'sora-2',
prompt: 'Aerial drone shot over snowy mountain range at sunrise, cinematic, ultra wide',
seconds: '8',
size: '1280x720'
})
});
const { id: videoId } = await submitResp.json();
console.log(`Video ID: ${videoId}`);
// Step 2: Poll
let status = 'queued';
while (status !== 'completed' && status !== 'failed') {
await new Promise(r => setTimeout(r, 15000));
const statusResp = await fetch(`${BASE_URL}/videos/${videoId}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const data = await statusResp.json();
status = data.status;
console.log(`Status: ${status}, progress: ${data.progress ?? 0}%`);
}
if (status === 'failed') throw new Error('Generation failed');
// Step 3: Download
const contentResp = await fetch(`${BASE_URL}/videos/${videoId}/content`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const buffer = Buffer.from(await contentResp.arrayBuffer());
fs.writeFileSync('output.mp4', buffer);
console.log('Saved: output.mp4');
Browser JavaScript
{/* Demo only; route through your backend in production to avoid leaking the API key. Browsers also aren't ideal for downloading large video files. */}
const submitResp = await fetch('https://api.apiyi.com/v1/videos', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-your-api-key'
},
body: JSON.stringify({
model: 'sora-2',
prompt: 'Watercolor northern lights over snowy mountains, gentle motion',
seconds: '4',
size: '720x1280'
})
});
const { id } = await submitResp.json();
console.log('Video ID:', id);
{/* After polling completes, hand the video URL to a backend proxy for download and serve it back to the client. */}
Parameters Quick Reference
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | Yes | — | sora-2 (720p only) or sora-2-pro (720p / 1024p / 1080p tiers) |
prompt | string | Yes | — | Video description; describe scene, camera motion, style, lighting in detail |
seconds | string | No | "4" | Duration as string enum: "4" / "8" / "12" (not a number) |
size | string | No | 720x1280 | Output resolution; must match the model’s supported tiers (see Tech Specs) |
input_reference upload), see the Image-to-Video endpoint.Response Format
Step 1 — Immediate Submit Response
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}
Step 2 — Polling While Running
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "in_progress",
"progress": 45,
"created_at": 1712697600,
"size": "1280x720",
"seconds": "8"
}
Step 2 — Polling After Completion
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8"
}
- No direct
video_urlfield — the video file must be downloaded fromGET /v1/videos/{id}/content(returns avideo/mp4binary stream). Don’t expect a CDN URL in the JSON response. progressis not strictly linear — it can jump (e.g. 0 → 45 → 80 → 100)- On
status: "failed", anerrorfield is not always present — most failures are content-policy or capacity issues, just retry or revise the prompt - Video content is retained on OpenAI for 1 day only —
/contentreturns 404 after expiration
seconds rate when the task completes (see pricing table). The POST submission, status polling, and content download themselves are not billed, and failed tasks are not billed.Authorizations
API Key from the APIYI console (must use Sora2官转 group + usage-based billing)
Body
Model ID. sora-2 supports 720p only; sora-2-pro supports 720p / 1024p / 1080p tiers
sora-2, sora-2-pro Video generation prompt; describe scene, camera motion, style, lighting, and character actions in detail
"A serene Japanese garden with cherry blossoms, koi pond, traditional bridge, golden hour, ultra detailed"
Video duration as a string enum (not a number):
"4"— 4 seconds (default), ideal for short demos, single shots, fast prompt iteration"8"— 8 seconds, standard short-form video, most common"12"— 12 seconds, long shots and continuous action
Passing "10" / "15" or the integer 4 returns 400
4, 8, 12 Output resolution. sora-2 and sora-2-pro support different tiers:
sora-2(720p only):720x1280(portrait, default) /1280x720(landscape)sora-2-proadditionally supports:1024x1792/1792x1024(1024p, $0.50/sec)1080x1920/1920x1080(1080p, $0.70/sec)
Passing 1024p / 1080p sizes to sora-2 returns 400
720x1280, 1280x720, 1024x1792, 1792x1024, 1080x1920, 1920x1080 Response
Task submitted, returns video_id with queued status
Task ID for subsequent polling and download
"video_abc123def456"
Object type, fixed video
"video"
Model ID used for this task
"sora-2"
Task status:
queued— submitted, waiting in queuein_progress— generatingcompleted— done, ready to download (/v1/videos/{id}/content)failed— failed (not billed), safe to retry
queued, in_progress, completed, failed "queued"
Generation progress percentage (0–100), not strictly linear
0
Task creation Unix timestamp (seconds)
1712697600
Task completion Unix timestamp (seconds), present only on completed status
1712697900
Actual output resolution (matches the requested size)
"1280x720"
Actual duration generated (matches the requested seconds)
"8"
Quality tier (standard for sora-2, high for sora-2-pro)
"standard"
Was this page helpful?