API Reference
Code Examples
Implementation examples in various programming languages
Overview
This page provides complete code examples for integrating with the Sora 2 Video API in various programming languages.
JavaScript / Node.js
Basic Text to Video
const API_KEY = process.env.SORA_API_KEY;
const BASE_URL = 'https://soravideo.art/api/v1';
async function generateVideo(prompt) {
// Start generation
const response = await fetch(`${BASE_URL}/sora2/text-to-video`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt,
aspectRatio: '16:9'
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(result.error || result.msg);
}
return result.data.task_id;
}
async function waitForVideo(taskId) {
while (true) {
const response = await fetch(`${BASE_URL}/tasks/${taskId}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const result = await response.json();
const task = result.data;
console.log(`Status: ${task.status} (${task.progress || 0}%)`);
if (task.status === 'completed') {
return task.video_url;
}
if (task.status === 'failed') {
throw new Error('Video generation failed');
}
await new Promise(r => setTimeout(r, 3000));
}
}
// Usage
async function main() {
const taskId = await generateVideo('A cat playing with a ball of yarn');
console.log('Task started:', taskId);
const videoUrl = await waitForVideo(taskId);
console.log('Video ready:', videoUrl);
}
main().catch(console.error);TypeScript with Full Types
interface ApiResponse<T> {
code: number;
msg: string;
data?: T;
}
interface GenerationParams {
prompt: string;
negativePrompt?: string;
aspectRatio?: '16:9' | '9:16' | '1:1';
duration?: 5 | 10 | 15;
quality?: 'standard' | 'high';
}
interface TaskResult {
task_id: string;
status: 'pending' | 'processing' | 'completed' | 'failed';
progress?: number;
video_url?: string;
thumbnail_url?: string;
created_at: string;
completed_at?: string;
}
class SoraClient {
private apiKey: string;
private baseUrl: string;
constructor(apiKey: string, baseUrl = 'https://soravideo.art/api/v1') {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
private async request<T>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...options.headers
}
});
const result: ApiResponse<T> = await response.json();
if (result.code !== 200) {
throw new Error(result.msg);
}
return result.data!;
}
async textToVideo(params: GenerationParams): Promise<string> {
const data = await this.request<{ task_id: string }>(
'/sora2/text-to-video',
{
method: 'POST',
body: JSON.stringify(params)
}
);
return data.task_id;
}
async textToVideoPro(params: GenerationParams): Promise<string> {
const data = await this.request<{ task_id: string }>(
'/sora2-pro/text-to-video',
{
method: 'POST',
body: JSON.stringify(params)
}
);
return data.task_id;
}
async getTask(taskId: string): Promise<TaskResult> {
return this.request<TaskResult>(`/tasks/${taskId}`);
}
async waitForCompletion(
taskId: string,
onProgress?: (progress: number) => void
): Promise<TaskResult> {
while (true) {
const task = await this.getTask(taskId);
if (onProgress && task.progress) {
onProgress(task.progress);
}
if (task.status === 'completed' || task.status === 'failed') {
return task;
}
await new Promise(r => setTimeout(r, 3000));
}
}
}
// Usage
const client = new SoraClient(process.env.SORA_API_KEY!);
async function generateVideo() {
const taskId = await client.textToVideoPro({
prompt: 'Cinematic sunset over mountains',
duration: 10,
quality: 'high'
});
const result = await client.waitForCompletion(taskId, (progress) => {
console.log(`Progress: ${progress}%`);
});
console.log('Video URL:', result.video_url);
}Python
Basic Example
import os
import time
import requests
from typing import Optional, Dict, Any
API_KEY = os.environ.get('SORA_API_KEY')
BASE_URL = 'https://soravideo.art/api/v1'
def generate_video(prompt: str, aspect_ratio: str = '16:9') -> str:
"""Generate a video from text prompt"""
response = requests.post(
f'{BASE_URL}/sora2/text-to-video',
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
},
json={
'prompt': prompt,
'aspectRatio': aspect_ratio
}
)
result = response.json()
if result['code'] != 200:
raise Exception(result.get('error') or result.get('msg'))
return result['data']['task_id']
def get_task(task_id: str) -> Dict[str, Any]:
"""Get task status"""
response = requests.get(
f'{BASE_URL}/tasks/{task_id}',
headers={'Authorization': f'Bearer {API_KEY}'}
)
result = response.json()
if result['code'] != 200:
raise Exception(result.get('error') or result.get('msg'))
return result['data']
def wait_for_completion(task_id: str, poll_interval: int = 3) -> str:
"""Wait for task to complete and return video URL"""
while True:
task = get_task(task_id)
status = task['status']
progress = task.get('progress', 0)
print(f'Status: {status} ({progress}%)')
if status == 'completed':
return task['video_url']
if status == 'failed':
raise Exception('Video generation failed')
time.sleep(poll_interval)
if __name__ == '__main__':
task_id = generate_video('A golden retriever running through a field')
print(f'Task started: {task_id}')
video_url = wait_for_completion(task_id)
print(f'Video ready: {video_url}')Async Python with aiohttp
import asyncio
import aiohttp
import os
API_KEY = os.environ.get('SORA_API_KEY')
BASE_URL = 'https://soravideo.art/api/v1'
class AsyncSoraClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
async def text_to_video(
self,
session: aiohttp.ClientSession,
prompt: str,
**kwargs
) -> str:
async with session.post(
f'{BASE_URL}/sora2/text-to-video',
headers=self.headers,
json={'prompt': prompt, **kwargs}
) as response:
result = await response.json()
if result['code'] != 200:
raise Exception(result['msg'])
return result['data']['task_id']
async def get_task(
self,
session: aiohttp.ClientSession,
task_id: str
) -> dict:
async with session.get(
f'{BASE_URL}/tasks/{task_id}',
headers=self.headers
) as response:
result = await response.json()
if result['code'] != 200:
raise Exception(result['msg'])
return result['data']
async def wait_for_completion(
self,
session: aiohttp.ClientSession,
task_id: str
) -> dict:
while True:
task = await self.get_task(session, task_id)
if task['status'] in ('completed', 'failed'):
return task
await asyncio.sleep(3)
async def main():
client = AsyncSoraClient(API_KEY)
async with aiohttp.ClientSession() as session:
# Generate multiple videos concurrently
prompts = [
'A cat sleeping in sunlight',
'Waves crashing on a beach',
'City lights at night'
]
# Start all tasks
task_ids = await asyncio.gather(*[
client.text_to_video(session, prompt)
for prompt in prompts
])
print(f'Started {len(task_ids)} tasks')
# Wait for all to complete
results = await asyncio.gather(*[
client.wait_for_completion(session, task_id)
for task_id in task_ids
])
for result in results:
print(f'Video: {result.get("video_url")}')
if __name__ == '__main__':
asyncio.run(main())cURL
Generate Video
curl -X POST https://soravideo.art/api/v1/sora2/text-to-video \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A beautiful sunrise over mountains",
"aspectRatio": "16:9"
}'Check Task Status
curl https://soravideo.art/api/v1/tasks/task_abc123 \
-H "Authorization: Bearer sk_your_api_key"Upload Image
curl -X POST https://soravideo.art/api/v1/upload \
-H "Authorization: Bearer sk_your_api_key" \
-F "file=@/path/to/image.jpg"Image to Video
curl -X POST https://soravideo.art/api/v1/sora2/image-to-video \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://cdn.example.com/uploads/image123.jpg",
"prompt": "The flower slowly blooms"
}'Get Credit Balance
curl https://soravideo.art/api/v1/credits \
-H "Authorization: Bearer sk_your_api_key"Go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
const baseURL = "https://soravideo.art/api/v1"
type Client struct {
apiKey string
httpClient *http.Client
}
type ApiResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data json.RawMessage `json:"data"`
}
type TaskResult struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
Progress int `json:"progress"`
VideoURL string `json:"video_url"`
ThumbnailURL string `json:"thumbnail_url"`
}
func NewClient(apiKey string) *Client {
return &Client{
apiKey: apiKey,
httpClient: &http.Client{Timeout: 30 * time.Second},
}
}
func (c *Client) TextToVideo(prompt string) (string, error) {
payload := map[string]string{
"prompt": prompt,
"aspectRatio": "16:9",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", baseURL+"/sora2/text-to-video", bytes.NewBuffer(body))
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
var result ApiResponse
json.Unmarshal(data, &result)
if result.Code != 200 {
return "", fmt.Errorf(result.Msg)
}
var taskData struct {
TaskID string `json:"task_id"`
}
json.Unmarshal(result.Data, &taskData)
return taskData.TaskID, nil
}
func (c *Client) GetTask(taskID string) (*TaskResult, error) {
req, _ := http.NewRequest("GET", baseURL+"/tasks/"+taskID, nil)
req.Header.Set("Authorization", "Bearer "+c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
data, _ := io.ReadAll(resp.Body)
var result ApiResponse
json.Unmarshal(data, &result)
if result.Code != 200 {
return nil, fmt.Errorf(result.Msg)
}
var task TaskResult
json.Unmarshal(result.Data, &task)
return &task, nil
}
func (c *Client) WaitForCompletion(taskID string) (*TaskResult, error) {
for {
task, err := c.GetTask(taskID)
if err != nil {
return nil, err
}
fmt.Printf("Status: %s (%d%%)\n", task.Status, task.Progress)
if task.Status == "completed" || task.Status == "failed" {
return task, nil
}
time.Sleep(3 * time.Second)
}
}
func main() {
client := NewClient(os.Getenv("SORA_API_KEY"))
taskID, err := client.TextToVideo("A butterfly landing on a flower")
if err != nil {
panic(err)
}
fmt.Println("Task started:", taskID)
result, err := client.WaitForCompletion(taskID)
if err != nil {
panic(err)
}
fmt.Println("Video URL:", result.VideoURL)
}PHP
<?php
class SoraClient {
private string $apiKey;
private string $baseUrl;
public function __construct(string $apiKey, string $baseUrl = 'https://soravideo.art/api/v1') {
$this->apiKey = $apiKey;
$this->baseUrl = $baseUrl;
}
private function request(string $endpoint, string $method = 'GET', ?array $data = null): array {
$ch = curl_init($this->baseUrl . $endpoint);
$headers = [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json'
];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
if ($data) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
}
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['code'] !== 200) {
throw new Exception($result['msg']);
}
return $result['data'];
}
public function textToVideo(string $prompt, string $aspectRatio = '16:9'): string {
$result = $this->request('/sora2/text-to-video', 'POST', [
'prompt' => $prompt,
'aspectRatio' => $aspectRatio
]);
return $result['task_id'];
}
public function getTask(string $taskId): array {
return $this->request('/tasks/' . $taskId);
}
public function waitForCompletion(string $taskId): array {
while (true) {
$task = $this->getTask($taskId);
echo "Status: {$task['status']} ({$task['progress']}%)\n";
if ($task['status'] === 'completed' || $task['status'] === 'failed') {
return $task;
}
sleep(3);
}
}
}
// Usage
$client = new SoraClient($_ENV['SORA_API_KEY']);
$taskId = $client->textToVideo('A serene lake at dawn');
echo "Task started: $taskId\n";
$result = $client->waitForCompletion($taskId);
echo "Video URL: {$result['video_url']}\n";