Video
Video models usually run as asynchronous tasks and may bill by seconds, resolution, or clip. Start with duration=5 or shorter, n=1, and a base resolution to verify model choice, parameters, and callback handling.
POST /v1/video/generations
Async video generation. Submit a prompt to receive a task ID, then poll task status for the final video. Use /v1/models and the model detail page for text-to-video, image-to-video, reference-image, or editing parameters.
Image-to-video, keyframe, and video-edit routes are most reliable with data:image/...;base64,... image inputs. Plain image or video URLs must be directly downloadable by the execution provider; avoid signed-in, blocked, very small, or private resources.
Use /v1/models model details as the source of truth; supported input modes, resolutions, and durations can differ by video model.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | Choose a video generation model from /v1/models |
| prompt | string | Yes* | Video description; can be generated from an existing prompt template via template_id |
| template_id | string | No | Existing prompt template ID, use with variables; unknown templates return 404 |
| variables | object | No | Prompt template variables; values must be strings |
| image / image_url | string | No | Starting frame as base64 or URL |
| n | integer | No | 1 - 4 |
| size | string | No | 832x480, 480x832, 624x624, 1280x720, 720x1280, 960x960, 1088x832, 832x1088, 1920x1080, 1080x1920, 1440x1440, 1632x1248, 1248x1632 |
| duration | integer | No | 1 - 60 seconds; use 5 seconds or shorter for first probes |
| fps | integer | No | 1 - 60 |
| negative_prompt | string | No | Negative prompt, max 1024 chars |
| seed | integer | No | Random seed for reproducible generation |
| webhook_url | string | No | Callback URL on completion (https only) |
| tags | array | No | Array of tag strings |
curl https://test.sealink.io/v1/video/generations \-H "Authorization: Bearer $SEALINK_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "kling-v3-omni","prompt": "A serene lake at sunset, camera slowly panning across the water","size": "1280x720","duration": 5,"n": 1}'
import osfrom openai import OpenAIimport requests# For async video generation, use the raw HTTP clientres = requests.post("https://test.sealink.io/v1/video/generations",headers={"Authorization": f"Bearer {os.environ['SEALINK_API_KEY']}"},json={"model": "kling-v3-omni","prompt": "A serene lake at sunset, camera slowly panning across the water","size": "1280x720","duration": 5,"n": 1,},)task = res.json()print(f"Task ID: {task['id']}")
IMG_B64="$(base64 -w0 first-frame.png)"curl https://test.sealink.io/v1/video/generations \-H "Authorization: Bearer $SEALINK_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "<image-to-video-model-from-/v1/models>","prompt": "A tiny product photo turning slowly on a clean table","image_url": "data:image/png;base64,'"$IMG_B64"'","size": "832x480","duration": 5,"n": 1}'
import osimport requestsres = requests.post("https://test.sealink.io/v1/video/generations",headers={"Authorization": f"Bearer {os.environ['SEALINK_API_KEY']}"},json={"model": "<image-to-video-model-from-/v1/models>","prompt": "A tiny product photo turning slowly on a clean table","image_url": "https://raw.githubusercontent.com/mathiasbynens/small/master/jpeg.jpg","size": "832x480","duration": 3,"n": 1,},)task = res.json()print(f"Task ID: {task['id']}")
FIRST_B64="$(base64 -w0 first-frame.png)"LAST_B64="$(base64 -w0 last-frame.png)"curl https://test.sealink.io/v1/video/generations \-H "Authorization: Bearer $SEALINK_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "<keyframe-video-model-from-/v1/models>","prompt": "Smoothly move from the first frame to the last frame","image_url": "data:image/png;base64,'"$FIRST_B64"'","last_image_url": "data:image/png;base64,'"$LAST_B64"'","size": "832x480","duration": 5,"n": 1}'
POST /v1/video/edits
Video editing. Edit existing videos using prompts, including background replacement and style transfer. Animate-style edits usually require both a video input and a reference image, use /v1/video/edits, and human-body animation inputs should contain exactly one clearly visible human body.
Image-to-video, keyframe, and video-edit routes are most reliable with data:image/...;base64,... image inputs. Plain image or video URLs must be directly downloadable by the execution provider; avoid signed-in, blocked, very small, or private resources.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Yes | Choose a video editing model from /v1/models |
| video | string | Yes | Source video as base64 or URL |
| prompt | string | Yes | Edit instruction description |
| negative_prompt | string | No | Negative prompt |
| image / image_url | string | No | Reference image base64 or URL |
| reference_image_url / reference_url | string | No | Reference image URL aliases |
| resolution | string | No | Same as video size enum |
| duration | integer | No | 1 - 60 seconds |
| seed | integer | No | Random seed |
| prompt_extend | boolean | No | Enable prompt expansion |
| watermark / check_image | boolean | No | Provider watermark and image validation toggles |
curl https://test.sealink.io/v1/video/edits \-H "Authorization: Bearer $SEALINK_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "kling-v3-omni","video": "https://example.com/input-video.mp4","prompt": "Change the background to a beach sunset","resolution": "1280x720","duration": 5}'
import osimport requestsres = requests.post("https://test.sealink.io/v1/video/edits",headers={"Authorization": f"Bearer {os.environ['SEALINK_API_KEY']}"},json={"model": "kling-v3-omni","video": "https://example.com/input-video.mp4","prompt": "Change the background to a beach sunset","resolution": "1280x720","duration": 5,},)task = res.json()print(f"Task ID: {task['id']}")
IMG_B64="$(base64 -w0 character.png)"curl https://test.sealink.io/v1/video/edits \-H "Authorization: Bearer $SEALINK_API_KEY" \-H "Content-Type: application/json" \-d '{"model": "<video-animate-model-from-/v1/models>","prompt": "Make the subject wave gently","image_url": "data:image/png;base64,'"$IMG_B64"'","video_url": "https://example.com/single-person.mp4","size": "832x480","duration": 5,"n": 1}'
GET /v1/tasks/{task_id}
Poll async task status. Completed video tasks return data or upstream_response and settle usage at terminal state.
Status values: pending | running | completed | failed. Async routes with cancellation support can use DELETE /v1/tasks/{task_id} to release the pre-authorization; tasks without upstream cancellation return 501. Do not keep the submit request open while the video renders.
# Poll task statuscurl https://test.sealink.io/v1/tasks/task_abc123 \-H "Authorization: Bearer $SEALINK_API_KEY"
# Cancel a running async task when the route supports cancellationcurl -X DELETE https://test.sealink.io/v1/tasks/task_abc123 \-H "Authorization: Bearer $SEALINK_API_KEY"
# Poll until completeimport osimport requestsimport timetask_id = "task_abc123"while True:res = requests.get("https://test.sealink.io/v1/tasks/" + task_id,headers={"Authorization": f"Bearer {os.environ['SEALINK_API_KEY']}"},)task = res.json()if task["status"] in ("completed", "failed"):print(task["status"], task.get("data") or task.get("upstream_response"))breaktime.sleep(5)
const taskId = "task_abc123";async function poll() {while (true) {const res = await fetch(`https://test.sealink.io/v1/tasks/${taskId}`,{ headers: { Authorization: `Bearer ${process.env.SEALINK_API_KEY}` } });const task = await res.json();if (task.status === "completed" || task.status === "failed") {console.log(task.status, task.data ?? task.upstream_response);break;}await new Promise(r => setTimeout(r, 5000));}}poll();