Docs · Video models

Video Model API Platform Integration Guide

Integrate the video generation API into your own product or tool, for your users or team.

Developers already using the Volcano Ark native request format can use this platform's Ark-compatible endpoint directly (POST /videos/api/v3/contents/generations/tasks); see the differences from Ark native below — 5.9 Ark-compatible endpoint: differences from Ark native.

01Get your first video running in 3 minutes

Want to try it before you write any code? Use your API key in the video workbench to generate a video directly — no code required.

The minimal loop is three steps: submit → poll → download.

⚠️ Generation is asynchronous. Turnaround time varies with the model, duration, and scene complexity. Submission returns a job ID, not a video — poll the response's poll_url to get the result. Do not wait synchronously.

Step 0: create an API key

Create one on the console's Tokens page. The group only selects the price tier for text models; video models do not go through it, so leave it on the default auto. Every key can call all of the video models listed here. Pricing is calculated per your account's discount, and the actual amount is whatever /estimate returns for your request — the same model can show a different amount for different customers.

🔴 The IP allow-list on the key is enforced on video endpoints: requests from unlisted IPs return 403 ip_not_allowed. Leave it empty if your egress IP is not fixed. The separate "allowed models" list does not apply to video endpoints.

Step 1: submit a generation job
curl example · Submit a job
curl https://tryaiapi.com/videos/v1/videos/generations \ -H "Authorization: Bearer <your API key>" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedance-2.0", "prompt": "A sunrise over the ocean, camera slowly pushing in", "resolution": "720p", "duration": 5, "aspect_ratio": "16:9" }'

The response's status starts as queued (that state can be very brief — seeing running already in the submit response is normal), then moves to running; poll_url is the address you poll next:

Response example · Submission accepted
{ "job_id": "...", "status": "queued", "poll_url": "https://tryaiapi.com/videos/v1/videos/jobs/<job_id>", "created_at": "2026-08-22T10:03:11Z" }
(Optional) get an estimate before you submit

The request fields are identical to submission — just swap the path for /generations/estimate. It does not create a job, charge you, or trigger generation.

Response example · Estimate (doubao-seedance-2.0 · 720p · 5s — illustrative only; the actual amount is whatever /estimate returns for your request)
{ "model": "doubao-seedance-2.0", "estimated_cost": 0.8132, "estimated_cost_cny": 5.69, "fx_cny_per_usd": 7, "currency": "USD", "basis": "pre_hold", "final_cost_may_adjust": true }
Step 2: poll job status

Take the poll_url from the previous response and request it as-is:

curl example · Poll
curl <poll_url> \ -H "Authorization: Bearer <your API key>"
Step 3: download the result

Once status becomes completed, video_url is a direct, downloadable link to the video:

Response example · Completed, ready to download
{ "job_id": "...", "status": "completed", "model": "doubao-seedance-2.0", "video_url": "<the generation engine's own direct link>", "platform_video_url": null, "expires_at": "2026-08-23T10:05:40Z", "cost_final": 0.81, "duration_ms": 118342, "metadata": { "duration": 5, "resolution": "720p" } }

⚠️ video_url expires — download and save it promptly; do not rely on it staying reachable long-term. The actual expiry is whatever expires_at in the same response says (it varies by which upstream channel the model runs on — most are about 24 hours; don't hard-code that number).

Currently available video models
ModelCall name (use this in the model field)Supported resolutions
Seedance 2.0doubao-seedance-2.0480p / 720p / 1080p / 4k
Seedance 2.0 Fastdoubao-seedance-2.0-fast480p / 720p
Seedance 2.5doubao-seedance-2.5480p / 720p / 1080p
MiniMax H3MiniMax-H3768p / 2k (lowercase required; 768P / 2K are rejected)

The table above lists the currently available video models; for the complete, real-time list see the model market. Video models are not returned by the text-gateway GET /v1/models endpoint.

Last updated: 2026-09-27

02Reference images

🔴 When submitting reference images via the API, provide publicly accessible URLs in image_urls.

For images containing real people: first create an asset using that URL, then reference it in your generation request as asset://<asset_id> — see "Asset library: the real-person channel" below.

(This platform also offers a separate upload endpoint, used by the video workbench when a user selects a local image; a platform integration built on the API does not need it — see "API reference → 5.8".)

⚠️ Pixel limit: this platform's upload pre-check rejects any image whose width × height exceeds 36 million pixels (this value is the real rejection threshold observed in production from the current supply channel on 2026-08-18; other supply channels' generation-time upstream limit may differ — the error returned at generation time is authoritative). A typical phone photo at 6048×8064 (about 49 million pixels) exceeds it. An oversized image makes the job fail, and the hold is refunded automatically.

Base64: as in the engine's official API, images / audio can be sent inline as data:image/<format>;base64,… / data:audio/<format>;base64,… (lowercase format; images jpeg, png, webp, bmp, tiff, gif, heic, heif, each under 30 MB; audio wav, mp3, each at most 15 MB; whole request body at most 64 MB). Job details show a link generated by the platform. A wrong format or size returns invalid_inline_media with no charge. Reference videos do not accept Base64. For large files, uploading first (or using the asset library) and passing a link is recommended.

⚠️ Per-request reference limits depend on the model: Seedance 2.0 series — up to 9 reference images, 3 reference videos and 3 reference audio clips; Seedance 2.5 — up to 30 reference images, 10 reference videos and 10 reference audio clips.

Last updated: 2026-09-27

03Asset library: the real-person channel

Why it exists

Currently applies to Seedance 2.0 and Seedance 2.5: these two models apply content moderation to reference images that contain real people — submitting a raw image link for one will be rejected. The asset library is the channel for referencing real people: register the likeness as an asset first, then reference it in your generation request. Whether other models apply the same moderation depends on the actual error code your generation request gets back (a model that doesn't trigger this check will not return input_image_real_person).

When you must use it

Whenever a Seedance 2.0 or Seedance 2.5 reference image contains a real human face. Reference assets containing real faces must be registered through the asset library; direct image URLs with faces are rejected by content moderation.

Three steps
  • Get a public image or video URL (your own link, or one from the upload endpoint)
  • Call the create-asset endpoint with that link and a name (add "kind": "video" for a video asset, "kind": "audio" for an audio asset) → get back an asset ID — video and audio assets accept public direct-download links only; there is no upload endpoint for them. Whether video/audio kinds are supported depends on the current asset-library channel: unsupported kinds return asset_kind_unsupported (400, no charge) — in that case pass a public direct link in the generation request instead of going through the asset library
  • Put asset://<asset_id> in the generation request's image_urls (or video_urls for a video asset)

⚠️ After creating an asset there is a brief processing window (usually under ten seconds) before it can be used for generation. Take the id from the create response and query that one asset by id (GET /videos/v1/videos/assets/<id>), polling until status is Active before submitting a generation request, rather than guessing a fixed wait time.

Recommended flow (when using several images at once)
  • Register all the images together (one create call each; no need to wait for the previous one to become ready) and keep each id
  • Poll each one by id every 2–3 seconds — the address is:
    GET https://tryaiapi.com/videos/v1/videos/assets/<id> (curl example below)
  • status is Active → that image is ready to submit
  • Failed → register a different image, do not retry the same one
  • Put an overall cap of 120 seconds on the whole batch and treat anything beyond it as failed. Most are ready within seconds and a few take longer, so within those 120 seconds, don't mark one as failed just because it is slow

🔴 The poll exit condition must cover both terminal states: Active (processing finished — ready to submit) and Failed (processing failed; change the image).

Single-asset endpoint: GET /videos/v1/videos/assets/<id>
curl example · Query one asset by id
BASE="https://tryaiapi.com" curl "$BASE/videos/v1/videos/assets/<id>" \ -H "Authorization: Bearer <your API Key>"
Response example (ready)
{ "id": "...", "asset_id": "...", "ref": "asset://<asset_id>", "name": "waiter-li", "status": "Active", "kind": "image", "usable": null, "source_url": "<your public image URL>", "created_at": "2026-09-15T13:37:02Z" }

Use the id from the create response in the path; the asset_id works too. The fields are exactly the same as one item of the list endpoint. An id that is not yours, does not exist, or was deleted returns 404.
(Optional) Adding ?model=<model name> returns one extra boolean field, usable, saying whether this asset can be used under that model; you only need it when you switch back and forth between models. Without ?model=, usable is null.

🔴 The list endpoint is for managing assets — do not poll status with it; poll with the single-asset endpoint above.

⚠️ Failed currently carries no reason; the most common cause is an image that is too small, so use normally sized photographs. Treat Failed as "register a different image" rather than retrying the same one.

(Optional) check whether a model supports the asset library before integrating
curl example · Check capability
BASE="https://tryaiapi.com" curl "$BASE/videos/v1/videos/assets/capability?model=doubao-seedance-2.0" \ -H "Authorization: Bearer <your API key>"
Response example
{ "enabled": true, "upload_max_bytes": 31457280, "upload_max_pixels": 36000000 }
Step 1: create an asset
curl example · Create an asset
BASE="https://tryaiapi.com" curl "$BASE/videos/v1/videos/assets" \ -H "Authorization: Bearer <your API key>" \ -H "Content-Type: application/json" \ -d '{ "url": "<your public image link>", "name": "front-desk-alex" }'
Response example
{ "id": "...", "asset_id": "...", "ref": "asset://<asset_id>", "name": "front-desk-alex", "status": "Processing", "usable": false, "source_url": "<your public image link>", "created_at": "2026-08-22T10:00:02Z" }

Asset status: Processing → Active (processing finished) / Failed (processing failed).
⚠️ In the example above status is still Processing, so this response cannot be submitted straight to generation — take the id from it, poll by id, and submit once status is Active. doubao-seedance-2.0 / doubao-seedance-2.0-fast require waiting until processing finishes; MiniMax-H3 is the exception — an asset can be referenced right after registration, regardless of this status.

When in doubt, call GET /videos/v1/videos/assets/capability?model=<model name> — its enabled field tells you directly whether that model can reference assets.

Step 2: reference it in a generation request

Take the ref from the previous step (asset://<asset_id>) and place it in image_urls, exactly like a regular image link:

curl example · Generate using an asset reference
curl https://tryaiapi.com/videos/v1/videos/generations \ -H "Authorization: Bearer <your API key>" \ -H "Content-Type: application/json" \ -d '{ "model": "doubao-seedance-2.0", "prompt": "This person walks into the store and greets the camera with a smile", "image_urls": ["asset://<asset_id>"], "resolution": "720p", "duration": 5 }'

Last updated: 2026-09-27

04Naming people & mention syntax

When several reference images appear together, you can tell the prompt "have this person do X" by naming them.

🔴 Over the API you must use the positional mention syntax @图片1, @图片2 (the spaced form @图片 1 is accepted too) — the number matches the order of the image_urls array (starting at 1). These two tokens are a literal, untranslated string the upstream model requires; do not substitute an English phrase for them. Only Seedance 2.0 and Seedance 2.5 currently support this @ syntax. MiniMax-H3 does not parse it: distinguish multiple reference images by their order in image_urls and each item's role field (see "Reference images") — you cannot bind a character to a name via @ in the prompt.

⚠️ The API only parses positional syntax such as @图片1, not arbitrary names. A name is treated as plain prompt text and the person binding will not take effect; map names to @图片N in your own application before submitting.

⇒ If you want your users to be able to use names, the rewrite has to happen in your own product: maintain a "name → which position this image is" mapping, and rewrite it to @图片N before you submit.

Last updated: 2026-09-27

05API reference

Authentication: every endpoint uses Authorization: Bearer <your key>.

Error envelope (uniform across the REST endpoints in this section and the Ark-compatible endpoint):

Error response shape
{ "error": { "code": "stable code", "message": "human-readable description", "type": "error category", "field": "the offending field (optional)", "details": { } } }

Please branch on code, not on the message text — copy may change, code is stable.

5.1 Submit a generation job · POST /videos/v1/videos/generations
FieldTypeRequiredDescription
modelstring✅Model name, ≤100 characters
promptstring✅ (except a final video from a draft)Prompt text. On the Seedance 2.0 series and Seedance 2.5, keep it to at most 500 Chinese characters or 1000 English words (as the official guide recommends; the model may skip details in longer prompts); ≤2000 characters on MiniMax-H3 (this platform's current entry-point limit, not an official vendor limit). Do not put inline parameters such as --dur / --rs / --rt in the prompt — this native endpoint rejects them for every model (prompt_reserved_params). Always use request fields; only the Ark-compatible endpoint parses inline parameters (and strips them from the prompt)
durationintegerSeconds. When omitted, doubao-seedance-2.5 defaults to -1 (same as the official Volcano Ark default); doubao-seedance-2.0, doubao-seedance-2.0-fast and MiniMax-H3 default to 5. doubao-seedance-2.0 / doubao-seedance-2.0-fast accept 4–15 or -1, doubao-seedance-2.5 accepts 4–30 or -1, MiniMax-H3 accepts 4–15 (no -1). -1 lets the model choose the length (same as the official Volcano Ark parameter): the hold is sized for the model's maximum (15 s for the Seedance 2.0 series, 30 s for Seedance 2.5) and the final charge follows the actual output length, with the difference released; the actual length is in metadata.duration. doubao-seedance-2.5 video edit (omni_reference_task_type: "edit") only accepts -1 and defaults to it. Out-of-range values return 400 at submission time
resolutionstringSeedance family: 480p / 720p / 1080p, defaults to 720p, doubao-seedance-2.0-fast tops out at 720p; 4k is available on doubao-seedance-2.0 only (billed at the official 4k unit price); a draft (draft: true) is 480p only and a final video from a draft is 1080p only (picked automatically when omitted); MiniMax-H3: 768p / 2k (lowercase on the wire, no 1080p), defaults to 768p
aspect_ratiostring16:9 / 4:3 / 1:1 / 3:4 / 9:16 / 21:9 / adaptive. With a reference image, doubao-seedance-2.5 defaults to reference-to-video and honors whatever aspect ratio you send. In first-frame / first-and-last-frames mode its output ratio follows the first-frame image, and when declared a video edit / extension (omni_reference_task_type edit / extend) it follows the source video; in these modes the ratio you send has no effect and does not cause an error. The doubao-seedance-2.0 family can specify a ratio in these modes. Note: with a reference video but no declared sub-task the model may decide it is an edit / extension on its own — the official guide recommends adaptive in that case
image_urlsarrayReference images, up to 9 items (up to 30 for doubao-seedance-2.5); two accepted forms below
video_urlsstring[]Reference videos, up to 3 items (up to 10 for doubao-seedance-2.5); each is a public video URL or asset://<video_asset_id> (the asset must be kind: video; an image asset here is rejected). Seedance 2.0 family: each clip 2–15 s, ≤15 s in total; doubao-seedance-2.5: each clip 2–30 s (4–30 s for video edit), ≤30 s in total. Clips outside these limits are rejected with no charge (reference_video_duration_out_of_range / reference_video_total_too_long). The link must be directly downloadable (mp4 / mov). Jobs with reference videos take significantly longer to generate — widen your polling timeout accordingly
audio_urlsstring[]Reference audio, up to 3 items (up to 10, 30s combined, for doubao-seedance-2.5); each is a public audio URL or asset://<audio_asset_id> (the asset must be kind: audio); except on doubao-seedance-2.5, it cannot be used alone — combine with a reference image or a reference video
generate_audiobooleanWhether to generate an audio track. Defaults to true (with audio) when omitted, matching Volcengine Ark’s official default; pass false for a silent video. Pass it explicitly either way rather than relying on the default
watermarkbooleanWhether to add a watermark
seedinteger-1 to 4294967295. Officially listed for Seedance 1.0 only; it has no effect on Seedance 2.0 and Seedance 2.5 (no error if sent)
camera_fixedbooleanSame as above: officially Seedance 1.0 only; no effect on Seedance 2.0 and Seedance 2.5 (no error if sent)
framesintegerSame as above: officially Seedance 1.0 only; no effect on Seedance 2.0 and Seedance 2.5 (no error if sent). Use duration instead
omni_reference_task_typestringOmni-reference sub-task: auto / reference / edit (video edit) / extend (video extension); official doubao-seedance-2.5 parameter (no effect on the Seedance 2.0 series; no error if sent). edit / extend need at least one video_urls entry, otherwise 400; edit only accepts duration -1; any other value returns 400
return_last_framebooleanWhen true, the finished job carries last_frame_url (a JPEG of the last frame, valid for about 24 hours, not copied by this platform) — use it as the next clip's first frame to chain continuous shots. Seedance 2.0 and Seedance 2.5; no extra charge
draftbooleanDraft mode, doubao-seedance-2.5 only: a 480p preview to check shots and motion first, priced the same as a normal 480p video. true on doubao-seedance-2.0, doubao-seedance-2.0-fast or MiniMax-H3 returns 400
draft_task_idstringFinal video from a draft, doubao-seedance-2.5 only: the job id of your own completed draft on the same model, created within 7 days. The final video is fixed at 1080p with the draft's length and is billed as a normal 1080p video. The prompt, reference media, duration, aspect ratio, seed, generate_audio and omni_reference_task_type are reused from the draft — do not send them (400 if you do)
output_formatstringmp4 (default) / mov (doubao-seedance-2.5 only; higher colour precision for grading and keying; some players cannot play it). The 2.0 family only outputs mp4: mp4 is the same as omitting it, mov returns 400. No extra charge
toolsarrayWeb search: [{"type": "web_search"}], Seedance 2.0 and Seedance 2.5. The model decides from the prompt whether to search; per the official guide it applies to text-only input. The number of searches is in metadata.usage.tool_usage.web_search
priorityintegerQueue priority 0–9, higher first (default 0), Seedance 2.0 and Seedance 2.5
execution_expires_afterintegerTask expiry in seconds, 3600–259200 (default 172800). For Seedance 2.0 and Seedance 2.5, a timed-out job waits up to this time for its result to be confirmed; see timeout below
safety_identifierstringAn identifier of your end user (a hash is recommended), printable ASCII, ≤64 characters, passed to the generation provider as-is (see the Volcano Ark docs for its official purpose)
service_tierstringSeedance 2.0 and Seedance 2.5 only have online inference: default is the same as omitting it, flex returns 400
generation_typestringomni_reference (multimodal reference, the default reading) / first_and_last_frames (first/last frame; reference video and audio are ignored in this mode)
callback_url / callback_secret—❌Not supported — passing these returns an error. Poll poll_url instead.

Each item in image_urls can be:

  • A string: a public image URL, or asset://<asset_id>. With exactly one image and no role, this is treated as first-frame image-to-video.
  • 🔴 With two or more images (outside first-and-last-frames mode), any image without a role is treated as a reference image (reference_image); images where you set role yourself follow what you set. Applies to Seedance 2.0 and Seedance 2.5.
  • Single-image exception: outside first-and-last-frames mode, doubao-seedance-2.5 treats even a single image as a reference image (reference-to-video).
  • A single image without a role, sent together with a reference video or reference audio, is treated as a reference image.
  • An object: { "url": "...", "role": "reference_image" }, where role may be first_frame / last_frame / reference_image. For multimodal reference, set role to reference_image explicitly

video_urls / audio_urls take plain URL strings only; you do not need to write a role (on the Ark-format endpoint you may also write these two fixed roles on video_url / audio_url items, as in the official examples). All three fields accept asset:// references, as long as the asset kind matches the field (image → image_urls, video → video_urls, audio → audio_urls).

Request header Idempotency-Key (optional, strongly recommended): send the same key on a network retry and it will not create a duplicate job or charge you twice. Submitting again with the same key returns the first job, even if the body changed; the body is not diffed. Use a new key for each new job.

Success response:

Response example · Submission accepted
{ "job_id": "...", "status": "queued", "poll_url": "https://tryaiapi.com/videos/v1/videos/jobs/<job_id>", "created_at": "2026-08-21T..." }
5.2 Estimate before submitting · POST /videos/v1/videos/generations/estimate

Same request fields as 5.1. It does not create a job, charge you, or trigger generation.

Response fieldDescription
modelThe model the estimate is for (echoed back)
estimated_costEstimated cost (USD)
estimated_cost_cnyCNY-converted amount (reference only)
fx_cny_per_usdDisplay exchange rate
currencyUSD (the billing currency of record)
basisEstimate basis, always pre_hold (computed on the pre-submission hold rules)
final_cost_may_adjusttrue — the final settled amount may differ slightly
5.3 Query a job · GET /videos/v1/videos/jobs/{job_id}
FieldDescription
statusSee the status table below
status_notePresent only when there is something worth explaining (a short human-readable note — always in Chinese in the current API; do not parse it, show it as-is or branch on status)
video_urlThe generation engine's own direct link; validity varies by which upstream channel the model runs on (most are about 24 hours) — use expires_at below for the actual value
expires_atExpiry time of the link above
platform_video_urlThis platform's own copy; defaults to null (not produced unless the 7-day copy is enabled)
platform_expires_atExpiry of the copy above (returned only when the 7-day copy is enabled)
last_frame_url / last_frame_expires_atLast-frame image link and its expiry (only when the job was created with return_last_frame: true; about 24 hours; not copied by this platform); otherwise null
error{code, message, details} on failure; always null while in progress
cost_pending / cost_finalHeld / settled amount (USD)
duration_msWall-clock time from submission to completion
metadataduration (the actual length — check it when you sent -1) / resolution / ratio / seed / usage (including web-search count tool_usage) / output_format / tools, etc.

Job status values:

ValueMeaning
queuedAccepted, waiting in the queue
runningGenerating
completedDone — ready to download
failedFailed (the hold is auto-refunded)
cancelledCancelled
timeoutTimed out (the hold is auto-refunded). ⚠️ A job that has timed out may still produce a video: until the result is confirmed its status stays running, usually for no more than 24 hours (for Seedance 2.0 and Seedance 2.5, up to the task's execution_expires_after, 48 hours by default, same as the official API), and the refund happens only once it is confirmed that no video was produced. During this period the native endpoint adds a status_note field explaining the situation; the Ark-compatible endpoint has no such field. Set your overall client timeout above 48 hours (or above your execution_expires_after if you set one).

⚠️ When you see running with a status_note, the result is still being confirmed: the charge has not been settled yet, so do not resubmit.

5.4 List jobs · GET /videos/v1/videos/jobs
ParameterDescription
page / page_sizePage number (≥1) / items per page (1–200, default 20)
statusFilter by status, values as in the table above
start_date / end_dateYYYY-MM-DD, both inclusive
api_key_idFilter by key

Responds with { items: [...], total, page, page_size, fx_cny_per_usd }, sorted newest-first by submission time (not adjustable). fx_cny_per_usd is the platform's current display USD→CNY rate, for display conversion only; billing is in USD.

5.5 Usage stats · GET /videos/v1/videos/jobs/stats

Same filter parameters as 5.4. Returns total_jobs / completed_jobs / failed_jobs / in_flight_jobs / total_cost (completed jobs only) / avg_duration_ms / fx_cny_per_usd (display rate, same as 5.4).

5.6 Export · GET /videos/v1/videos/jobs/export.csv

Same filter parameters as 5.4. ⚠️ A single export is capped at 200 rows — for more, page through 5.4 and aggregate on your side.

Header row (column names map 1:1 to the job object fields in 5.3): job_id, status, model, token_name, cost_final, cost_pending, duration_ms, created_at, completed_at, video_url, platform_video_url, error_code, error_detail, cost_final_cny (display only: cost_final x fx_cny_per_usd, converted at the current display FX), fx_cny_per_usd.

5.7 Asset library

Create an asset POST /videos/v1/videos/assets

FieldTypeRequiredDescription
urlstring✅http(s) image, video or audio URL (signed temporary URLs work as-is)
kindstringimage (default) / video / audio (audio: wav / mp3, 2–30 s, ≤15MB). A URL whose extension clearly contradicts the kind is rejected (asset_kind_url_mismatch)
namestring≤64 characters; cannot be "图片" or "图片N" (reserved for the mention syntax); must be unique within your account

The response includes id (for querying and deletion), ref (shaped like asset://xxx, placed directly into image_urls), and status (Processing / Active / Failed). Only Active assets can be used for generation (exception: MiniMax-H3 — an asset can be referenced right after registration, regardless of this status).

List assets GET /videos/v1/videos/assets
Returns { assets: [...] }.
🔴 This endpoint is for managing assets — do not poll status with it; poll with "Get one asset" below.

Get one asset GET /videos/v1/videos/assets/<id>
Returns just this one asset from your library, with the same fields as a list item (id, status, …); <id> may be the id or the asset_id from the create response. Anything that is not yours, does not exist, or was deleted returns 404. After registering, poll by id with this endpoint (every 2–3 seconds): submit once status is Active, and register a different image on Failed — no need to fetch the whole list.
(Optional) When switching between models, add ?model=<model name> so usable reports true/false (without it, or with an unknown model name, it is null).

Delete an asset DELETE /videos/v1/videos/assets/<asset_id>
Removes it from your library. already_retired: true in the response means it was already deleted (repeat calls are safe).

Check capability GET /videos/v1/videos/assets/capability?model=<model name>
Returns enabled (whether that model supports the asset library), upload_max_bytes, and upload_max_pixels. We recommend reading this endpoint at integration time rather than hardcoding these limits in your own code.

5.8 Upload endpoint (video workbench only — a platform integration usually doesn't need it)

This platform provides an image upload endpoint that turns a local file into a usable URL. An API integration usually does not need it: supply your own public URL instead (see "Reference images" above).

POST /videos/v1/videos/uploads, with the raw image bytes as the request body (not a form) — declare the type via Content-Type (image/jpeg / png / webp / gif / heic / heif / bmp / tiff); the response includes url. Images only: there is no upload endpoint for video assets or reference videos — videos must be supplied as publicly downloadable links (mp4 / mov); the video workbench also takes a pasted link, not a local file.

5.9 Ark-compatible endpoint: differences from Ark native

If you already use the Volcano Ark native format, you can connect directly to POST /videos/api/v3/contents/generations/tasks. The table lists only what differs:

ItemArk nativeThis platform
Address & authhttps://ark.cn-beijing.volces.com/api/v3, Ark API KeySet base_url to https://tryaiapi.com/videos/api/v3 and api_key to this platform's API Key; leaving out /api/v3 returns 404
Model nameModel ID, or an inference endpoint ID (starting with ep-)Use the model name, e.g. doubao-seedance-2-0-260128; an ep- endpoint ID returns 400
Task IDVolcano Ark task IDA UUID from this platform
Callbackscallback_url supportedNot supported — sending it returns 400; poll GET …/tasks/{id} instead
Task listLast 7 days only; filter.model takes an inference endpoint IDIncludes tasks older than 7 days; filter.model takes a model name
Cancelling an in-progress taskQueued: can be cancelled; generating: cannotOnce handed to the provider: cancellable if the supply channel supports it and the provider accepts (hold refunded in full), otherwise 400; a task still queued on this platform also returns 400; 409 (CancellationPending) = cancelled, settlement still being written — query again shortly. Deleting a finished task works as in the official API; your billing details keep it
Error codes of failed tasksArk error codesThis platform's stable codes — see §6 Error codes
Output linkscontent.video_url, valid for 24 hourscontent.video_url is the provider's direct link, valid until content.expires_at; once the copy succeeds, a 7-day platform copy content.platform_video_url is added
Request parametersPer the official parameter listParameters outside the list return 400 naming the parameter — never silently dropped; one the official API supports but the current channel hasn't wired up returns 400 (unsupported_parameter) before submission, with no charge
Real-person reference imagesasset:// of an asset on the Ark sideRegister it in this platform's asset library first and use the asset:// returned here

Everything else — request format, error format, status values, parameter semantics — matches the official API; which model each parameter applies to is in 5.1. Inline prompt parameters (--rs / --dur, etc.) are parsed into the matching fields, and disagreeing with the top-level field returns 400; for a final video from a draft, draft_task.id is this platform's draft task ID.

Last updated: 2026-09-28

06Error codes

Branch on code, not on the message text.

6.1 Client & validation errors
codeHTTPMeaningSuggested action
input_image_real_person400A reference image may contain a real personThis image needs to be added to the asset library first
input_image_too_large400Image exceeds the pixel limitUse a smaller image (the actual size and the limit are in details)
output_content_policy400The generated content may involve copyright or sensitive materialAdjust the reference images or prompt and retry
content_safety_rejected400The submission was rejected by the content-safety screen (it screens the prompt and reference media; the job ends as failed and the hold is auto-refunded)Review the prompt and reference media, then retry with a new Idempotency-Key (the old key only returns the failed job)
reference_media_unfetchable400A reference image/video could not be readCheck whether the link is publicly reachable and not too slow
invalid_asset_reference_format400The asset reference is malformed (not shaped like asset://<asset_id>)Client-side parameter error; value must match asset://<asset_id>
invalid_asset_reference400The referenced asset isn't in your library, or this model cannot use itPick a model that can use it, or create the asset again
asset_unavailable400The asset cannot be used yet: still processing, or processing failedProcessing: wait for Active, then resubmit; Failed: register a different image
asset_library_full400Your asset library has hit its cap (only appears if this platform has configured a per-account asset cap for you; unlimited by default)Delete unused assets
unsupported_resolution400This model does not support that resolution (for example 4k on doubao-seedance-2.5 or the fast tier, 1080p on the fast tier, or anything but 480p for a draft)Use a resolution from the model table above
unsupported_parameter400This model does not support the parameter / value (for example draft: true or output_format: "mov" on doubao-seedance-2.0; the Ark-endpoint field names ratio / content sent to the native endpoint; a prompt or duration sent with a draft follow-up); message names the fieldRemove or correct that field as message says
invalid_draft_task400The draft_task_id cannot be used: not your job, not a draft, not completed, older than 7 days, or a different modelGenerate a new draft and use its id
frame_role_conflict400First/last-frame roles cannot be combined with a reference videoDrop one of the two; do not mix them
asset_kind_invalid400kind is not image / video / audio when creating an assetUse one of the three values
asset_kind_url_mismatch400The URL extension clearly contradicts kind when creating an asset (e.g. .mp4 with image)Fix kind or the URL
asset_kind_field_mismatch400Asset kind does not match the field in the generation request (e.g. image asset in video_urls, video asset in image_urls, or audio asset outside audio_urls)Image assets go in image_urls, video assets in video_urls, audio assets in audio_urls
asset_kind_unsupported400This model's asset library does not support this asset kindPass a public direct URL instead
asset_url_invalid400The asset url is not an http(s) URLCheck the URL
invalid_inline_media400An inline Base64 asset is malformed (bad data: prefix, MIME type, encoding, or file format); validated before submission, no chargeFix the Base64 content per message, or switch to a public link
invalid_upload400The uploaded file is not acceptable (too large or unsupported type)Re-upload within the limits of the upload endpoint
unsupported_model400This endpoint does not support that modelSwitch model or endpoint
idempotency_key_reused409The same Idempotency-Key was reused for a different request body. The native and Ark-compatible endpoints on this page never return this code: resubmitting with the same key returns the first job (see 5.1)Use a fresh Idempotency-Key
billing_in_progress /
billing_reconcile_required
409Billing for this job is in flight (or has been parked for manual reconciliation)🔴 Do not mint a new Idempotency-Key — that key is mid-charge and a new one charges again. Wait and keep polling the job. If it is still this code after a minute, contact us
job_state_conflict409The request is fine, but the job it targets changed state in the meantimeQuery that job_id and wait for a terminal status (completed / failed / timeout / cancelled) before submitting again under a new Idempotency-Key; the existing job may still hold funds — resubmitting early can freeze the amount twice
storage_unavailable503Platform storage is temporarily unavailableRetry later. ⚠️ If this happens at submit time the job may already exist with its hold in place, pending confirmation: retry with the same Idempotency-Key (it replays the original job); a new key may hold funds twice
prompt_reserved_params400The prompt contains inline parameters such as --dur / --rs (not parsed on this native endpoint)Use duration / resolution request fields instead
inline_param_conflict400Ark-compatible endpoint only: an inline prompt parameter disagrees with the top-level fieldKeep one of the two
audio_requires_visual400Reference audio cannot be used aloneAdd a reference image or a reference video
invalid_request400Generic invalid-parameter code (wrong type, value outside the allowed set, over a limit, duration out of range…); message names the field and states the allowed range. Duration out of range returns this code on every model — there is no separate duration error codeFix the parameter named in message
too_many_reference_items400MiniMax-H3 only: exceeds its model-specific combination limits (e.g. number of first/last-frame images). Otherwise, exceeding a model's reference-item limits (see "Quotas & limits") returns invalid_requestSend fewer reference images / videos
frame_and_reference_mixed400First/last-frame images mixed with reference images (MiniMax-H3 and similar)Use one or the other
reference_video_duration_out_of_range400A reference video clip is outside the allowed length (2–15 s for the Seedance 2.0 family; 2–30 s for doubao-seedance-2.5, 4–30 s for video edit)Trim it and resubmit
reference_video_total_too_long400Total reference-video length over the limit (15 s for the Seedance 2.0 family; 30 s for doubao-seedance-2.5)Drop a clip or trim
reference_video_duration_unverifiable400The reference video's duration could not be read (the link is not a directly downloadable MP4 / MOV — e.g. a file-sharing page or a login-gated URL)Use a directly downloadable public URL
asset_name_too_long / asset_name_reserved / asset_name_taken400Asset registration: name too long / uses the reserved “图片” / “图片N” format / duplicates an existing asset namePick another name — it is the @ handle used in prompts, so it must be unique and cannot be truncated
upload_expired409An image sent through the upload endpoint passed its retention window and can no longer be added to the libraryUpload it again, then add it
6.2 Auth & server errors
codeHTTPMeaningSuggested action
invalid_api_key401/403Invalid key, or the account is disabledCheck your configuration; contact us
ip_not_allowed403The key is restricted to an IP range and the current source isn't in itContact us to adjust it
insufficient_credits402Insufficient account balanceTop up; we recommend building your own low-balance alert
model_not_found404Model name doesn't exist or isn't enabledCheck the model name
task_not_found404Job doesn't exist, or doesn't belong to youCheck the job ID
upload_quota_exceeded429Upload quota reached (only appears if this platform has upload-quota enforcement turned on; when it's off, going over quota is only logged, not blocked)For API integrations, pass public URLs directly; see "Reference images"
rate_limit_exceeded429Requests are coming in too fastBack off and retry
submission_rate_limited429This account hit the cap on concurrently running jobs, or on submissions in the last minute (not a failure — no job was created and nothing was charged); this gate can be turned off by this platform, in which case this code is never returnedBack off per the Retry-After header, then retry. details carries the current value and the cap (inflight/max_inflight or submits_last_minute/max_per_minute) so you can throttle adaptively
upstream_timeout504Generation timed out (the hold is auto-refunded)Retryable
upstream_generation_failed502/503Failure on the generation provider's side (the hold is auto-refunded); also returned when the asset library is temporarily unavailable at asset creation (nothing is charged)Back off and retry
submission_result_ambiguous502The submission result could not be confirmed🔴 Contact us first — do not retry blindly
internal_error500Internal error on this platformContact us
billing_error500The pre-submission balance check failed (billing system temporarily unavailable); this happens before the hold is placed — no chargeRetry shortly; contact us if it keeps failing
invalid_json400The request body is not valid JSONCheck your serialization and Content-Type: application/json
request_too_large413The request body exceeds 64 MB (see "Quotas and limits"); rejected before parsing — no chargeShrink the request body (use a link for large files, or upload / register it in the asset library first)
not_found404The path doesn't exist (a method/URL typo or a wrong version prefix — unrelated to the business-level task_not_found / model_not_found)Check the request address (including how base_url is composed — see the "Ark-compatible endpoint" differences table in 5.9)
asset_upstream_missing502The asset is temporarily unavailable; the platform is restoring it automaticallyRetry shortly
credits_lock_unavailable503The system is busy; nothing was chargedRetry shortly
discount_lookup_unavailable503Pricing is temporarily unavailable; nothing was chargedRetry shortly
upstream_state_persistence_failed503The job may already have started generating, but the platform cannot record its status right now🔴 Contact us before retrying: a blind retry may generate twice
upstream_channel_unavailable502The generation service is temporarily unavailable (not related to your API key)Retry with backoff; contact us if it persists
missing_task_id502The submission did not go through; the hold is auto-refundedRetry later
6.3 Retry guidance
  • 400-class: don't auto-retry — the request itself needs to change.
  • 401 / 402 / 404: don't auto-retry.
  • 429: exponential backoff.
  • 502 / 503 / 504: retryable with backoff, except submission_result_ambiguous — it means we could not confirm whether that job was accepted by the generation provider; retrying blindly risks a duplicate video and a duplicate charge.

Last updated: 2026-09-28

07Tenancy & isolation boundaries 🔴 read before integrating

Assets and jobs are scoped to your account, not to an individual API key.

When this section applies to you

If you only call this API from within your own service and you decide who sees what, none of this affects your users — everything they see is determined entirely by your product. But if you plan to hand off listing, querying, or deleting assets to them (for example, an asset-management panel for your users, or handing them a key directly), read this section first.

Isolation is scoped at the account level: every key issued under one account is the same tenant to this platform. As a result:

  • Once you expose "list assets" / "delete assets" to your users, User A can see, and can delete, an asset uploaded by User B
  • The asset library is account-level — all of your users share one library
  • Usage breakdowns are available at the granularity of a key, at finest
Your users never call this API directly — isolation is on you

This platform can only see down to your account — it cannot see, or distinguish, which of your users is behind a given call on your product. Who-can-see-whom and what-permissions-they-have among your own users can only be implemented in your own product.

Different customers are isolated from each other: accounts cannot see each other; you cannot see another customer's assets.

🔴 Compliance notice: authorization for real-person material rests with the integrator. This platform's asset library channel does not include the generation engine's verified real-name / liveness check flow, and produces no proof of subject consent.

You must ensure that every user on your product who uploads a real-person asset lawfully holds the right to use that likeness with the necessary authorization, and that you retain the corresponding proof of authorization; you should also address this in the service agreement you have with your own users. Content involving a minor's likeness or voice is subject to stricter compliance requirements.

Last updated: 2026-09-24

08Quotas & limits

ItemLimitScope
Prompt lengthSeedance 2.0 and Seedance 2.5: recommended at most 500 Chinese characters or 1000 English words; MiniMax-H3 2000 characters (this platform's current entry-point limit, not an official vendor limit)Per request
Reference imagesSeedance 2.0 series and MiniMax-H3: 9; Seedance 2.5: 30Per request
Reference videos / audioSeedance 2.0 series and MiniMax-H3: 3 each (≤15s combined each); Seedance 2.5: 10 each (≤30s combined each)Per request
Pixels per image36 million (width × height; this platform's upload pre-check value, matching the current supply channel's production-observed generation-time upstream limit — other channels may differ)Per image
File size per image30 MBPer image
Total request body size64 MB (same as the official API; large requests carrying Base64 media are queued and processed in turn)Per request
CSV export200 rowsPer request

⚠️ Result links expire: by default only the generation engine's own direct link is provided — its actual validity is whatever expires_at in the response says (varies by which upstream channel the model runs on; most are about 24 hours) — download and move it to your own storage promptly; if you need this platform to retain a 7-day copy, contact us to enable it.

⚠️ Cancelling is available on the Ark-compatible endpoint for in-progress tasks when the current supply channel supports cancellation: on success the hold is refunded in full; if the provider no longer accepts cancellation, or the current channel doesn't support it, it returns 400; a task still queued on this platform and not yet submitted to the provider also returns 400. Finished tasks can have their record deleted (see 5.9 "Ark-compatible endpoint: differences from Ark native"). Failed and timed-out jobs are refunded automatically.

Last updated: 2026-09-28

09Integration FAQ

Why was my image rejected?
Three common reasons — it contains a real person (use the asset library, see "Asset library: the real-person channel"); it exceeds the pixel limit (downscale first, see "Reference images"); or the content involves copyright or sensitive material. The error message tells you which one.
Why doesn't @Alex work?
Over the API you must write @图片1 — see "Naming people & mention syntax".
My users can see each other's assets — what do I do?
See "Tenancy & isolation boundaries" — you need to implement isolation in your own layer.
How long does a job take?
Turnaround depends on the model, duration, and scene complexity. Poll the response's poll_url asynchronously; do not wait synchronously.
Can I cancel a job?
Yes, when the current supply channel supports it. On the Ark-compatible endpoint, send DELETE …/tasks/{id} for a task still in progress to request cancellation; on success the hold is refunded in full, and if the provider no longer accepts cancellation, or the current channel doesn't support it, it returns 400; a task still queued and not yet submitted to the provider also returns 400. The same call deletes the record of a finished task. Failed and timed-out jobs are refunded automatically.

Last updated: 2026-09-27

Want more integration detail? Contact support@tryaiapi.com and we'll confirm the integration details with you as soon as we can.