Skip to main content

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

ParameterTypeRequiredDefaultDescription
promptstringYes-Description of the video to generate
modelstringNorunway-gen3Video generation model
duration_secondsnumberNo4Video duration (model-dependent max)
resolutionstringNo1080pOutput resolution (720p or 1080p)
aspect_ratiostringNo16:9Video aspect ratio

Supported Models

ModelProviderMax DurationResolutionPrice
veo-3Google60s1080p$0.35/second
runway-gen3Runway16s1080p$0.10/second
luma-dream-machineLuma AI10s1080p$0.06/second
pikaPika Labs4s1080p$0.067/second

Aspect Ratios

RatioDescriptionBest For
16:9WidescreenYouTube, presentations
9:16VerticalTikTok, Instagram Reels
1:1SquareInstagram, profile videos
4:3StandardClassic 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

ParameterTypeDescription
idstringThe 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

StatusDescription
pendingJob queued, waiting to start
processingVideo is being generated
completeVideo ready for download
failedGeneration 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

TierConcurrent JobsJobs/Day
Free15
Pro5100
EnterpriseCustomCustom