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 레퍼런스
Sora 2 텍스트-투-비디오 API 레퍼런스 및 라이브 플레이그라운드 — JSON 요청 본문, 비동기 3단계 플로우, 유연한 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입니다. 참조 이미지에서 동영상으로 애니메이션을 만들려면 이미지-투-비디오 엔드포인트를 사용합니다(동일한 경로 + multipart 업로드).- 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 (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');
브라우저 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 | Yes | — | sora-2 (720p 전용) 또는 sora-2-pro (720p / 1024p / 1080p 티어) |
prompt | string | Yes | — | 동영상 설명; 장면, 카메라 움직임, 스타일, 조명을 자세히 설명합니다 |
seconds | string | No | "4" | 기간은 문자열 enum입니다: "4" / "8" / "12" (숫자가 아닙니다) |
size | string | No | 720x1280 | 출력 해상도; 모델이 지원하는 티어와 일치해야 합니다(기술 사양 참조) |
input_reference 업로드)의 경우 이미지-투-동영상 엔드포인트를 참조하십시오.응답 형식
단계 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바이너리 스트림을 반환합니다). JSON 응답에서 CDN URL이 있을 것이라고 기대하지 마십시오. progress은 엄격하게 선형적이지 않습니다 — 건너뛸 수 있습니다(예: 0 → 45 → 80 → 100)status: "failed"에서는error필드가 항상 존재하지 않습니다 — 대부분의 실패는 콘텐츠 정책 또는 용량 문제이며, 그냥 다시 시도하거나 프롬프트를 수정하십시오- 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"
이 페이지가 도움이 되었나요?