AI Model APIs

Videos

Use the asynchronous video APIs for seedance and happyhorse: submit a task, save the task ID, poll for status, and store the output promptly after success.

Supported video series

SeriesModelBest atProtocol style
seedanceseedance-2-0, seedance-2-0-fast, seedance-2-0-miniMultimodal references (image + video + audio), audio-enabled video, video editing & extension, up to 4KMultimodal content array
happyhorsehappyhorse-1.1-t2v, happyhorse-1.1-i2v, happyhorse-1.1-r2v, happyhorse-1.0-video-editPhysically realistic, smooth motion; generation with multiple reference images; partial video replacement editinginput + parameters

Common conventions

Base URL https://api.tokgate.io
  • Auth: same as the other APIs — send the header Authorization: Bearer sk-***.
  • Async flow: submit the task → get the task ID → poll the status at a fixed interval → take the video address once succeeded → download and store it immediately.
  • Polling interval: video generation usually takes 1 ~ 5 minutes; poll about every 15 seconds, never below 5 seconds.
  • Do not resubmit: after a successful submission, save the task ID and poll. Resubmitting creates a new task and is billed again.
  • Output validity: video links from both series are kept for only 24 hours and cleared automatically after that.

Timeouts and long connectionsDo not wait for the result over a long-lived connection. Set the client HTTP timeout for the submit-request duration (a few seconds), and track generation progress via the polling API.

Limits follow upstream documentationThe size, dimension, count and duration limits on this page come from each upstream vendor's documentation and may change as they update it. For the current values, refer to each vendor's official documentation.


seedance series

The Volcano Engine Ark Doubao Seedance 2.0 series supports multimodal image, video, audio and text input, as well as video generation, editing and extension.

Supported models

Use one of the following model IDs in the model field.

Model IDPositioning
seedance-2-0Flagship; pursues the highest generation quality; the only one with 4K
seedance-2-0-fastFaster output, balancing quality and speed
seedance-2-0-miniCost-first, ideal for high-volume test shots

Public model IDsUse only the three public model IDs above in requests. Internal endpoint IDs and upstream-normalized names in responses are not request parameters. A successful response may show an upstream name in model; keep using the IDs above for later requests.

Capability matrix

CapabilityInput combinationDescription
Text-to-videoTextGenerates one video from a prompt only.
Image-to-videoFirst-frame image + text (optional)Generates forward from the given image as the first frame.
Image-to-video · first & last framesFirst-frame image + last-frame image + text (optional)Fills in the motion between the two images.
Multimodal reference-to-videoImages 0~9 + videos 0~3 + audio 0~3 + text (optional)Combines reference materials into a brand-new video. Audio alone is not allowed — at least one reference video or image is required.
Edit videoVideo + image + textE.g. "Replace the perfume in the gift box in the video with the face cream from image 1, keeping the camera work unchanged".
Extend videoVideo to extend + textAppends content after the existing video.
Audio-enabled videoWith generate_audio: true, automatically generates voice, sound effects and background music (mono) synchronized with the picture.
Web searchText-only inputtools: [{"type": "web_search"}] lets the model look up information before generating. Available only with text-only input.
Return last framereturn_last_frame: true — use the last frame of the previous clip as the first frame of the next to chain a continuous long video.

Restrictions on real-person portrait materialThe Seedance 2.0 series does not accept reference images or videos containing real human faces. Scenarios involving portraits must use the licensed-material solutions provided upstream (same-account output trust, preset virtual avatars, licensed real-person material); please confirm a viable path with us via the contact page first.

Submit a generation task

POST https://api.tokgate.io/api/v3/contents/generations/tasks

Request body fields

ParameterTypeRequiredDescription
modelstringRequiredtokgate.io model ID; see the model table above.
contentarray<object>RequiredArray of input materials; see "content elements" below.
resolutionstringOptionalResolution, default 720p. Options: 480p / 720p / 1080p / 4k. 1080p is not supported on fast and mini; 4k is supported only on seedance-2-0.
ratiostringOptionalAspect ratio, default adaptive. Options: 21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16 / adaptive.
durationintegerOptionalDuration in seconds; default 5, range 4 ~ 15; you can also pass -1 to let the model decide. The actual duration is the duration returned by the query API — duration directly affects billing.
generate_audiobooleanOptionalDefault true — output carries synchronized audio. Set false for a silent video. Put dialogue inside double quotes to improve audio quality.
output_formatstringOptionalOutput format; currently supported and defaulted to mp4.
watermarkbooleanOptionalDefault false. When true, an AI-generated watermark is shown in the lower-right corner.
return_last_framebooleanOptionalDefault false. When true, the query API returns the last-frame image of the video (same dimensions as the video, no watermark).
toolsarray<object>OptionalTool configuration; currently supports [{"type": "web_search"}]. Available only in text-only input scenarios.
callback_urlstringOptionalCallback URL (POST) invoked on task status changes. The callback body matches the query API response. Failed deliveries are retried 3 times.
execution_expires_afterintegerOptionalTask timeout threshold in seconds; default 172800 (48 hours), range 3600 ~ 259200. Timed-out tasks are marked expired.
priorityintegerOptionalQueue priority 0 ~ 9, default 0; larger values queue earlier. Equal priorities are first-in-first-out. It only affects queue order and does not interrupt running tasks.
safety_identifierstringOptionalUnique end-user identifier, up to 64 characters. Passing a hash of the user ID is recommended to avoid exposing personal data.

Fields not supported by the Seedance 2.0 seriesseed, frames, camera_fixed, service_tier (online inference only) and draft (draft mode) are not yet supported on the 2.0 series; they are ignored or rejected with an error.

content elements

typeStructureroleDescription
text{"type":"text","text":"..."}The prompt. You can reference the following materials as "image 1", "video 1", "audio 1" inside it.
image_url{"type":"image_url","image_url":{"url":"..."},"role":"reference_image"}reference_imageReference images, 0 ~ 9. Public URLs or Base64 data URIs are supported.
video_url{"type":"video_url","video_url":{"url":"..."},"role":"reference_video"}reference_videoReference videos, 0 ~ 3. Used for editing, extension or style reference.
audio_url{"type":"audio_url","audio_url":{"url":"..."},"role":"reference_audio"}reference_audioReference audio, 0 ~ 3. Cannot be the only material passed.

Output spec differences

Itemseedance-2-0seedance-2-0-fastseedance-2-0-mini
Resolution480p / 720p / 1080p / 4k (10-bit depth)480p / 720p480p / 720p
Aspect ratio21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16 / adaptive
Duration4 ~ 15 seconds (or -1 to let the model decide)
Output formatMP4 (4K is H.265-encoded)

4K playback compatibility4K videos use H.265 + 10-bit encoding, which a few browsers and players do not support. If playback misbehaves, switch to VLC, MPV, QuickTime Player or similar, or drop to 1080p.

Submit response

{
  "id": "cgt-2026xxxx-xxxx"
}

The returned id is the task ID used for later queries. Task records are kept for 7 days (from creation time) and cleared automatically after that.

Task ID and polling contractA successful POST returns a top-level id; use that same value as {id} in the GET path. Keep polling on queued / running; read content.video_url on succeeded; stop on the other terminal states. Do not switch to task_id, and the success status is not success.

Query task status

GET https://api.tokgate.io/api/v3/contents/generations/tasks/{id}

Set the path parameter id directly to the same-named id returned by the submit API.

{
  "id": "cgt-2026xxxx-xxxx",
  "model": "doubao-seedance-2-0-260128",
  "status": "succeeded",
  "content": {
    "video_url": "https://.../result.mp4"
  },
  "usage": {
    "completion_tokens": 108900,
    "total_tokens": 108900
  },
  "created_at": 1779348818,
  "updated_at": 1779348874,
  "resolution": "720p",
  "ratio": "16:9",
  "duration": 5,
  "framespersecond": 24,
  "generate_audio": true,
  "output_format": "mp4",
  "service_tier": "default",
  "execution_expires_after": 172800,
  "priority": 0
}
FieldDescription
modelThe upstream-normalized model name in the response, for result records only. Keep using the public model IDs above in later requests.
statusTask status; see the enum below.
content.video_urlVideo address, returned only when succeeded. Valid for 24 hours.
errorError details on failure; this field may be absent from a successful response.
resolution / ratio / duration / framespersecondThe actual generation parameters. With adaptive or duration: -1, read the values the model finally chose here.
usageToken usage of this task, for reconciliation.
created_at / updated_atCreation time and status update time (Unix seconds).
generate_audio / output_formatThe actual audio switch and output format. output_format is currently mp4, and content.video_url points to the downloadable MP4 file.
statusMeaningAction
queuedSubmitted, queuingKeep polling
runningGeneratingKeep polling
succeededSucceededTake content.video_url and store it immediately
failedFailedRead error to locate the cause, fix the prompt or materials, then retry
cancelledCancelled (only queued tasks can be cancelled)Resubmit if you need the result
expiredExceeded execution_expires_after without completing; terminatedResubmit; raise the timeout threshold if necessary

Complete examples

# Step 1: Submit the task
curl -X POST https://api.tokgate.io/api/v3/contents/generations/tasks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -d '{
    "model": "seedance-2-0",
    "content": [
      { "type": "text", "text": "A coastline in the early morning, waves lapping against the reefs, seagulls circling low, the camera pushing in from far to near" }
    ],
    "resolution": "720p",
    "ratio": "16:9",
    "duration": 5,
    "generate_audio": true,
    "output_format": "mp4",
    "watermark": false
  }'
# Response: { "id": "cgt-2026xxxx-xxxx" }

# Step 2: Poll the task status (recommended every 15 seconds)
curl https://api.tokgate.io/api/v3/contents/generations/tasks/cgt-2026xxxx-xxxx \
  -H "Authorization: Bearer sk-***"

# Step 3: Download content.video_url once status becomes succeeded
curl -o coastline.mp4 "https://.../result.mp4"
curl -X POST https://api.tokgate.io/api/v3/contents/generations/tasks \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -d '{
    "model": "seedance-2-0-fast",
    "content": [
      { "type": "text", "text": "Use image 1 as the first frame; the product rotates slowly to show details, soft studio lighting" },
      {
        "type": "image_url",
        "image_url": { "url": "https://your-cdn.example.com/product.jpg" },
        "role": "reference_image"
      }
    ],
    "resolution": "720p",
    "ratio": "adaptive",
    "duration": 5
  }'
{
  "model": "seedance-2-0",
  "content": [
    {
      "type": "text",
      "text": "A first-person-perspective fruit-tea commercial: the first frame is image 1 — a hand picks an apple covered in morning dew; then a quick cut to a shaker cup being shaken; the last frame freezes on image 2. Use the compositional rhythm of video 1 throughout, with audio 1 as the background music"
    },
    { "type": "image_url", "image_url": { "url": "https://your-cdn.example.com/pic1.jpg" }, "role": "reference_image" },
    { "type": "image_url", "image_url": { "url": "https://your-cdn.example.com/pic2.jpg" }, "role": "reference_image" },
    { "type": "video_url", "video_url": { "url": "https://your-cdn.example.com/ref.mp4" }, "role": "reference_video" },
    { "type": "audio_url", "audio_url": { "url": "https://your-cdn.example.com/bgm.mp3" }, "role": "reference_audio" }
  ],
  "generate_audio": true,
  "ratio": "16:9",
  "duration": 11,
  "watermark": false,
  "return_last_frame": true
}
{
  "model": "seedance-2-0",
  "content": [
    { "type": "text", "text": "Shoot a nature-documentary shot introducing the physical characteristics of the glass frog; it must match real biological traits" }
  ],
  "tools": [{ "type": "web_search" }],
  "ratio": "16:9",
  "duration": 11,
  "watermark": false
}

happyhorse series

The HappyHorse video generation series supports text-to-video, first-frame image-to-video, multi-image reference-to-video and video editing.

Supported models

CapabilityModel (model)InputKey parameter rules
Text-to-video (T2V)happyhorse-1.1-t2vPass only the required input.prompt; do not send input.mediaratio is supported; the verified combination on this page is 720P, 16:9 and 5 seconds
Image-to-video · first-frame based (I2V)happyhorse-1.1-i2vExactly one first_frame in input.media; prompt is optionalDo not pass ratio; the output aspect ratio follows the first frame
Reference-to-video (R2V)happyhorse-1.1-r2v1 ~ 9 reference_image items in input.media + required promptReference images in the prompt as [Image N] in array order
Video editinghappyhorse-1.0-video-editExactly one video in input.media, plus 0 ~ 5 reference_image items; prompt is requiredThe minimal request needs only resolution; do not pass ratio or duration

Use the complete model IDUse only the four complete IDs in the table above. Do not construct model names from version numbers. Before going live, you can call GET /v1/models to confirm that these models are visible to the current API key.

Submit a generation task

POST https://api.tokgate.io/api/v1/services/aigc/video-generation/video-synthesis

Request headers

HeaderRequiredDescription
AuthorizationRequiredBearer sk-***
Content-TypeRequiredapplication/json
X-DashScope-AsyncRequiredFixed at enable. Missing this header returns an error (saying synchronous calls are not supported).

Request body fields

ParameterTypeRequiredDescription
modelstringRequiredModel name; see the list above.
input.promptstringDepends on capabilityThe prompt. Required for T2V / R2V / video editing; optional for I2V. The provider applies character-counting limits under its own rules (up to 5,000 or 2,500 characters, depending on how the input is counted); overflow is truncated automatically.
input.mediaarray<object>Depends on capabilityMaterial list; elements contain type and url. Not needed for T2V.
input.media[].typestringRequiredfirst_frame (I2V first frame, exactly 1) / reference_image (reference image) / video (video to edit, exactly 1).
input.media[].urlstringRequiredMaterial address. Images support public URLs or Base64 (data:{MIME};base64,{data}); videos must be publicly accessible URLs.
parameters.resolutionstringOptionalResolution tier 480P / 720P / 1080P, default 1080P. Video editing supports only 720P / 1080P. Note the tier uses an uppercase P.
parameters.ratiostringOptionalUsed only by T2V / R2V. Default: 16:9. Options: 16:9 / 9:16 / 1:1 / 4:3 / 3:4 / 4:5 / 5:4 / 9:21 / 21:9. Do not send it for I2V or video editing: I2V follows the first frame, while video editing follows the input video.
parameters.durationintegerOptionalThe verified T2V / I2V / R2V requests on this page all use 5 seconds. I2V / R2V accept integers from 3 to 15 and default to 5. Video editing does not support this parameter; its output follows the input video and is capped at 15 seconds.
parameters.watermarkbooleanOptionalDefault true — adds a fixed "Happy Horse" watermark in the lower-right corner. You must explicitly pass false if you do not want a watermark.
parameters.seedintegerOptionalRandom seed, [0, 2147483647]. Fixing it makes results more reproducible, though the probabilistic model does not guarantee identical output.
parameters.audio_settingstringOptionalVideo editing only. auto (default, model-controlled) or origin (keeps the original sound of the input video).

The model must match the input structureT2V sends only input.prompt; I2V, R2V and video editing must send input.media as shown above. Field required: input.media usually means the selected model and request-body shape do not match. Do not work around it by adding irrelevant media to T2V.

Watermark on by defaultThe watermark of happyhorse defaults to true, the opposite of seedance (default false). For commercial use, explicitly pass false.

Material limits

MaterialLimits
First-frame image (first_frame)Formats JPEG / JPG / PNG / WEBP; both width and height at least 300 px; aspect ratio 1:2.5 ~ 2.5:1; up to 20 MB; exactly 1 image.
Reference images (reference_image for R2V)1 ~ 9 images; same formats as above; short side at least 400 px — clear images of 720P or better recommended; up to 20 MB. Avoid images that are too small, blurry or over-compressed.
Reference images (reference_image for video editing)0 ~ 5 images; both width and height at least 300 px; aspect ratio 1:2.5 ~ 2.5:1; up to 20 MB.
Video to edit (video)Formats MP4 / MOV (H.264 recommended); duration 3 ~ 60 seconds; long side up to 4096 px, short side at least 360 px; aspect ratio 1:2.5 ~ 2.5:1; up to 100 MB; frame rate above 8 fps; must be a publicly accessible URL.

Output duration of video editingOutput is 3 ~ 15 seconds. When the input video is no longer than 15 seconds, the output duration matches the input; beyond 15 seconds, the system automatically takes the first 15 seconds, so the maximum output is 15 seconds.

Reference syntax for R2V

For reference-to-video, use [Image 1], [Image 2] in the prompt to refer to the images at the corresponding positions in the media array (order matches the array), and clearly name the specific object in each reference image. Example: "The woman in the red qipao from [Image 1] gently raises her hand to unfold the folding fan from [Image 2]".

Submit response

{
  "output": {
    "task_status": "PENDING",
    "task_id": "0385dc79-5ff8-4d82-bcb6-xxxxxx"
  },
  "request_id": "4909100c-7b5a-9f92-bfe5-xxxxxx"
}

Save output.task_idqueryable for 24 hours. Do not create the task again; just poll directly.

Query task status

GET https://api.tokgate.io/api/v1/tasks/{task_id}
{
  "request_id": "99243b47-ec5f-9413-9993-xxxxxx",
  "output": {
    "task_id": "4673458e-28be-4a05-bf2a-xxxxxx",
    "task_status": "SUCCEEDED",
    "submit_time": "2026-04-20 17:55:17.075",
    "scheduled_time": "2026-04-20 17:55:17.129",
    "end_time": "2026-04-20 17:56:36.658",
    "orig_prompt": "A miniature city built from cardboard and bottle caps comes alive at night",
    "video_url": "https://.../result.mp4?Expires=..."
  },
  "usage": {
    "duration": 5,
    "input_video_duration": 0,
    "output_video_duration": 5,
    "video_count": 1,
    "SR": 720,
    "ratio": "16:9"
  }
}
{
  "request_id": "e5d70b02-ebd3-98ce-9fe8-xxxxxx",
  "output": {
    "task_id": "86ecf553-d340-4e21-af6e-xxxxxx",
    "task_status": "FAILED",
    "code": "InvalidParameter",
    "message": "The parameter is invalid."
  }
}
{
  "request_id": "a4de7c32-7057-9f82-8581-xxxxxx",
  "output": {
    "task_id": "502a00b1-19d9-4839-a82f-xxxxxx",
    "task_status": "UNKNOWN"
  }
}
FieldDescription
output.task_statusTask status; see the enum below.
output.video_urlVideo address, returned only on SUCCEEDED. Format MP4 (H.264), valid for 24 hours.
output.orig_promptThe original input prompt.
output.submit_time / scheduled_time / end_timeSubmission / execution-start / completion time, in YYYY-MM-DD HH:mm:ss.SSS format.
usage.durationTotal billed video duration (seconds). Video editing is generally billed using the combined input and output video durations; use the value returned by the API as the source of truth.
usage.input_video_duration / output_video_durationInput / output video duration (seconds).
usage.SR / usage.ratioThe actual output resolution tier and aspect ratio.
usage.video_countNumber of output videos, fixed at 1.
request_idUnique request identifier; provide it when troubleshooting.
task_statusMeaningAction
PENDINGQueuingKeep polling
RUNNINGProcessingKeep polling
SUCCEEDEDSucceededTake video_url and store it immediately
FAILEDFailedRead code / message to locate the cause
CANCELEDCancelledResubmit if you need the result
UNKNOWNThe task does not exist, or the task_id has passed its 24-hour validityCheck the task_id; if expired, the only option is to resubmit

Keep polling while output.task_status is PENDING or RUNNING. SUCCEEDED, FAILED, CANCELED and UNKNOWN are all terminal states. Even when the query returns HTTP 200, always inspect output.task_status. The default query limit is 20 RPS; polling every 15 seconds is recommended.

Complete examples

# Step 1: Create the task only once
curl -X POST https://api.tokgate.io/api/v1/services/aigc/video-generation/video-synthesis \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -H "X-DashScope-Async: enable" \
  -d '{
    "model": "happyhorse-1.1-t2v",
    "input": {
      "prompt": "A miniature city built from cardboard and bottle caps comes alive at night. A cardboard train slowly passes by, with small lights illuminating the way."
    },
    "parameters": {
      "resolution": "720P",
      "ratio": "16:9",
      "duration": 5
    }
  }'
# Save output.task_id from the response; do not POST again

# Step 2: Query the same task_id every 15 seconds
curl https://api.tokgate.io/api/v1/tasks/0385dc79-5ff8-4d82-bcb6-xxxxxx \
  -H "Authorization: Bearer sk-***"

# Step 3: Download output.video_url only when output.task_status is SUCCEEDED
curl -o happyhorse-result.mp4 "https://.../result.mp4?Expires=..."
curl -X POST https://api.tokgate.io/api/v1/services/aigc/video-generation/video-synthesis \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -H "X-DashScope-Async: enable" \
  -d '{
    "model": "happyhorse-1.1-i2v",
    "input": {
      "prompt": "A cat running across grass as sunlight filters through the blades",
      "media": [
        { "type": "first_frame", "url": "https://your-cdn.example.com/cat.png" }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "duration": 5
    }
  }'
curl -X POST https://api.tokgate.io/api/v1/services/aigc/video-generation/video-synthesis \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -H "X-DashScope-Async: enable" \
  -d '{
    "model": "happyhorse-1.1-r2v",
    "input": {
      "prompt": "The woman in the red qipao from [Image 1] gently raises her hand to unfold the fan from [Image 2], ending with a close-up of her face",
      "media": [
        { "type": "reference_image", "url": "https://your-cdn.example.com/girl.jpg" },
        { "type": "reference_image", "url": "https://your-cdn.example.com/fan.jpg" }
      ]
    },
    "parameters": {
      "resolution": "720P",
      "ratio": "16:9",
      "duration": 5
    }
  }'
curl -X POST https://api.tokgate.io/api/v1/services/aigc/video-generation/video-synthesis \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-***" \
  -H "X-DashScope-Async: enable" \
  -d '{
    "model": "happyhorse-1.0-video-edit",
    "input": {
      "prompt": "Put the character in the video into the striped sweater from the image; keep everything else unchanged",
      "media": [
        { "type": "video", "url": "https://your-cdn.example.com/source.mp4" },
        { "type": "reference_image", "url": "https://your-cdn.example.com/sweater.webp" }
      ]
    },
    "parameters": {
      "resolution": "720P"
    }
  }'

Complete Python flow (create only once)

First put the key in the TOKGATE_API_KEY environment variable. The script below POSTs exactly once, then keeps querying the same task_id. It stops on any terminal state and, on success, verifies the MP4 container header before saving the file. To call another HappyHorse model, replace only payload with the matching request body above.

import json
import os
import time
from pathlib import Path
from urllib.request import Request, urlopen

base_url = "https://api.tokgate.io"
api_key = os.environ["TOKGATE_API_KEY"]

payload = {
    "model": "happyhorse-1.1-t2v",
    "input": {
        "prompt": "A miniature city built from cardboard and bottle caps comes alive at night"
    },
    "parameters": {
        "resolution": "720P",
        "ratio": "16:9",
        "duration": 5
    }
}

# Create the task only once
create_request = Request(
    f"{base_url}/api/v1/services/aigc/video-generation/video-synthesis",
    data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "X-DashScope-Async": "enable",
    },
    method="POST",
)
with urlopen(create_request, timeout=30) as response:
    created = json.load(response)

task_id = created["output"]["task_id"]
print(f"task_id={task_id}")

# Wait up to 30 minutes; continue on PENDING / RUNNING and stop on any terminal state
terminal_statuses = {"SUCCEEDED", "FAILED", "CANCELED", "UNKNOWN"}
for _ in range(120):
    time.sleep(15)
    query_request = Request(
        f"{base_url}/api/v1/tasks/{task_id}",
        headers={"Authorization": f"Bearer {api_key}"},
    )
    with urlopen(query_request, timeout=30) as response:
        result = json.load(response)

    output = result["output"]
    status = output["task_status"]
    print(f"task_status={status}")
    if status in terminal_statuses:
        break
else:
    raise TimeoutError("The task did not reach a terminal state within 30 minutes")

if status != "SUCCEEDED":
    raise RuntimeError(
        "{}: {} {}".format(status, output.get("code", ""), output.get("message", ""))
    )

# Download immediately after success; the result URL is retained for only 24 hours
with urlopen(output["video_url"], timeout=180) as response:
    video = response.read()
if len(video) < 12 or video[4:8] != b"ftyp":
    raise RuntimeError("The response is not a valid MP4 file")

Path("happyhorse-result.mp4").write_bytes(video)
print(f"saved happyhorse-result.mp4 ({len(video)} bytes)")

Series comparison

Itemseedancehappyhorse
Submit / query pathsPOST /api/v3/contents/generations/tasks
GET /api/v3/contents/generations/tasks/{id}
POST /api/v1/services/aigc/video-generation/video-synthesis
GET /api/v1/tasks/{task_id}
Async request headerNo extra header neededRequired X-DashScope-Async: enable
Material fieldcontent[] (type + role)input.media[] (type + url)
Control-parameter locationTop level of the request bodyInside the parameters object
Task ID fieldidoutput.task_id
Status field and valuesstatus: lowercase (succeeded…)output.task_status: uppercase (SUCCEEDED…)
Video address fieldcontent.video_urloutput.video_url
Resolution notationLowercase 720p, default 720pUppercase 720P, default 1080P
Watermark defaultfalsetrue
Task-record retention7 days24 hours
Audio generationgenerate_audio (on by default)Video editing can use audio_setting to keep the original sound

Error handling

  • 4xx at submission: usually an illegal parameter combination (e.g. passing 1080p to fast / mini, multiple first frames to happyhorse-1.1-i2v, or duration to video editing). Check against the relevant parameter table and retry. For status-code semantics see Error codes.
  • Missing async header: calling happyhorse without X-DashScope-Async: enable fails immediately with an error saying synchronous calls are not supported.
  • Task failure: common causes are content failing moderation, materials violating the limits, upstream generation failure or timeout. Fix the prompt, replace the materials, or lower the resolution and duration, then retry.
  • Material inaccessible: when passing URLs, make sure they are publicly reachable, not hotlink-protected and require no auth; the video to edit does not support Base64 — it must be an accessible URL.
  • Output expiry: video links expire after 24 hours. In production, always download and re-store them in your own object storage immediately after the task succeeds.
  • A missing task may still return HTTP 200: clients must inspect status / output.task_status and error fields instead of treating the HTTP status alone as success.