APIAdvanced usersUpdated

Video Generation API

The Video Generation API creates asynchronous video jobs. A create request returns HTTP 202 with a job ID; use that ID to poll until the job reaches succeeded or failed, then download the completed MP4.

The examples use https://api.icodeeasy.cc as the base URL. Every endpoint call documented below requires your API key; a signed result-file URL returned after success is the only exception:

Authorization: Bearer <your API key>

Endpoints

PurposeMethod and route
Create a video jobPOST /v1/videos/generations
Get a jobGET /v1/videos/tasks/{id}
Download completed contentGET /v1/videos/tasks/{id}/content
Delete a completed or failed jobDELETE /v1/videos/tasks/{id}

Five-minute quickstart

1. Create a job

curl -X POST https://api.icodeeasy.cc/v1/videos/generations \
  -H 'Authorization: Bearer <your API key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "doubao-seedance-2.5",
    "prompt": "a futuristic city street in the rain, slow forward camera movement, neon reflections on wet pavement",
    "resolution": "480p",
    "ratio": "9:16",
    "duration": 4,
    "generate_audio": true
  }'

Creation returns HTTP 202:

{
  "id": "vid_1785398400000000000",
  "task_id": "vid_1785398400000000000",
  "object": "video.generation.job",
  "status": "queued",
  "model": "doubao-seedance-2.5",
  "created_at": "2026-07-30T08:00:00Z",
  "updated_at": "2026-07-30T08:00:00Z"
}

Use task_id as the recommended job identifier for polling, downloading, and deletion; id remains available with the same value for compatibility. A 202 response means the job was accepted, not that the video is already complete.

2. Poll the job

Copy the task_id from the create response into TASK_ID:

TASK_ID='vid_1785398400000000000'
curl "https://api.icodeeasy.cc/v1/videos/tasks/${TASK_ID}" \
  -H 'Authorization: Bearer <your API key>'

Poll about once every 5 seconds. Do not create another job while the current one is queued or running.

{
  "id": "vid_1785398400000000000",
  "object": "video.generation.job",
  "status": "running",
  "model": "doubao-seedance-2.0",
  "created_at": "2026-07-30T08:00:00Z",
  "updated_at": "2026-07-30T08:00:20Z",
  "progress": 42
}

progress is best-effort and may be absent. Treat status, not progress, as authoritative.

3. Download the video

After status becomes succeeded, the response includes url and the final cost_rmb:

{
  "id": "vid_1785398400000000000",
  "object": "video.generation.job",
  "status": "succeeded",
  "model": "doubao-seedance-2.0",
  "created_at": "2026-07-30T08:00:00Z",
  "updated_at": "2026-07-30T08:01:18Z",
  "progress": 100,
  "url": "/v1/videos/tasks/vid_1785398400000000000/content",
  "cost_rmb": 0.528
}

Download through the canonical authenticated content route and follow redirects:

TASK_ID='vid_1785398400000000000'
curl -L "https://api.icodeeasy.cc/v1/videos/tasks/${TASK_ID}/content" \
  -H 'Authorization: Bearer <your API key>' \
  -o result.mp4

The content route supports HTTP Range and common conditional download headers. Requesting content before success returns 409 video_not_ready.


Job lifecycle and safe retries

StatusMeaningClient action
queuedAccepted and waiting to startKeep polling the same job
runningThe video is being generatedKeep polling the same job
succeededTerminal success; content is readyDownload and store the result
failedTerminal failureRead error.code; create a new job only if you intentionally try again

Retry rules:

  • After receiving HTTP 202, keep polling the returned task_id. Repeating the create request may create another job.
  • Polling and download GET requests are safe to retry.
  • If creation returns submission_unknown, do not submit another request. The job may already have been accepted; contact support with the request time, model, and prompt summary.
  • After a confirmed terminal failed job, create a new job only when you intentionally want to generate another video.

Webhooks and callback_url are not supported. Poll the job endpoint instead.


Create request reference

FieldTypeRequiredDescription
modelstringYesCanonical model ID. There is no default; missing or blank values return 400 invalid_request.
promptstringText required for standard modelsPut all text instructions here. For Motion Control it is optional when both reference assets are supplied.
contentarrayWhen using referencesReference-media list containing public HTTPS image/video URL items only.
resolutionstringNoOutput tier. The default and allowed values depend on the model. Not accepted by Motion Control.
ratiostringNoOutput aspect ratio. aspect_ratio is accepted as an alias. Not accepted by Motion Control.
durationintegerNoRequested seconds. The default and allowed values depend on the model. Not accepted by Motion Control.
generate_audiobooleanNoGenerate audio when supported. Defaults are listed in the model table. Not accepted by Motion Control.
motion_modestringMotion Control onlystd or pro; defaults to std.
character_orientationstringMotion Control onlyimage or video; defaults to image. Controls the reference-video duration limit.
keep_original_soundbooleanMotion Control onlyKeep reference-video sound; defaults to true.

Put all text instructions in prompt. Use content only for reference images and videos.

Reference-media list (content)

content is a list because one job may need a first and last frame, several unordered reference images, or one image plus one video for Motion Control. Put one HTTPS URL string directly in each item's image_url or video_url field.

[
  { "type": "image_url", "image_url": "https://cdn.example.com/first.png", "role": "first_frame" },
  { "type": "image_url", "image_url": "https://cdn.example.com/last.png", "role": "last_frame" }
]
  • Image types: image_url or input_image.
  • Video types: video_url or input_video.
  • Frame roles: first_frame and last_frame. A last frame always requires a first frame.
  • Motion roles: one reference_image and one reference_video.
  • Grok reference images have no role; reference_image is also accepted.
  • Reference audio is not currently supported.
  • Media must use a publicly reachable HTTPS URL that remains valid while the job reads it.
  • Put images in image_url and videos in video_url.

Complete first-frame and last-frame request

Host both images at publicly readable HTTPS URLs, then put the URLs directly in content:

curl -X POST https://api.icodeeasy.cc/v1/videos/generations \
  -H 'Authorization: Bearer <your API key>' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "doubao-seedance-2.0",
    "prompt": "the camera moves smoothly from the opening frame to the ending frame",
    "content": [
      {"type":"image_url","image_url":"https://cdn.example.com/first.png","role":"first_frame"},
      {"type":"image_url","image_url":"https://cdn.example.com/last.png","role":"last_frame"}
    ],
    "resolution": "480p",
    "ratio": "9:16",
    "duration": 4,
    "generate_audio": true
  }'

You may send only the first frame. You cannot send a last frame unless the same request also contains a first frame.


Model cookbook

Seedance: text, first frame, and last frame

Seedance 2.5, Seedance 2.0 Standard, Fast, Mini, and Seedance 1.5 Pro support text-to-video and first/last-frame generation. Reference images require explicit frame roles. Seedance 2.5 is listed first in this family.

{
  "model": "doubao-seedance-2.5",
  "prompt": "the camera circles a glass sculpture as morning light changes",
  "content": [
    { "type": "image_url", "image_url": "https://cdn.example.com/seedance-first.png", "role": "first_frame" },
    { "type": "image_url", "image_url": "https://cdn.example.com/seedance-last.png", "role": "last_frame" }
  ],
  "resolution": "720p",
  "ratio": "16:9",
  "duration": 6,
  "generate_audio": true
}

Seedance 2.5 defaults to 480p, 9:16, 4 seconds, and generated audio enabled. With a first frame or first-plus-last frames, its ratio is normalized to adaptive.

MiniMax H3: text, first frame, and last frame

MiniMax-H3 supports text-to-video and first/last-frame generation through the same public request. It accepts 768P or 2K, durations from 4 to 15 seconds, and the 21:9, 16:9, 4:3, 1:1, 3:4, and 9:16 ratios. Its defaults are 768P, 9:16, and 5 seconds. Do not send generate_audio: this public contract has no generated-audio request toggle for H3.

Kling: frame-guided generation

{
  "model": "kling-v3",
  "prompt": "a train enters the station through light fog",
  "content": [
    { "type": "image_url", "image_url": "https://cdn.example.com/kling-first.png", "role": "first_frame" },
    { "type": "image_url", "image_url": "https://cdn.example.com/kling-last.png", "role": "last_frame" }
  ],
  "resolution": "1080p",
  "ratio": "16:9",
  "duration": 5,
  "generate_audio": true
}

Important Kling differences:

  • kling-v2-6: a last frame requires 1080p; generated audio is available only at 1080p and cannot be combined with a last frame.
  • kling-3.0-turbo: first frame only; no generated audio.
  • kling-v3 and kling-v3-omni: first/last frames and generated audio are supported.
  • kling-v3-omni also accepts up to two roleless reference images, but do not mix roleless and frame-role images in one request.
  • kling-video-o1: first/last frames; no generated audio.

Grok: unordered reference images

Grok accepts up to seven reference-image URLs. Do not assign first_frame or last_frame roles.

{
  "model": "grok-imagine-1.5-video",
  "prompt": "clouds roll over a canyon while the camera rises",
  "content": [
    { "type": "image_url", "image_url": "https://cdn.example.com/grok-reference.png" }
  ],
  "resolution": "480p",
  "ratio": "16:9",
  "duration": 6
}

Grok defaults to 480p, 9:16, and 6 seconds. Generated audio is not supported.

Kling Motion Control

Provide one public HTTPS image and one public HTTPS MP4 video:

{
  "model": "kling-v3-motion-control",
  "prompt": "preserve the character identity and follow the reference motion",
  "content": [
    { "type": "image_url", "image_url": "https://cdn.example.com/character.png", "role": "reference_image" },
    { "type": "video_url", "video_url": "https://cdn.example.com/motion.mp4", "role": "reference_video" }
  ],
  "motion_mode": "std",
  "character_orientation": "image",
  "keep_original_sound": true
}
  • character_orientation: "image": reference video must be 3–10 seconds.
  • character_orientation: "video": reference video must be 3–30 seconds.
  • Do not send resolution, ratio, duration, or generate_audio with a Motion Control model.

Model capability table

Canonical model IDResolution / modeDurationRatioReferencesAudio default
doubao-seedance-2.5480p, 720p4–30 s16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptiveFirst + last frame; frame-guided ratio normalizes to adaptiveOn
doubao-seedance-2.0480p, 720p, 1080p, 4K4–15 s16:9, 9:16, 1:1, 4:3, 3:4, 21:9, adaptiveFirst + last frameOn
doubao-seedance-2.0-fast480p, 720p4–15 sSame as Seedance 2.0First + last frameOn
doubao-seedance-2.0-mini480p, 720p4–15 sSame as Seedance 2.0First + last frameOn
doubao-seedance-1-5-pro480p, 720p, 1080p4–12 s16:9, 9:16, 1:1, 4:3, 3:4, 21:9First + last frameOn
MiniMax-H3768P, 2K4–15 s21:9, 16:9, 4:3, 1:1, 3:4, 9:16First + last frameNo public generated-audio toggle
kling-v2-6720p, 1080p5 or 10 s16:9, 9:16, 1:1First + conditional last frameOff
kling-3.0-turbo720p, 1080p3–15 s16:9, 9:16, 1:1First frame onlyUnsupported
kling-v3720p, 1080p, 4K3–15 s16:9, 9:16, 1:1First + last frameOn
kling-v3-omni720p, 1080p, 4K3–15 s16:9, 9:16, 1:1First + last or up to 2 roleless imagesOn
kling-video-o1720p, 1080p5 or 10 s16:9, 9:16, 1:1First + last frameUnsupported
kling-v2-6-motion-controlstd, proReference video1 image + 1 videoOriginal sound on
kling-v3-motion-controlstd, proReference video1 image + 1 videoOriginal sound on
grok-imagine-1.5-video480p, 720p6–30 s16:9, 9:16, 1:1, 3:2, 2:3Up to 7 roleless imagesUnsupported

For standard models, omitted option values use each model's defaults shown above. model itself is always required. The service validates combinations before starting the job.


Response and download behavior

All job responses use this shape:

FieldMeaning
idOwner-scoped job ID used for polling, content, deletion, and support
objectAlways video.generation.job
statusqueued, running, succeeded, or failed
modelCanonical model ID after alias normalization
created_at, updated_atUTC RFC 3339 timestamps
progressBest-effort generation progress, omitted when unavailable
urlPresent only after success; may be a relay content path or a signed relay file path
cost_rmbFinal task charge, present after successful settlement
error.codeStable failure category on a failed job

Prefer GET /v1/videos/tasks/{id}/content instead of storing assumptions about the returned URL shape. Use -L or enable redirects in your HTTP client. The authenticated content endpoint can return 200, 206 Partial Content, or a redirect to relay-managed storage.

A signed relay file URL can be opened without an API key; possession of the complete URL grants access to that video. Do not expose it in public logs, pages, or client-side analytics.

Deleting a safe terminal job returns HTTP 204 and may also remove its relay-managed video file. Download and store any result you need before deleting the job. Deletion is rejected with 409 video_delete_unsafe while a job is running or billing is unsettled. Deleting a local job record does not cancel generation that has already started.


Error handling

HTTP errors use:

{
  "error": {
    "type": "invalid_request",
    "message": "model is not supported"
  }
}
HTTPError typeMeaning / action
400invalid_requestInvalid model, field, media URL, role, duration, ratio, or model combination; fix the request
401unauthorizedAPI key is missing, invalid, or disabled
402insufficient_balanceBalance cannot cover the requested job; generation is not started
404not_foundThe job does not exist or belongs to another account
409video_not_readyContent was requested before terminal success
409video_delete_unsafeThe job is not safe to delete yet
413request_too_largeJSON create body exceeds its limit
502upstream_errorVideo generation or result download failed
503video_service_unavailable, upstream_quota_exceeded, video_price_unavailableVideo service capacity or current public pricing is temporarily unavailable
503submission_unknownJob acceptance is uncertain; do not submit a duplicate

A failed job response may look like:

{
  "id": "vid_1785398400000000000",
  "object": "video.generation.job",
  "status": "failed",
  "model": "doubao-seedance-2.0",
  "error": { "code": "generation_failed" }
}

Billing

Video generation uses account balance, not monthly quota.

task price = displayed RMB price per second for the selected model/specification × billable seconds

Check the current per-second prices on the Pricing page. Resolution, generated audio, or Motion Control mode may select a different displayed per-second row. For standard models, billable seconds are the requested duration; for Motion Control, they are the detected reference-video duration rounded up to a whole second.

The balance must be able to cover the job when it is created. Insufficient balance returns 402 before generation starts. The successful job's cost_rmb is the authoritative final charge. A definitely failed job is not charged.