Sora 2 Video Generation API
API for generating videos using OpenAI Sora 2 models with text-to-video and image-to-video modes.
Try it online: https://nanophoto.ai/sora-2
| Method | Path | Description |
|---|
| POST | /api/sora-2/generate | Generate a video |
| POST | /api/sora-2/check-status | Check task status |
Authorization: Bearer YOUR_API_KEY
| Model | Duration | Credits |
|---|
sora2 | 10s | 4 |
sora2 | 15s | 8 |
sora2-pro-standard (720p) | 10s | 60 |
sora2-pro-standard (720p) | 15s | 100 |
sora2-pro-high (1080p) | 10s | 120 |
sora2-pro-high (1080p) | 15s | 240 |
POST /api/sora-2/generate
| Header | Value |
|---|
Content-Type | application/json |
Authorization | Bearer YOUR_API_KEY |
| Parameter | Type | Required | Description |
|---|
prompt | string | Yes | Video generation prompt |
mode | string | Yes | textToVideo or imageToVideo |
modelTier | string | No | sora2 (default), sora2-pro-standard, or sora2-pro-high |
aspectRatio | string | No | portrait (default) or landscape |
videoDuration | string | No | 10 or 15 (seconds) |
imageUrls | string[] | Conditional | Public image URLs for imageToVideo mode |
API calls only accept imageUrls (public URLs) for image-to-video mode. Base64 image upload is not supported via API.
curl -X POST "https://nanophoto.ai/api/sora-2/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-raw '{
"prompt": "A golden retriever running on a beach at sunset, cinematic lighting",
"mode": "textToVideo",
"modelTier": "sora2",
"aspectRatio": "landscape",
"videoDuration": "10"
}'
curl -X POST "https://nanophoto.ai/api/sora-2/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-raw '{
"prompt": "The person in the painting comes alive, moving naturally and reciting poetry",
"mode": "imageToVideo",
"modelTier": "sora2",
"aspectRatio": "landscape",
"videoDuration": "10",
"imageUrls": ["https://static.nanophoto.ai/demo/nano-banana-pro.webp"]
}'
async function generateVideo() {
// Step 1: Submit generation task
const response = await fetch("https://nanophoto.ai/api/sora-2/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_API_KEY",
},
body: JSON.stringify({
prompt: "A golden retriever running on a beach at sunset",
mode: "textToVideo",
modelTier: "sora2",
aspectRatio: "landscape",
videoDuration: "10",
}),
});
const data = await response.json();
if (!data.success) {
console.error("Generation failed:", data.error);
return;
}
// Step 2: Poll for status
const taskId = data.taskId;
while (true) {
await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait 5s
const statusRes = await fetch(
"https://nanophoto.ai/api/sora-2/check-status",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_API_KEY",
},
body: JSON.stringify({ taskId }),
}
);
const status = await statusRes.json();
if (status.status === "completed") {
console.log("Video URL:", status.videoUrl);
return;
}
if (status.status === "failed") {
console.error("Generation failed:", status.error);
return;
}
console.log("Still processing...", status.progress);
}
}
generateVideo();
{
"success": true,
"status": "processing",
"taskId": "task_abc123",
"message": "Video generation in progress"
}
When you receive status: "processing", poll the check-status endpoint every 5-10 seconds.
{
"error": "Insufficient credits",
"errorCode": "INSUFFICIENT_CREDITS",
"requiredCredits": 4
}
POST /api/sora-2/check-status
| Header | Value |
|---|
Content-Type | application/json |
Authorization | Bearer YOUR_API_KEY |
| Parameter | Type | Required | Description |
|---|
taskId | string | Yes | Task ID from generate response |
curl -X POST "https://nanophoto.ai/api/sora-2/check-status" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-raw '{"taskId": "task_abc123"}'
{
"success": true,
"status": "processing",
"progress": "generating",
"message": "Video generation generating",
"taskId": "task_abc123"
}
{
"success": true,
"status": "completed",
"videoUrl": "https://video.nanophoto.ai/sora/...",
"taskId": "task_abc123",
"generationTime": 120,
"creditsUsed": 4
}
{
"success": false,
"status": "failed",
"error": "Video generation failed",
"errorCode": "GENERATION_FAILED",
"taskId": "task_abc123"
}
- Poll
/api/sora-2/check-status every 5-10 seconds
- Typical generation time: 1-3 minutes for
sora2, 3-8 minutes for pro models
- Credits are automatically refunded if generation fails
| errorCode | HTTP Status | Description |
|---|
LOGIN_REQUIRED | 401 | Authentication required |
API_KEY_RATE_LIMIT_EXCEEDED | 429 | Rate limit exceeded (100 req/hour) |
INSUFFICIENT_CREDITS | 402 | Not enough credits |
PROMPT_REQUIRED | 400 | Missing prompt |
IMAGE_REQUIRED | 400 | Image required for imageToVideo mode |
IMAGE_URLS_REQUIRED | 400 | API calls require imageUrls (no base64) |
GENERATION_FAILED | 500 | Video generation failed |
TASK_ID_REQUIRED | 400 | Missing task ID |
TASK_NOT_FOUND | 404 | Task not found or not owned by user |
INTERNAL_ERROR | 500 | Internal server error |