Video Generation API
Generate videos from text prompts using cutting-edge AI models including Google’s Veo 3, Runway Gen-3, Luma Dream Machine, and Pika. Video generation is asynchronous - you submit a job and poll for completion.Create Video Generation
Submit a video generation job.Endpoint
POST https://api.withperf.pro/v1/video/generations
Request Body
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
prompt | string | Yes | - | Description of the video to generate |
model | string | No | runway-gen3 | Video generation model |
duration_seconds | number | No | 4 | Video duration (model-dependent max) |
resolution | string | No | 1080p | Output resolution (720p or 1080p) |
aspect_ratio | string | No | 16:9 | Video aspect ratio |
Supported Models
| Model | Provider | Max Duration | Resolution | Price |
|---|---|---|---|---|
veo-3 | 60s | 1080p | $0.35/second | |
runway-gen3 | Runway | 16s | 1080p | $0.10/second |
luma-dream-machine | Luma AI | 10s | 1080p | $0.06/second |
pika | Pika Labs | 4s | 1080p | $0.067/second |
Aspect Ratios
| Ratio | Description | Best For |
|---|---|---|
16:9 | Widescreen | YouTube, presentations |
9:16 | Vertical | TikTok, Instagram Reels |
1:1 | Square | Instagram, profile videos |
4:3 | Standard | Classic video format |
Request Examples
cURL
curl -X POST https://api.withperf.pro/v1/video/generations \
-H "Authorization: Bearer pk_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A serene mountain landscape with flowing water and dramatic clouds, cinematic quality",
"model": "runway-gen3",
"duration_seconds": 8,
"resolution": "1080p",
"aspect_ratio": "16:9"
}'
JavaScript
const response = await fetch('https://api.withperf.pro/v1/video/generations', {
method: 'POST',
headers: {
'Authorization': 'Bearer pk_live_abc123',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: 'A serene mountain landscape with flowing water and dramatic clouds, cinematic quality',
model: 'runway-gen3',
duration_seconds: 8
})
});
const job = await response.json();
console.log('Job ID:', job.id);
// Poll for completion using the job ID
Python
import requests
import time
# Submit job
response = requests.post(
'https://api.withperf.pro/v1/video/generations',
headers={
'Authorization': 'Bearer pk_live_abc123',
'Content-Type': 'application/json'
},
json={
'prompt': 'A serene mountain landscape with flowing water and dramatic clouds',
'model': 'runway-gen3',
'duration_seconds': 8
}
)
job = response.json()
job_id = job['id']
print(f'Job submitted: {job_id}')
Response (202 Accepted)
{
"id": "job_vid_abc123",
"status": "pending",
"model": "runway-gen3",
"prompt": "A serene mountain landscape with flowing water and dramatic clouds, cinematic quality",
"duration_seconds": 8,
"resolution": "1080p",
"aspect_ratio": "16:9",
"estimated_cost_usd": 0.80,
"perf": {
"request_id": "req_vid_abc123",
"model_used": "runway-gen3",
"latency_ms": 234
}
}
Check Video Generation Status
Poll for the status of a video generation job.Endpoint
GET https://api.withperf.pro/v1/video/generations/:id
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The job ID returned from the creation request |
Request Example
curl -X GET https://api.withperf.pro/v1/video/generations/job_vid_abc123 \
-H "Authorization: Bearer pk_live_abc123"
Status Values
| Status | Description |
|---|---|
pending | Job queued, waiting to start |
processing | Video is being generated |
complete | Video ready for download |
failed | Generation failed (check error_message) |
Response (Processing)
{
"id": "job_vid_abc123",
"status": "processing",
"model": "runway-gen3",
"prompt": "A serene mountain landscape...",
"progress_percent": 45,
"estimated_remaining_seconds": 30
}
Response (Complete)
{
"id": "job_vid_abc123",
"status": "complete",
"model": "runway-gen3",
"prompt": "A serene mountain landscape with flowing water and dramatic clouds, cinematic quality",
"video_url": "https://storage.withperf.pro/videos/job_vid_abc123.mp4",
"duration_seconds": 8,
"resolution": "1080p",
"aspect_ratio": "16:9",
"perf": {
"request_id": "req_vid_abc123",
"model_used": "runway-gen3",
"generation_time_ms": 45234,
"cost_usd": 0.80
}
}
Response (Failed)
{
"id": "job_vid_abc123",
"status": "failed",
"model": "runway-gen3",
"prompt": "...",
"error_message": "Content policy violation: prompt contains prohibited content",
"perf": {
"request_id": "req_vid_abc123",
"model_used": "runway-gen3"
}
}
Complete Polling Example
JavaScript
async function generateVideo(prompt, options = {}) {
// Submit job
const submitResponse = await fetch('https://api.withperf.pro/v1/video/generations', {
method: 'POST',
headers: {
'Authorization': 'Bearer pk_live_abc123',
'Content-Type': 'application/json'
},
body: JSON.stringify({ prompt, ...options })
});
const job = await submitResponse.json();
console.log('Job submitted:', job.id);
// Poll for completion
while (true) {
const statusResponse = await fetch(
`https://api.withperf.pro/v1/video/generations/${job.id}`,
{ headers: { 'Authorization': 'Bearer pk_live_abc123' } }
);
const status = await statusResponse.json();
console.log('Status:', status.status);
if (status.status === 'complete') {
return status.video_url;
}
if (status.status === 'failed') {
throw new Error(status.error_message);
}
// Wait 5 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
// Usage
const videoUrl = await generateVideo(
'A cat playing piano in a jazz club, cinematic lighting',
{ model: 'runway-gen3', duration_seconds: 8 }
);
console.log('Video ready:', videoUrl);
Python
import requests
import time
def generate_video(prompt, model='runway-gen3', duration_seconds=4):
headers = {'Authorization': 'Bearer pk_live_abc123'}
# Submit job
response = requests.post(
'https://api.withperf.pro/v1/video/generations',
headers={**headers, 'Content-Type': 'application/json'},
json={
'prompt': prompt,
'model': model,
'duration_seconds': duration_seconds
}
)
job = response.json()
job_id = job['id']
print(f'Job submitted: {job_id}')
# Poll for completion
while True:
status_response = requests.get(
f'https://api.withperf.pro/v1/video/generations/{job_id}',
headers=headers
)
status = status_response.json()
print(f'Status: {status["status"]}')
if status['status'] == 'complete':
return status['video_url']
if status['status'] == 'failed':
raise Exception(status.get('error_message', 'Video generation failed'))
time.sleep(5)
# Usage
video_url = generate_video(
'A cat playing piano in a jazz club, cinematic lighting',
model='runway-gen3',
duration_seconds=8
)
print(f'Video ready: {video_url}')
Prompt Best Practices
Be Descriptive
{
"prompt": "Slow motion shot of coffee being poured into a white ceramic cup, steam rising, warm morning light through window, shallow depth of field"
}
Specify Camera Movement
{
"prompt": "Drone shot flying over a mountain range at sunrise, slowly revealing a valley with a river below, cinematic quality"
}
Include Lighting and Mood
{
"prompt": "A lone astronaut walking on Mars surface, dramatic sunset lighting casting long shadows, dust particles in the air, sci-fi atmosphere"
}
Error Responses
400 Bad Request
{
"error": {
"type": "invalid_request",
"message": "prompt is required"
}
}
400 Duration Exceeded
{
"error": {
"type": "invalid_request",
"message": "duration_seconds exceeds maximum of 16 for runway-gen3 model"
}
}
404 Job Not Found
{
"error": {
"type": "not_found",
"message": "Video generation job not found"
}
}
Rate Limits
| Tier | Concurrent Jobs | Jobs/Day |
|---|---|---|
| Free | 1 | 5 |
| Pro | 5 | 100 |
| Enterprise | Custom | Custom |
Related Endpoints
- Image Generation - Generate still images
- Audio Generation - Text-to-speech
- Chat API - Text generation