Create an AI video generation job
curl --request POST \
--url https://api.adskull.io/v1/video-generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"prompt": "<string>",
"resolution": "<string>",
"duration_seconds": "8",
"tier": "<string>",
"ratio": "9:16",
"audio_enabled": true,
"negative_prompt": "<string>",
"input_image_url": "<string>",
"input_video_url": "<string>"
}
'import requests
url = "https://api.adskull.io/v1/video-generations"
payload = {
"prompt": "<string>",
"resolution": "<string>",
"duration_seconds": "8",
"tier": "<string>",
"ratio": "9:16",
"audio_enabled": True,
"negative_prompt": "<string>",
"input_image_url": "<string>",
"input_video_url": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: '<string>',
resolution: '<string>',
duration_seconds: '8',
tier: '<string>',
ratio: '9:16',
audio_enabled: true,
negative_prompt: '<string>',
input_image_url: '<string>',
input_video_url: '<string>'
})
};
fetch('https://api.adskull.io/v1/video-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.adskull.io/v1/video-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([
'prompt' => '<string>',
'resolution' => '<string>',
'duration_seconds' => '8',
'tier' => '<string>',
'ratio' => '9:16',
'audio_enabled' => true,
'negative_prompt' => '<string>',
'input_image_url' => '<string>',
'input_video_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.adskull.io/v1/video-generations"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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.adskull.io/v1/video-generations")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.adskull.io/v1/video-generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"object": "image_generation_job",
"status": "queued",
"credits_reserved": 123,
"assets": [
{
"id": "<string>",
"object": "asset",
"type": "image",
"url": "<string>",
"mime_type": "<string>",
"size_bytes": 123,
"duration_seconds": 123,
"width": 123,
"height": 123,
"expires_at": "2023-11-07T05:31:56Z"
}
],
"created_at": "2023-11-07T05:31:56Z",
"progress_percent": 50,
"credits_used": 123,
"credits_refunded": 0,
"request": {},
"failure_code": "<string>",
"failure_message": "<string>",
"updated_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"failed_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Unique key for safe retries of job creation requests.
8 - 128Body
Video generation request. The backend validates the
(model_id, tier, resolution, duration_seconds, audio_enabled)
tuple against the pricing matrix and rejects any invalid combo
with 400 invalid_request. Call GET /v1/models/{model_id} for
the authoritative options, or use the per-model matrix in the docs.
Required-in-practice fields beyond the OpenAPI required list:
• mode — must be edit for V2V models or motion for MC models.
• audio_enabled — required boolean for any model with audio pricing
rows (Veo, Sora, Wan 2.6, Wan 2.7, V2V, MC, Kling, Seedance 1.5 Pro,
Seedance 2.5, Seedance 2.5 V2V).
Orientation cheatsheet: • 9:16 → vertical / portrait (TikTok, Reels, Shorts) • 16:9 → horizontal / landscape (YouTube, web) • 1:1 → square (Instagram feed)
Models with inherit-from-input ratios (do NOT send ratio):
wan-2.6, hailuo-2.3, grok-imagine-1.5, wan-2.6-v2v, kling-2.6-mc,
kling-3.0-mc. minimax-h3 inherits only on the image-to-video path:
send ratio for text-to-video, omit it when input_image_url is set
(the output matches the input image).
Image-to-video-only models (input_image_url REQUIRED): wan-2.6, hailuo-2.3, grok-imagine-1.5.
Video model. Call GET /v1/models/{model_id} for full options.
veo-3.1, kling-2.6, kling-3.0, seedance-1.5-pro, seedance-2.0, seedance-2.5, wan-2.6, wan-2.7, hailuo-2.3, grok-imagine, grok-imagine-1.5, happyhorse-1.1, kling-3.0-turbo, gemini-omni, sora-2, sora-2-pro, minimax-h3, wan-2.6-v2v, wan-2.7-videoedit, seedance-2.5-v2v, minimax-h3-v2v, kling-2.6-mc, kling-3.0-mc 1 - 4096Per-model resolution: • veo-3.1 → 720p | 1080p | 4K • kling-2.6 → 1080p • kling-3.0 → 720p | 1080p • seedance-1.5-pro → 480p | 720p | 1080p • seedance-2.0 (tier=fast) → 480p | 720p • seedance-2.0 (tier=quality) → 480p | 720p | 1080p • seedance-2.5, seedance-2.5-v2v → 480p | 720p (no 1080p, no 4K) • wan-2.6, wan-2.7, wan-2.6-v2v, wan-2.7-videoedit → 720p | 1080p • hailuo-2.3 → 768p (6/10s) | 1080p (6s only) • minimax-h3, minimax-h3-v2v → 768p | 2K • grok-imagine → 480p | 720p • sora-2 → 720p • sora-2-pro → 720p | 1024x1792 | 1080x1920
Duration as a STRING (not number). Per-model accepted values: • veo-3.1 → "8" (8s; extend for more) • kling-2.6 → "5" | "10" • kling-3.0 → "3" | "5" | "7" | "10" | "15" • seedance-1.5-pro → "4" | "8" | "12" • seedance-2.0 → "4" | "8" | "12" • seedance-2.5, seedance-2.5-v2v → "4" | "5" | "8" | "10" | "15" | "20" | "30" • wan-2.6 → "5" | "10" | "15" • wan-2.7 → "5" | "8" • wan-2.7-videoedit → "5" | "8" | "10" • wan-2.6-v2v → "5" | "10" • hailuo-2.3 (768p) → "6" | "10" • hailuo-2.3 (1080p) → "6" only • minimax-h3, minimax-h3-v2v → "4"–"15" (every integer) • grok-imagine → "6" | "10" | "15" | "20" | "30" • sora-2 / sora-2-pro → "4" | "8" | "12" | "16" | "20"
"8"
• generate — text or first-frame image-to-video (most models). • edit — required for wan-2.6-v2v, wan-2.7-videoedit, seedance-2.5-v2v, minimax-h3-v2v (needs input_video_url). • motion — required for kling-2.6-mc, kling-3.0-mc (needs input_image_url + input_video_url).
generate, edit, motion Per-model performance tier: • veo-3.1 → lite | fast | quality (default fast; lite cannot extend) • seedance-2.0 → fast | quality (fast has no 1080p) • hailuo-2.3 → standard | pro • grok-imagine → fun | normal | spicy (spicy rejects uploaded refs) Other models ignore this field.
Aspect ratio W:H. Per-model supported values:
• veo-3.1, sora-2, sora-2-pro → 9:16, 16:9
• kling-2.6, kling-3.0 → 9:16, 16:9, 1:1
• seedance-1.5-pro, seedance-2.0 → 1:1, 4:3, 3:4, 16:9, 9:16, 21:9 (seedance-2.0 also: adaptive)
• seedance-2.5, seedance-2.5-v2v → 1:1, 4:3, 3:4, 16:9, 9:16, 21:9, adaptive
• wan-2.7, wan-2.7-videoedit → 16:9, 9:16, 1:1, 4:3, 3:4
• grok-imagine → 2:3, 3:2, 1:1, 16:9, 9:16
• minimax-h3, minimax-h3-v2v → 21:9, 16:9, 4:3, 1:1, 3:4, 9:16
(minimax-h3-v2v also: adaptive — its default; minimax-h3
REQUIRES ratio for text-to-video but ignores it when
input_image_url is set — omit it for image-to-video)
DO NOT send ratio for wan-2.6, hailuo-2.3, wan-2.6-v2v,
kling-*-mc (ratio inherits from the input media).
"9:16"
Per-model audio behavior: • forced-on (rejects false): veo-3.1, sora-2, sora-2-pro, wan-2.6, minimax-h3, minimax-h3-v2v (native stereo audio always on) • forced-off (rejects true): wan-2.7, hailuo-2.3, grok-imagine, wan-2.6-v2v, wan-2.7-videoedit, MC • toggle: kling-2.6, kling-3.0, seedance-1.5-pro, seedance-2.5, seedance-2.5-v2v • n/a (ignored): seedance-2.0
Content to avoid. Supported by kling, seedance, wan, V2V, MC. Ignored by veo, sora, hailuo, grok.
Hosted image URL. REQUIRED for wan-2.6 / hailuo-2.3 (image-to-video) and for mode=motion (kling-*-mc). Optional first-frame for veo / kling / seedance / wan-2.7 / grok / sora. seedance-2.5 also accepts up to 4 reference images (never mixed with first/last frames). Use POST /v1/assets to host local files.
Hosted video URL. REQUIRED for mode=edit (wan-2.6-v2v, wan-2.7-videoedit, seedance-2.5-v2v, minimax-h3-v2v) and mode=motion (kling-*-mc). minimax-h3-v2v references must be MP4/MOV (H.264/H.265), ≤ 50 MB, 2–15s per clip, ≤ 15s total, and are billed on input + output seconds. Use POST /v1/assets to host local files.
Response
Video generation accepted.
image_generation_job, video_generation_job, talking_avatar_job queued, processing, completed, failed, canceled Show child attributes
Show child attributes
0 <= x <= 100curl --request POST \
--url https://api.adskull.io/v1/video-generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"prompt": "<string>",
"resolution": "<string>",
"duration_seconds": "8",
"tier": "<string>",
"ratio": "9:16",
"audio_enabled": true,
"negative_prompt": "<string>",
"input_image_url": "<string>",
"input_video_url": "<string>"
}
'import requests
url = "https://api.adskull.io/v1/video-generations"
payload = {
"prompt": "<string>",
"resolution": "<string>",
"duration_seconds": "8",
"tier": "<string>",
"ratio": "9:16",
"audio_enabled": True,
"negative_prompt": "<string>",
"input_image_url": "<string>",
"input_video_url": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: '<string>',
resolution: '<string>',
duration_seconds: '8',
tier: '<string>',
ratio: '9:16',
audio_enabled: true,
negative_prompt: '<string>',
input_image_url: '<string>',
input_video_url: '<string>'
})
};
fetch('https://api.adskull.io/v1/video-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.adskull.io/v1/video-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([
'prompt' => '<string>',
'resolution' => '<string>',
'duration_seconds' => '8',
'tier' => '<string>',
'ratio' => '9:16',
'audio_enabled' => true,
'negative_prompt' => '<string>',
'input_image_url' => '<string>',
'input_video_url' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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.adskull.io/v1/video-generations"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
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.adskull.io/v1/video-generations")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.adskull.io/v1/video-generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"resolution\": \"<string>\",\n \"duration_seconds\": \"8\",\n \"tier\": \"<string>\",\n \"ratio\": \"9:16\",\n \"audio_enabled\": true,\n \"negative_prompt\": \"<string>\",\n \"input_image_url\": \"<string>\",\n \"input_video_url\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"object": "image_generation_job",
"status": "queued",
"credits_reserved": 123,
"assets": [
{
"id": "<string>",
"object": "asset",
"type": "image",
"url": "<string>",
"mime_type": "<string>",
"size_bytes": 123,
"duration_seconds": 123,
"width": 123,
"height": 123,
"expires_at": "2023-11-07T05:31:56Z"
}
],
"created_at": "2023-11-07T05:31:56Z",
"progress_percent": 50,
"credits_used": 123,
"credits_refunded": 0,
"request": {},
"failure_code": "<string>",
"failure_message": "<string>",
"updated_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"failed_at": "2023-11-07T05:31:56Z"
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}{
"error": {
"code": "<string>",
"message": "<string>",
"request_id": "<string>",
"details": {}
}
}
