Generate Videos
April 6, 2026
Table of contents
- Model Compatibility Matrix
- Request Headers
- Request Body
- Responses
- Model
- Webhook Callback (
replyUrl) - Examples
- Try It
Generate videos using Luma AI models from text prompts with optional image input. All video generation is asynchronous — this endpoint returns immediately with a job ID. Poll GET /jobs/jobid for completion, or use replyUrl webhook for automatic callbacks.
Video generation typically completes within 30-60 seconds for draft, and ~3 minutes for 1080p on unlimited plans (relaxed mode). Generation times vary by model, resolution, and server load.
Model Compatibility Matrix
Not all parameter combinations are supported. The API validates against this matrix and returns 400 for unsupported combinations.
ray-v3-flash (default) | ray-v3 | ray-v3-reasoning | |
|---|---|---|---|
| Resolutions | draft, 540p, 720p, 1080p | draft, 540p, 720p, 1080p | 720p, 1080p |
| Durations | 5s, 10s | 5s, 10s | 5s, 10s |
| SDR | all resolutions, 5s+10s | all resolutions, 5s+10s | all resolutions, 5s+10s |
| HDR | 540p-1080p, 5s only | 540p-1080p, 5s only | 720p-1080p, 5s only |
| HDR+EXR | 540p-720p, 5s only | 540p-720p, 5s only | 720p only, 5s only |
| imageStart/imageEnd | yes | yes | yes |
| imageCharacter | no | yes (SDR only) | no |
Dynamic range output formats:
sdr— Standard H.264 MP4 (playable in browsers).hdr— HEVC (H.265) Main 10 profile, BT.2020 color, HDR10 (PQ). Not playable in browsers — requires VLC, mpv, or a native HDR-capable player.hdr_exr— Same HDR video + EXR frames download (ZIP) available viaresponse.video_hdr_exr.
https://api.useapi.net/v1/luma/videos
Request Headers
Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data
API tokenis required, see Setup useapi.net for details.
Request Body
{
"prompt": "A serene mountain landscape at sunset with camera slowly panning right",
"model": "ray-v3-flash",
"resolution": "720p",
"aspect_ratio": "16:9",
"duration": "5s"
}
promptis required. Text description of the video to generate. Maximum 2000 characters.emailis optional. Specific account to use. Auto-selected (random with available capacity) if omitted. WhenimageStart,imageEnd, orimageCharacteris provided, the account is automatically inferred from the asset reference —emailis not required. If provided, it must match the asset’s account.modelis optional, the AI model to use (default:ray-v3-flash). Supported values:ray-v3-flash,ray-v3,ray-v3-reasoning.resolutionis optional, video resolution (default:draft). Supported values:draft,540p,720p,1080p. See matrix above for per-model restrictions.aspect_ratiois optional, video aspect ratio (default:16:9). Supported values:9:16,3:4,1:1,4:3,16:9,21:9.durationis optional, video duration (default:5s). Supported values:5s,10s. HDR/HDR+EXR limited to5s.dynamic_rangeis optional, video dynamic range (default:sdr). Supported values:sdr,hdr,hdr_exr. See matrix above for resolution restrictions and output format details.imageStartis optional.assetReffrom POST /assets/email— start keyframe for image-to-video.imageEndis optional.assetRef— end keyframe. Can be used alone or withimageStart.imageCharacteris optional.assetRef— character reference image. Only supported withray-v3model andsdrdynamic range. Cannot be combined withimageStartorimageEnd.replyUrlis optional, webhook URL for job status callbacks. Receives POST requests with the job record on submission and on completion/failure.replyRefis optional, custom reference string passed back in webhook callbacks.
Responses
-
Job created successfully. Video is generating in the background.
{ "jobid": "j0326140530123456789v-u12345-email:[email protected]:a1b2c3d4-e5f6-7890-abcd-ef1234567890-bot:luma", "type": "video", "status": "created", "created": "2026-03-26T14:05:30.123Z", "request": { "prompt": "A serene mountain landscape at sunset with camera slowly panning right", "model": "ray-v3-flash", "resolution": "720p", "aspect_ratio": "16:9", "duration": "5s", "dynamic_range": "sdr" } }Poll GET /jobs/
jobidfor completion status, or usereplyUrlfor webhook callbacks. -
Validation error.
{ "error": "Parameter model (invalid-model) valid values: ray-v3-flash, ray-v3, ray-v3-reasoning" } -
Invalid API token.
{ "error": "Unauthorized" } -
Subscription expired or insufficient credits.
{ "error": "Account has no subscription or subscription expired" } -
Asset not found or expired.
{ "error": "Asset not found" } -
Content moderation rejection.
{ "error": "Content moderation: prompt rejected", "code": 422 } -
All accounts at maximum capacity. Wait for current jobs to complete or use DELETE /jobs/
jobidto free slots.{ "error": "All configured accounts are running at maximum capacity", "code": 429 } -
596 Session Error
Account session expired. Re-add the account using POST /accounts with correct credentials.
{ "error": "Luma account has an error. Please check your account configuration via GET /v1/luma/accounts or re-add the account via POST /v1/luma/accounts" }
Model
{
jobid: string // Unique job identifier
type: 'video' // Job type
status: 'created' // Initial status
created: string // ISO 8601 timestamp
request: {
prompt: string
model: string // "ray-v3-flash" | "ray-v3" | "ray-v3-reasoning"
imageStart?: string // assetRef — start keyframe
imageEnd?: string // assetRef — end keyframe
imageCharacter?: string // assetRef — character reference (ray-v3 + sdr only)
resolution?: string // "draft" | "540p" | "720p" | "1080p"
aspect_ratio?: string // "9:16" | "3:4" | "1:1" | "4:3" | "16:9" | "21:9"
duration?: string // "5s" | "10s"
dynamic_range?: string // "sdr" | "hdr" | "hdr_exr"
}
}
Webhook Callback (replyUrl)
When replyUrl is provided, the API sends a POST request to that URL on completion or failure. The callback payload uses the same shape as GET /jobs/jobid with an additional replyRef field. See Webhook Callbacks for full type definitions.
Examples
-
# Text-to-video curl -X POST \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "prompt": "A serene mountain landscape at sunset", "model": "ray-v3-flash", "resolution": "720p", "aspect_ratio": "16:9", "duration": "5s" }' \ "https://api.useapi.net/v1/luma/videos" # Image-to-video curl -X POST \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Camera slowly pans across the scene", "model": "ray-v3", "imageStart": "u12345-email:[email protected]:a1b2c3d4-e5f6-7890-abcd-ef1234567890", "resolution": "1080p", "duration": "5s" }' \ "https://api.useapi.net/v1/luma/videos" -
const token = 'YOUR_API_TOKEN' const apiUrl = 'https://api.useapi.net/v1/luma/videos' // Text-to-video const response = await fetch(apiUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'A serene mountain landscape at sunset', model: 'ray-v3-flash', resolution: '720p', aspect_ratio: '16:9', duration: '5s' }) }) const result = await response.json() console.log('Job created:', result.jobid) // Poll for completion const poll = async (jobid) => { while (true) { const res = await fetch(`https://api.useapi.net/v1/luma/jobs/${jobid}`, { headers: { 'Authorization': `Bearer ${token}` } }) const job = await res.json() console.log('Status:', job.status) if (job.status === 'completed') { console.log('Video URL:', job.response.video.url) return job } if (job.status === 'failed') throw new Error(job.error) await new Promise(r => setTimeout(r, 10000)) } } const completed = await poll(result.jobid) -
import requests import time token = 'YOUR_API_TOKEN' api_url = 'https://api.useapi.net/v1/luma/videos' headers = { 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } # Text-to-video data = { 'prompt': 'A serene mountain landscape at sunset', 'model': 'ray-v3-flash', 'resolution': '720p', 'aspect_ratio': '16:9', 'duration': '5s' } response = requests.post(api_url, headers=headers, json=data) result = response.json() print(f"Job created: {result['jobid']}") # Poll for completion jobid = result['jobid'] while True: job = requests.get( f'https://api.useapi.net/v1/luma/jobs/{jobid}', headers={'Authorization': f'Bearer {token}'} ).json() print(f"Status: {job['status']}") if job['status'] == 'completed': print(f"Video URL: {job['response']['video']['url']}") break if job['status'] == 'failed': raise Exception(job.get('error')) time.sleep(10)