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"
}
'import requests
url = "https://api.apiyi.com/v1/videos"
payload = {
"model": "sora-2",
"prompt": "A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'sora-2',
prompt: 'A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion'
})
};
fetch('https://api.apiyi.com/v1/videos', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.apiyi.com/v1/videos",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'sora-2',
'prompt' => 'A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apiyi.com/v1/videos"
payload := strings.NewReader("{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apiyi.com/v1/videos")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/videos")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}"
response = http.request(request)
puts response.read_body{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}Справочник API генерации видео по тексту
Справочник API Sora 2 для генерации видео по тексту и интерактивная песочница — тело запроса JSON, асинхронный трехэтапный поток, гибкая длительность 4 / 8 / 12 секунд.
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"
}
'import requests
url = "https://api.apiyi.com/v1/videos"
payload = {
"model": "sora-2",
"prompt": "A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'sora-2',
prompt: 'A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion'
})
};
fetch('https://api.apiyi.com/v1/videos', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.apiyi.com/v1/videos",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'sora-2',
'prompt' => 'A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apiyi.com/v1/videos"
payload := strings.NewReader("{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apiyi.com/v1/videos")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/videos")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"sora-2\",\n \"prompt\": \"A golden retriever running on the beach at sunset, cinematic, golden hour, slow motion\"\n}"
response = http.request(request)
puts response.read_body{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}Bearer sk-xxx), введите prompt, выберите model / size / seconds и отправьте.input_reference, тело запроса — application/json. Чтобы анимировать по опорному изображению (image-to-video), используйте эндпоинт Image-to-Video (тот же путь + multipart upload).- Шаг 1 (эта страница):
POST /v1/videos→ возвращаетvideo_id+status: "queued" - Шаг 2: Опросите
GET /v1/videos/{video_id}, пока неstatus: "completed" - Шаг 3: Скачайте из
GET /v1/videos/{video_id}/content(возвращает файл MP4)
Примеры кода
Python (OpenAI SDK для быстрой интеграции)
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 (прямые запросы)
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');
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. */}
Краткая справка по параметрам
| Параметр | Тип | Обязательно | По умолчанию | Описание |
|---|---|---|---|---|
model | string | Да | — | sora-2 (только 720p) или sora-2-pro (уровни 720p / 1024p / 1080p) |
prompt | string | Да | — | Описание видео; подробно опишите сцену, движение камеры, стиль, освещение |
seconds | string | Нет | "4" | Длительность как строковое перечисление: "4" / "8" / "12" (не число) |
size | string | Нет | 720x1280 | Выходное разрешение; должно соответствовать поддерживаемым уровням модели (см. Технические характеристики) |
input_reference) см. эндпоинт Image-to-Video.Формат ответа
Шаг 1 — Немедленный ответ на отправку
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "queued",
"progress": 0,
"created_at": 1712697600,
"size": "1280x720",
"seconds": "8",
"quality": "standard"
}
Шаг 2 — Опрос во время выполнения
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "in_progress",
"progress": 45,
"created_at": 1712697600,
"size": "1280x720",
"seconds": "8"
}
Шаг 2 — Опрос после завершения
{
"id": "video_abc123def456",
"object": "video",
"model": "sora-2",
"status": "completed",
"progress": 100,
"created_at": 1712697600,
"completed_at": 1712697900,
"size": "1280x720",
"seconds": "8"
}
- Нет прямого поля
video_url— видеофайл необходимо загрузить изGET /v1/videos/{id}/content(возвращает двоичный потокvideo/mp4). Не ожидайте CDN URL в ответе JSON. progressне является строго линейным — он может перескакивать (например, 0 → 45 → 80 → 100)- При
status: "failed"полеerrorне всегда присутствует — большинство сбоев связаны с политикой контента или capacity, просто повторите попытку или измените prompt - Видео содержимое хранится в OpenAI только 1 день — после истечения срока
/contentвозвращает 404
seconds, когда задача завершается (см. таблицу тарифов). Само POST-отправление, опрос статуса и загрузка содержимого не тарифицируются, и неудачные задачи не тарифицируются.Авторизации
API Key from the APIYI console (must use Sora2官转 group + usage-based billing)
Тело
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 Ответ
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"
Была ли эта страница полезной?