Video Generation
Generate videos from text, images, and supported reference assets.
Video generation is asynchronous. Create a task, poll its status, and download content only after the task is completed.
- Create:
POST /v1/videos/generations - Status:
GET /v1/videos/{video_id} - Content:
GET /v1/videos/{video_id}/content(video/mp4) - Edit:
POST /v1/videos/edits; the legacy Remix endpoint is deprecated
Supported model families
| Model family | Public model IDs | Input modes | Audio | Multimodal reference | Start/end frames |
|---|---|---|---|---|---|
| Seedance | seedance-2.0, seedance-2.0-fast | t2v, i2v, r2v | Audio input and generated audio | Yes | Yes |
| Wan | wan-2.5, wan-2.6, wan-2.6-flash, wan-2.7, wan-3.0 | t2v, i2v, r2v | Audio input and generated audio | Model-dependent | Model-dependent |
| Kling | kling-3.0, kling-2.6, kling-2.5-turbo | t2v, i2v, motion | Generated audio on supported models | Model-dependent | Model-dependent |
| Hailuo | hailuo-2.3, hailuo-2.3-fast | t2v, i2v | No | No | No |
| Veo | veo-3.1, veo-3.1-fast | t2v | Generated audio | No | No |
| Sora | sora-2, sora-2-pro | t2v, i2v, edit | Synchronized generated audio | No | No |
| Runway | gen4_turbo | i2v | No | No | No |
Create a video task
Endpoint: POST /v1/videos/generations
curl -X POST 'https://silkdock.ai/v1/videos/generations' \
-H 'Authorization: Bearer $SILKDOCK_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "seedance-2.0",
"prompt": "Ocean waves strike a lighthouse as the camera slowly pushes in",
"seconds": 10,
"extra_body": {
"resolution": "1080p",
"aspect_ratio": "16:9"
}
}'Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | Public model ID. |
prompt | string | Yes | Video description or transformation instruction. |
input_reference | string | string[] | file | No | One input image. Arrays are accepted for backward compatibility, but only the first non-empty item is used. |
seconds | integer | No | Video duration in seconds. Use a value supported by the selected model. |
size | string | No | Legacy pixel dimensions. Prefer extra_body.resolution and extra_body.aspect_ratio. |
user | string | No | End-user identifier supplied by the caller. |
extra_body | object | No | Model-specific extension fields listed below. |
extra_body fields
| Field | Type | Description |
|---|---|---|
resolution | string | 480p, 720p, 1080p, or 4k, as supported by the model. |
aspect_ratio | string | 16:9, 9:16, 1:1, 4:3, 3:4, or 21:9, as supported by the model. |
audio_url | string | External reference audio URL. |
generate_audio | boolean | Generate audio on the server. |
video_url | string | Seedance reference video for r2v mode. |
first_frame_url / first_image | string | Explicit first-frame URL. |
last_frame_url / last_image | string | Explicit last-frame URL. |
reference_image_urls | string[] | Multimodal reference-image URLs. |
reference_video_urls | string[] | Multimodal reference-video URLs. |
reference_audio_urls | string[] | Multimodal reference-audio URLs. |
motion_ref_url / motion_ref_urls | string | string[] | Motion-reference video URL or URLs. |
motion_mode | string | Kling supports std and pro; Seedance ignores this field. |
motion_strength | number | Motion-transfer strength. Use only when the model-specific contract declares allowed values. |
character_orientation | string | Kling character orientation: image or video. |
keep_original_sound | boolean | Whether Kling motion keeps the reference video's original sound. |
camera_control | object | Kling motion camera control. |
element_list | array | Kling subject-reference or element list. |
background_tolerance | number | Kling motion background tolerance. |
frames | integer | Seedance output frame count. When present, duration is not sent as well. |
return_last_frame | boolean | Return the generated last frame for Seedance. |
camera_fixed | boolean | Fix the camera for Seedance. |
seed | integer | Seedance random seed. |
callback_url | string | Seedance task callback URL. |
safety_identifier | string | Seedance safety identifier. |
service_tier | string | Seedance service tier. |
execution_expires_after | integer | Seedance task execution expiry. |
enhance_prompt | boolean | Veo prompt enhancement; defaults to true. |
prompt_extend | boolean | Wan 2.5/2.6/2.6 Flash/2.7/3.0 prompt rewriting; defaults to true. |
prompt_optimizer | boolean | Hailuo 2.3/Fast prompt optimization; defaults to true. |
fast_pretreatment | boolean | Hailuo 2.3/Fast fast preprocessing; defaults to false. |
aigc_watermark | boolean | Hailuo 2.3/Fast AIGC watermark; defaults to false. |
watermark | boolean | Seedance watermark; defaults to false. |
Each extension field is converted only when it is a native field declared by the selected model's official API.
think_level, thinking_level, and reasoning_effort are not part of the public image or video contract. Wan 3.0 also does not expose enable_thinking.
Do not send extension fields that are absent from the selected model's model-specific input list.
Reference input selection
| Goal | Input |
|---|---|
| Single-image video | input_reference as a URL or file |
| Multiple reference images or explicit multimodal image guidance | extra_body.reference_image_urls |
| General video reference | extra_body.reference_video_urls |
| Motion transfer | input_reference plus extra_body.motion_ref_url |
| One external audio input | extra_body.audio_url |
| Multimodal audio guidance | extra_body.reference_audio_urls |
| First or start/end frames | extra_body.first_frame_url and optionally extra_body.last_frame_url |
input_reference always represents one input image. An array is accepted only for backward compatibility: the gateway uses the first non-empty item and does not interpret later items as an end frame or multimodal references. A normal input_reference is not automatically converted to first_frame_url.
Discover model capabilities
Query GET /model_group/info?model_group=<MODEL_ID> before presenting model-specific controls.
These fields describe the public model contract, not a union of every underlying provider's capabilities. Only expose controls returned for the selected public model.
| Response field | Type | Description |
|---|---|---|
supported_resolutions | string[] | Supported resolution tiers. |
supported_aspect_ratios | string[] | Supported display ratios; prefer this list when rendering size controls. |
max_video_duration_seconds | number | Maximum output duration. |
supports_video_audio_input | boolean | Whether reference audio is supported. |
supports_video_audio_output | boolean | Whether generated output audio can be controlled. |
supports_video_multimodal_reference | boolean | Whether multimodal reference assets or native structures such as element_list are supported. |
supports_video_start_end_frame | boolean | Whether explicit start/end-frame generation is supported. |
supports_video_motion | boolean | Whether motion transfer is supported. |
curl 'https://silkdock.ai/model_group/info?model_group=seedance-2.0' \
-H 'Authorization: Bearer $SILKDOCK_API_KEY'Task responses
Creating a task returns an opaque ID. Do not parse or construct video IDs; status and content requests do not need the model ID again.
{
"id": "video_xxxxxx",
"object": "video",
"status": "processing",
"usage": {
"duration_seconds": 10.0,
"video_resolution": "1080p",
"has_audio": false
}
}A completed status response may include the download URL:
{
"id": "video_xxxxxx",
"status": "completed",
"url": "https://cdn.example.com/video.mp4"
}status is processing, completed, or failed. Failed tasks include an error object.
| Field | Type | Description |
|---|---|---|
id | string | Opaque video task ID. Do not parse or construct it. |
object | "video" | Object type. |
status | string | processing, completed, or failed. |
created_at | integer | null | Creation timestamp, when available. |
error | object | null | Failure details. |
usage | object | null | Billing inputs such as duration, resolution, and audio. |
url | string | null | Download URL after completion, when returned. |
Output specifications
| Model | Resolutions | Aspect ratios | seconds |
|---|---|---|---|
seedance-2.0 | 480p, 720p, 1080p, 4k | adaptive, 1:1, 4:3, 3:4, 16:9, 9:16, 21:9 | Any integer 4-15, or -1 for automatic |
seedance-2.0-fast | 480p, 720p | adaptive, 1:1, 4:3, 3:4, 16:9, 9:16, 21:9 | Any integer 4-15, or -1 for automatic |
kling-3.0 | 720p, 1080p, 4k | 1:1, 16:9, 9:16 | Any integer 1-15 |
wan-3.0 | 480p, 720p, 1080p | adaptive, 16:9, 4:3, 1:1, 3:4, 9:16 | Any integer 2-30, or -1 for automatic |
hailuo-2.3, hailuo-2.3-fast | 720p (officially 768P), 1080p | Model default for text; follows the reference image for image mode | 6 or 10 |
veo-3.1, veo-3.1-fast | 720p, 1080p, 4k | 16:9, 9:16 | 4, 6, or 8 |
sora-2, sora-2-pro | 720p, 1024p, 1080p on Pro | 16:9, 9:16 | 4, 8, 12, 16, or 20 |
gen4_turbo | 720p | 16:9, 9:16, 4:3, 3:4, 1:1, 21:9 | Any integer 2-10 |
A range such as 4-15 accepts every integer within the range. A comma-separated list accepts only those exact values.
Legacy size mapping
size | resolution | aspect_ratio |
|---|---|---|
1920x1080 | 1080p | 16:9 |
1080x1920 | 1080p | 9:16 |
1280x720 | 720p | 16:9 |
720x1280 | 720p | 9:16 |
1080x1080 | 1080p | 1:1 |
720x720 | 720p | 1:1 |
1440x1080 | 1080p | 4:3 |
960x720 | 720p | 4:3 |
1080x1440 | 1080p | 3:4 |
720x960 | 720p | 3:4 |
2520x1080 | 1080p | 21:9 |
1680x720 | 720p | 21:9 |
3840x2160 | 4k | 16:9 |
2160x3840 | 4k | 9:16 |
Seedance metering
Seedance reserves an estimated amount when the task is created using (input video seconds + output seconds) x width x height x 24 / 1024 x USD/token. A normal image-to-video request has no video input. Requests containing a reference video, motion video, or video edit use the video-input tier. Because input-video duration is not known at creation time, the estimate uses a four-second minimum; when the provider returns total_tokens, the gateway settles the difference against actual usage.
| Model | Output resolution | No video input (USD/M tokens) | With video input (USD/M tokens) |
|---|---|---|---|
seedance-2.0 | 480p, 720p | $7.00 | $4.30 |
seedance-2.0 | 1080p | $7.70 | $4.70 |
seedance-2.0 | 4K | $4.00 | $2.40 |
seedance-2.0-fast | 480p, 720p | $5.60 | $3.30 |
Metering uses the official international list price and does not follow temporary promotional discounts.
Image-to-video example
{
"model": "wan-2.7",
"prompt": "The subject turns and runs forward as the camera pulls back smoothly",
"input_reference": "https://example.com/first-frame.png",
"seconds": 10,
"extra_body": {
"resolution": "1080p",
"aspect_ratio": "16:9"
}
}Start/end-frame example
{
"model": "seedance-2.0",
"prompt": "Push slowly toward the subject and end on a night skyline",
"seconds": 6,
"extra_body": {
"resolution": "1080p",
"aspect_ratio": "16:9",
"first_frame_url": "https://example.com/first.png",
"last_frame_url": "https://example.com/last.png"
}
}Normal input_reference values remain reference images and do not automatically become first_frame_url. Check supports_video_start_end_frame before exposing this mode.
Motion-reference examples
Kling uses input_reference for the character or source image and motion_ref_url for the motion video:
{
"model": "kling-3.0",
"prompt": "Keep the character's appearance and transfer the dance motion",
"input_reference": "https://example.com/character.png",
"seconds": 5,
"extra_body": {
"motion_ref_url": "https://example.com/motion.mp4",
"motion_mode": "std",
"character_orientation": "image",
"keep_original_sound": false
}
}Seedance accepts the same public motion inputs. motion_mode is ignored for Seedance:
{
"model": "seedance-2.0",
"prompt": "Keep the subject and follow the walking rhythm and camera movement",
"input_reference": "https://example.com/character.png",
"seconds": 8,
"extra_body": {
"motion_ref_url": "https://example.com/motion.mp4",
"resolution": "720p",
"aspect_ratio": "16:9"
}
}Audio example
{
"model": "seedance-2.0",
"prompt": "A dancer spins in time with the beat",
"seconds": 10,
"extra_body": {
"resolution": "720p",
"aspect_ratio": "1:1",
"audio_url": "https://example.com/music.mp3"
}
}Code examples
curl -X POST 'https://silkdock.ai/v1/videos/generations' \
-H 'Authorization: Bearer sk-xxx' \
-H 'Content-Type: application/json' \
-d '{"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}'
curl 'https://silkdock.ai/v1/videos/video_xxx' \
-H 'Authorization: Bearer sk-xxx'
curl -L 'https://silkdock.ai/v1/videos/video_xxx/content' \
-H 'Authorization: Bearer sk-xxx' --output out.mp4const headers = { Authorization: "Bearer sk-xxx", "Content-Type": "application/json" };
const response = await fetch("https://silkdock.ai/v1/videos/generations", {
method: "POST",
headers,
body: JSON.stringify({
model: "seedance-2.0",
prompt: "Ocean waves strike a lighthouse",
seconds: 10,
extra_body: { resolution: "1080p", aspect_ratio: "16:9" },
}),
});
console.log(await response.json());import OpenAI from "openai";
const client = new OpenAI({ apiKey: "sk-xxx", baseURL: "https://silkdock.ai/v1" });
const video = await client.videos.create({
model: "seedance-2.0",
prompt: "Ocean waves strike a lighthouse",
seconds: 10,
extra_body: { resolution: "1080p", aspect_ratio: "16:9" },
});
let status = video;
while (status.status === "processing") {
await new Promise((resolve) => setTimeout(resolve, 5000));
status = await client.videos.retrieve(video.id);
}from openai import OpenAI
import time
client = OpenAI(api_key="sk-xxx", base_url="https://silkdock.ai/v1")
video = client.videos.create(
model="seedance-2.0",
prompt="Ocean waves strike a lighthouse",
seconds=10,
extra_body={"resolution": "1080p", "aspect_ratio": "16:9"},
)
while True:
status = client.videos.retrieve(video.id)
if status.status == "completed": break
if status.status == "failed": raise RuntimeError(status.error)
time.sleep(5)
content = client.videos.retrieve_content(video.id)
with open("out.mp4", "wb") as output:
output.write(content.read())#include <curl/curl.h>
int main(void) {
CURL *curl = curl_easy_init();
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Authorization: Bearer sk-xxx");
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, "https://silkdock.ai/v1/videos/generations");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"model\":\"seedance-2.0\",\"prompt\":\"Ocean waves strike a lighthouse\",\"seconds\":10,\"extra_body\":{\"resolution\":\"1080p\",\"aspect_ratio\":\"16:9\"}}");
curl_easy_perform(curl);
curl_easy_cleanup(curl);
}NSURL *url = [NSURL URLWithString:@"https://silkdock.ai/v1/videos/generations"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
[request setValue:@"Bearer sk-xxx" forHTTPHeaderField:@"Authorization"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
NSDictionary *payload = @{ @"model": @"seedance-2.0", @"prompt": @"Ocean waves strike a lighthouse", @"seconds": @10, @"extra_body": @{ @"resolution": @"1080p", @"aspect_ratio": @"16:9" } };
request.HTTPBody = [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil];
[[[NSURLSession sharedSession] dataTaskWithRequest:request] resume];HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://silkdock.ai/v1/videos/generations"))
.header("Authorization", "Bearer sk-xxx")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"model\":\"seedance-2.0\",\"prompt\":\"Ocean waves strike a lighthouse\",\"seconds\":10,\"extra_body\":{\"resolution\":\"1080p\",\"aspect_ratio\":\"16:9\"}}"))
.build();
System.out.println(HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()).body());payload := strings.NewReader(`{"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}`)
req, _ := http.NewRequest("POST", "https://silkdock.ai/v1/videos/generations", payload)
req.Header.Set("Authorization", "Bearer sk-xxx")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))<?php
$ch = curl_init('https://silkdock.ai/v1/videos/generations');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer sk-xxx', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['model' => 'seedance-2.0', 'prompt' => 'Ocean waves strike a lighthouse', 'seconds' => 10, 'extra_body' => ['resolution' => '1080p', 'aspect_ratio' => '16:9']])]);
echo curl_exec($ch);
curl_close($ch);var request = URLRequest(url: URL(string: "https://silkdock.ai/v1/videos/generations")!)
request.httpMethod = "POST"
request.setValue("Bearer sk-xxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let payload: [String: Any] = ["model": "seedance-2.0", "prompt": "Ocean waves strike a lighthouse", "seconds": 10, "extra_body": ["resolution": "1080p", "aspect_ratio": "16:9"]]
request.httpBody = try! JSONSerialization.data(withJSONObject: payload)
URLSession.shared.dataTask(with: request) { data, _, _ in print(String(data: data!, encoding: .utf8)!) }.resume()using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-xxx");
var json = JsonSerializer.Serialize(new { model = "seedance-2.0", prompt = "Ocean waves strike a lighthouse", seconds = 10, extra_body = new { resolution = "1080p", aspect_ratio = "16:9" } });
var response = await client.PostAsync("https://silkdock.ai/v1/videos/generations", new StringContent(json, Encoding.UTF8, "application/json"));
Console.WriteLine(await response.Content.ReadAsStringAsync());uri = URI("https://silkdock.ai/v1/videos/generations")
request = Net::HTTP::Post.new(uri, { "Authorization" => "Bearer sk-xxx", "Content-Type" => "application/json" })
request.body = { model: "seedance-2.0", prompt: "Ocean waves strike a lighthouse", seconds: 10, extra_body: { resolution: "1080p", aspect_ratio: "16:9" } }.to_json
puts Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }.bodyval json = """{"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}"""
val request = Request.Builder().url("https://silkdock.ai/v1/videos/generations")
.header("Authorization", "Bearer sk-xxx")
.post(json.toRequestBody("application/json".toMediaType())).build()
OkHttpClient().newCall(request).execute().use { println(it.body?.string()) }let response = reqwest::Client::new()
.post("https://silkdock.ai/v1/videos/generations")
.bearer_auth("sk-xxx")
.json(&serde_json::json!({"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}))
.send().await?;
println!("{}", response.text().await?);POST /v1/videos/generations HTTP/1.1
Host: silkdock.ai
Authorization: Bearer sk-xxx
Content-Type: application/json
{"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}final response = await http.post(
Uri.parse('https://silkdock.ai/v1/videos/generations'),
headers: {'Authorization': 'Bearer sk-xxx', 'Content-Type': 'application/json'},
body: jsonEncode({'model': 'seedance-2.0', 'prompt': 'Ocean waves strike a lighthouse', 'seconds': 10, 'extra_body': {'resolution': '1080p', 'aspect_ratio': '16:9'}}),
);
print(response.body);response <- request("https://silkdock.ai/v1/videos/generations") |>
req_headers(Authorization = "Bearer sk-xxx") |>
req_body_json(list(model = "seedance-2.0", prompt = "Ocean waves strike a lighthouse", seconds = 10, extra_body = list(resolution = "1080p", aspect_ratio = "16:9"))) |>
req_perform()
resp_body_json(response)let body = {|{"model":"seedance-2.0","prompt":"Ocean waves strike a lighthouse","seconds":10,"extra_body":{"resolution":"1080p","aspect_ratio":"16:9"}}|} in
let headers = Cohttp.Header.of_list [
("Authorization", "Bearer sk-xxx"); ("Content-Type", "application/json")
] in
Lwt_main.run (Cohttp_lwt_unix.Client.post ~headers ~body:(Cohttp_lwt.Body.of_string body)
(Uri.of_string "https://silkdock.ai/v1/videos/generations"))Check and download a task
- Status:
GET /v1/videos/{video_id} - Content:
GET /v1/videos/{video_id}/content
The task status is processing, completed, or failed. Download the result only after the status is completed. Poll every 3-5 seconds in production and set an application-level timeout.
Errors and billing
| Scenario | Behavior |
|---|---|
| Unsupported input mode | 400 BadRequestError |
| Unsupported resolution/aspect-ratio combination | Falls back to the model default and records a warning |
| Generation failure | status: "failed" with details in error |
| Download before completion | Video-not-ready error |
Billing depends on the model, duration, resolution, and generated audio. The usage object contains the metering inputs used by the gateway.
Last updated on