curl --request POST \
--url https://api.infery.ai/v1/videos/generations \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"resolution": "<string>",
"aspect_ratio": "<string>",
"n": 1,
"image_url": "<string>",
"video_url": "<string>",
"audio_url": "<string>",
"person_generation": "allow_all",
"style": "<string>"
}
'import requests
url = "https://api.infery.ai/v1/videos/generations"
payload = {
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"resolution": "<string>",
"aspect_ratio": "<string>",
"n": 1,
"image_url": "<string>",
"video_url": "<string>",
"audio_url": "<string>",
"person_generation": "allow_all",
"style": "<string>"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
duration: 123,
resolution: '<string>',
aspect_ratio: '<string>',
n: 1,
image_url: '<string>',
video_url: '<string>',
audio_url: '<string>',
person_generation: 'allow_all',
style: '<string>'
})
};
fetch('https://api.infery.ai/v1/videos/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.infery.ai/v1/videos/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'prompt' => '<string>',
'duration' => 123,
'resolution' => '<string>',
'aspect_ratio' => '<string>',
'n' => 1,
'image_url' => '<string>',
'video_url' => '<string>',
'audio_url' => '<string>',
'person_generation' => 'allow_all',
'style' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.infery.ai/v1/videos/generations"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.infery.ai/v1/videos/generations")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/videos/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "0f9c3b1e-6d2a-4c17-9f83-2b5e7a41c8d0",
"status": "queued",
"progress": 0,
"created": 1713204900,
"model": "veo-3.1-fast"
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}Create video generation
POST /v1/videos/generations — submit an async video generation job.
curl --request POST \
--url https://api.infery.ai/v1/videos/generations \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"resolution": "<string>",
"aspect_ratio": "<string>",
"n": 1,
"image_url": "<string>",
"video_url": "<string>",
"audio_url": "<string>",
"person_generation": "allow_all",
"style": "<string>"
}
'import requests
url = "https://api.infery.ai/v1/videos/generations"
payload = {
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"resolution": "<string>",
"aspect_ratio": "<string>",
"n": 1,
"image_url": "<string>",
"video_url": "<string>",
"audio_url": "<string>",
"person_generation": "allow_all",
"style": "<string>"
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
duration: 123,
resolution: '<string>',
aspect_ratio: '<string>',
n: 1,
image_url: '<string>',
video_url: '<string>',
audio_url: '<string>',
person_generation: 'allow_all',
style: '<string>'
})
};
fetch('https://api.infery.ai/v1/videos/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.infery.ai/v1/videos/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => '<string>',
'prompt' => '<string>',
'duration' => 123,
'resolution' => '<string>',
'aspect_ratio' => '<string>',
'n' => 1,
'image_url' => '<string>',
'video_url' => '<string>',
'audio_url' => '<string>',
'person_generation' => 'allow_all',
'style' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.infery.ai/v1/videos/generations"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.infery.ai/v1/videos/generations")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/videos/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"resolution\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"n\": 1,\n \"image_url\": \"<string>\",\n \"video_url\": \"<string>\",\n \"audio_url\": \"<string>\",\n \"person_generation\": \"allow_all\",\n \"style\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "0f9c3b1e-6d2a-4c17-9f83-2b5e7a41c8d0",
"status": "queued",
"progress": 0,
"created": 1713204900,
"model": "veo-3.1-fast"
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}id → poll the status endpoint until complete.
Submit a job
curl https://api.infery.ai/v1/videos/generations \
-H "Authorization: Bearer $INFERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-fast",
"prompt": "A cat surfing on a banana at sunset, cinematic",
"duration": 4,
"resolution": "720p",
"aspect_ratio": "16:9"
}'
{
"id": "0f9c3b1e-6d2a-4c17-9f83-2b5e7a41c8d0",
"status": "queued",
"progress": 0,
"created": 1713204900,
"model": "veo-3.1-fast"
}
id (a UUID), not job_id, and the timestamp is created, not created_at. The duration field is duration; duration_seconds is not recognised and an unrecognised key is ignored rather than refused, so the model’s default duration is rendered and billed instead.
Image-to-video
Pass a reference image viaimage_url. There is no inline-base64 field on this endpoint:
{
"model": "veo-3.1-fast",
"prompt": "Animate this photo with gentle camera pan",
"image_url": "https://cdn.example.com/source.jpg"
}
Supported models
Google Veo (3 and 2), OpenAI Sora, xAI (Grok Video), Alibaba Wan. See Models catalog.Storage
Theresult.url of a completed job is the upstream provider’s URL and expires with it — usually within an hour. Video jobs write no copy into workspace storage and return no file_id. Download the clip as soon as the job completes, and upload it through POST /v1/files if you need a durable handle.Authorizations
API key in format: Bearer inf_***
Body
Model ID to use for generation
Text prompt describing the video to generate
Duration in seconds (model-specific, see /v1/models)
Video resolution (model-specific, see /v1/models)
Video aspect ratio (model-specific, see /v1/models)
Number of videos to generate
Reference image URL for image-to-video
Reference video URL for video-to-video generation (model-specific)
Reference audio URL for lipsync generation (model-specific)
Person generation policy (Google Veo models)
dont_allow, allow_adult, allow_all Frame rate of the generated clip. Only 24, 30 and 60 are accepted; anything else is refused with 400. Also refused with 400 for a model served directly by Google (the Veo family), which has no frame-rate parameter — omit it there. Where it is accepted it is a billing dimension: the credit hold and the settle are both priced on it.
24, 30, 60 Free-form style hint. Accepted, persisted with the job and carried into the provider request object — but INERT today: no video provider reads it. The FAL mapper forwards only fields the model's own schema declares (and none declares style), and the direct providers build their request bodies field by field without it. Declared because the endpoint takes it, not because it changes the video.
Response
Video generation job submitted. Poll GET /v1/videos/generations/{jobId} until status === "completed".