Guide
Create a Video Task
Request parameters, reference asset formats, and responses for creating video tasks
Create a Video Task
Video generation is an async task: a successful creation only means the task has been accepted. Save the id in the response and then query the task to read its progress and result. One creation request corresponds to one task; querying and page refreshes do not create duplicates or cause duplicate charges.
For shared conventions (base URL, authentication, response structure, rate limiting, idempotency), see Authentication and Common Conventions.
API overview
| Purpose | Method | Path | Details |
|---|---|---|---|
| Create a video task | POST | /v1/video/generations | This page |
| Create a video task (OpenAI-compatible form) | POST | /v1/videos | This page |
| Query a video task | GET | /v1/video/generations/{task_id} | Query a Video Task |
| Query a video task (OpenAI-compatible form) | GET | /v1/videos/{task_id} | Query a Video Task |
Both forms have identical request bodies, response bodies, and task IDs, so either one works; the same task ID can be queried under both sets of paths.
Existing clients can continue using /v1/video/generations; the platform handles it at the entry layer as the /v1/videos video task plugin, with no field or path changes required.
Prepare variables
export LOCOPAL_API_KEY="sk-你的APIKey"
export LOCOPAL_API_ORIGIN="https://locopalai.com"
export LOCOPAL_VIDEO_MODEL_ID="从 /v1/models 返回的视频模型 ID"
export LOCOPAL_IMAGE_URL="https://你的对象存储域名/reference.png"
export LOCOPAL_VIDEO_URL="https://你的对象存储域名/reference.mp4"
export LOCOPAL_AUDIO_URL="https://你的对象存储域名/reference.mp3"
export LOCOPAL_TASK_ID="创建视频后响应中的 id"Create a video task
/v1/video/generationsAuthentication
Authorization: Bearer <API_KEY>, using a platform API key created on the console's "API Keys" page.
Request body · application/json
Prop
Type
Provide at least one form of text input, prompt or content: when only content is submitted, the platform uses the text of the first type: "text" element as the prompt. A missing model returns HTTP 400; do not pass parameters to the model that are not declared as supported on its details page.
content elements
type | Content field | role | Description |
|---|---|---|---|
text | text | Omit | Text prompt |
image_url | image_url.url | reference_image | Ordinary reference image; multiple can be submitted |
image_url | image_url.url | first_frame | Video first frame |
image_url | image_url.url | last_frame | Video last frame |
video_url | video_url.url | reference_video | Reference video for motion, camera movement, pacing, or visuals |
audio_url | audio_url.url | reference_audio | Reference for sound or pacing |
Public assets must use directly downloadable HTTPS URLs and must not depend on cookies, Referer, or login pages; images may also use data:image/...;base64,... depending on model support. Assets in the asset library with status Active use asset://<asset_id>; portrait assets can only be submitted to models that support the portrait asset library.
The image_url, video_url, and audio_url items in the content array are passed to the upstream in their original types; top-level parameters such as duration, ratio, resolution, seed, watermark, and generate_audio are also submitted with the task and do not need to be wrapped in metadata.
If you only need one ordinary reference image, you can also use the top-level image_url shorthand:
{
"model": "$LOCOPAL_VIDEO_MODEL_ID",
"prompt": "镜头缓慢推进",
"image_url": "https://your-object-storage.example/reference.png",
"duration": 5,
"ratio": "9:16",
"resolution": "480p",
"seed": 20260409,
"watermark": false
}The platform converts the top-level image_url into a single reference image content item. When you need multiple images, first/last frames, a reference video, or reference audio, use the content array.
Request example
Text-to-video
content is an array: use { "type": "text", "text": "..." } for text,
and type: "image_url" for reference images. For pure text generation, a single text item is enough.
resolution, ratio, and duration must be within the tiers supported by the current model.
generate_audio and watermark are not accepted by all models.
After a successful submission, rely only on the returned id / task_id to query; do not create the task again.
Text-to-video
curl -X POST "$LOCOPAL_API_ORIGIN/v1/video/generations" \
-H "Authorization: Bearer $LOCOPAL_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"model": "$LOCOPAL_VIDEO_MODEL_ID",
"content": [
{ "type": "text", "text": "雨后的城市街道,镜头从水面倒影缓慢抬升,电影感" }
],
"resolution": "720p",
"ratio": "16:9",
"duration": 5,
"generate_audio": true,
"watermark": false
}
JSONSingle image to video
{
"model": "从 /v1/models 选择的视频模型 ID",
"content": [
{ "type": "text", "text": "人物自然转身,衣摆随风摆动,镜头轻微环绕" },
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "https://你的对象存储域名/reference.png" }
}
],
"resolution": "720p",
"ratio": "9:16",
"duration": 5
}First and last frames
The first and last frames must be marked first_frame and last_frame respectively, using two different images.
{
"model": "从 /v1/models 选择的视频模型 ID",
"content": [
{ "type": "text", "text": "镜头从室内平滑移动到窗外城市夜景" },
{
"type": "image_url",
"role": "first_frame",
"image_url": { "url": "https://你的对象存储域名/first.png" }
},
{
"type": "image_url",
"role": "last_frame",
"image_url": { "url": "https://你的对象存储域名/last.png" }
}
],
"resolution": "720p",
"ratio": "16:9",
"duration": 5
}Multiple images and reference videos
The "depth video" often mentioned in business contexts has no separate deep_video field in the public API; it is submitted as a reference video: use video_url for type and reference_video for role. Each reference image occupies its own content element, and multiple URLs cannot be placed in a single image_url.url.
curl -X POST "$LOCOPAL_API_ORIGIN/v1/video/generations" \
-H "Authorization: Bearer $LOCOPAL_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- <<JSON
{
"model": "$LOCOPAL_VIDEO_MODEL_ID",
"content": [
{
"type": "text",
"text": "以图片1的人物为主体,沿用图片2的服装,参考视频的动作节奏和运镜,保持人物身份与产品外观一致。"
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "$LOCOPAL_IMAGE_URL" }
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "asset://你的素材ID" }
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "https://你的对象存储域名/scene.png" }
},
{
"type": "video_url",
"role": "reference_video",
"video_url": { "url": "$LOCOPAL_VIDEO_URL" }
}
],
"resolution": "720p",
"ratio": "16:9",
"duration": 7,
"generate_audio": false,
"watermark": false
}
JSONThe array order is the asset order. It is recommended to explicitly write "image 1, image 2, image 3, reference video" in the prompt rather than relying on the server guessing the order from file names. The number of reference images, reference video, reference audio, output resolution, and duration are determined by model capabilities; see Multiple Images and Reference Videos for details.
Multiple images, reference audio, and a fixed seed
seed can fix the sampling result; reference_audio serves as a reference for sound or pacing; duration, generate_audio, ratio, resolution, and watermark are all top-level parameters. The example below uses the 9:16 video parameters commonly used by customers:
{
"model": "doubao-seedance-2.0-D",
"content": [
{
"type": "text",
"text": "以图片1的人物和服装为主体,参考图片2的另一名角色,参考音频的情绪和节奏生成电影感画面,保持角色身份一致。"
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "asset://asset-20260917114312-cyele" }
},
{
"type": "image_url",
"role": "reference_image",
"image_url": { "url": "asset://asset-20260917111324-mquys" }
},
{
"type": "audio_url",
"role": "reference_audio",
"audio_url": { "url": "https://your-object-storage.example/reference.mp3" }
}
],
"duration": 9,
"generate_audio": true,
"ratio": "9:16",
"resolution": "480p",
"seed": 20260409,
"watermark": false
}After a successful creation, the id / task_id in the response is still queried through the async task flow; reference audio must be an HTTPS address the platform can access, and asset:// assets must first be Active.
Response parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Public task ID, used when querying the task |
task_id | string | Compatibility field identical to id |
model | string | Model ID used for this request |
status | string | queued when accepted successfully |
created_at | integer | Task creation time (Unix seconds) |
object | string | Optional; may be omitted in the creation response and is usually video after a successful query |
progress | integer | Optional; may be omitted in the creation response, and the current progress is returned by queries |
Response body
{
"created_at": 1789567067,
"id": "task_QH33zpW2IRHEnrmBbZFvtPzodyXvevWu",
"model": "seedance-2.0-mini",
"status": "queued",
"task_id": "task_QH33zpW2IRHEnrmBbZFvtPzodyXvevWu"
}The creation response is not a fixed full set of fields. Clients should rely on whether id / task_id is non-empty, and must not treat the presence of object or progress as a requirement for successful acceptance.
After receiving HTTP 200 and a task ID, even if the local wait times out, only query the original task; never automatically create it again.
Error response
When parameter validation fails, the API returns HTTP 400 with code of invalid_request, and message directly states what is missing or wrong:
{
"code": "invalid_request",
"message": "缺少提示词:请在 prompt 或 content 的 text 元素中提供文本描述",
"data": null
}When the balance or the current API key quota is insufficient to cover the estimated cost of this request, the API returns HTTP 403 without creating a task or incurring any charge:
{
"code": "insufficient_user_quota",
"message": "余额不足:本次预计需要 $11.500000,当前可用 $0.002000,请充值或调整参数后重试",
"data": null
}| HTTP | Common cause | Handling |
|---|---|---|
400 | Missing model, malformed JSON, missing prompt, or an incorrectly written reference asset role or URL | Fix according to message and resubmit |
401 | API key missing, expired, or unauthorized | Use a valid key |
403 | Balance or current key quota insufficient to cover the estimated cost (insufficient_user_quota) | Top up or reduce parameters such as duration/resolution, then resubmit; no task is created in this case |
429 | In-flight tasks have reached the concurrency limit (task_concurrency_exceeded) | Wait for existing tasks to finish according to "currently N / limit M" in the message before submitting |
429 | The current group's upstream load is saturated or the request rate is limited | Retry later and avoid concurrent duplicate submissions |
500 | Task creation failed | Read the error code; if a task ID already exists, keep querying the original task |
503 | The current model is unavailable | Query /v1/models again and switch to an available model, or try again later |
Concurrency and submission pacing
Generation tasks run concurrently in the background, and both submission and result downloads consume the platform's outbound bandwidth, so the platform caps the number of tasks being processed at the same time: each account can have at most 2000 at once. Submitting after reaching the limit returns:
{
"code": "task_concurrency_exceeded",
"message": "当前账号有 2000 个生成任务正在处理中,已达到并发上限 2000,请等待任务完成后再提交",
"data": null
}Recommended way to organize batch tasks:
- Submit one batch first, wait until the tasks reach the
completed/failedfinal states, and then submit the next batch; do not retry the same request repeatedly in a loop; - The more reference images and the higher the resolution in a single submission, the longer outbound bandwidth is occupied, so the number of concurrent submissions should be reduced accordingly;
- When you need to produce multiple videos at the same time, track progress by task ID and continue after the previous batch finishes, to avoid duplicate submissions and duplicate charges.
Billing and parameter validation
- Video tasks are settled based on actual usage when they complete: a successful creation only means the task has been accepted; no charge is deducted in advance at submission and no billing record is created. After the task completes, only one actual charge record appears in the bill.
- At submission, the platform verifies whether the account balance (or current API key quota) covers the estimated quota for this request. If not, it returns HTTP
403withinsufficient_user_quota, and the error message gives "estimated for this request …, currently available …"; top up the balance or adjust the parameters and resubmit. No task is created and no charge is incurred in this case. - The request body is validated before submission; missing content returns a readable message directly, so you do not need to rely on upstream errors to locate the problem:
| Message | Cause | Handling |
|---|---|---|
缺少提示词:请在 prompt 或 content 的 text 元素中提供文本描述 | No text description | Add a prompt, or add a type: "text" element to content |
content[0].role 不支持 "xxx",可用值:reference_image、first_frame、last_frame、reference_video、reference_audio | The reference asset role is written incorrectly | Change it to an allowed role according to the message |
content[0].image_url.url 不能为空 | The reference asset URL is empty | Fill in asset://<asset ID>, a publicly downloadable HTTPS URL, or data: inline data |
content[0] 参考素材不可用:地址需要是 https:// 公网地址、asset://<素材ID> 或 data: 内联数据 | The asset URL protocol is not supported | Change it to a platform asset ID, a direct HTTPS link, or data: inline data; do not use ftp://, file://, or internal network addresses |
content[0] 参考素材不可用:素材库中找不到素材 xxx | The asset:// asset does not exist or does not belong to the current account | Submit it in the asset library first and wait until its status becomes available, or verify the account |
duration 必须大于 0 | Invalid duration parameter | Change it to a duration supported by the model |
