GPT Image 2.5 is live — OpenAI's newest image model, targeted edits that leave the rest of the frame alone
rreAPI Docs

doubao-seedance-2.5-face

ByteDance Seedance 2.5 — async video generation up to 30 seconds with native audio on reAPI. Full parameter reference, request modes, and billing dimensions.

ByteDance's next-generation async video model, live on reAPI. Seedance 2.5 turns text, photos, clips, or audio into video up to 30 seconds long, with generated speech, sound effects and music. Like the rest of the Seedance family, mode is implicit: which media fields you set (prompt, image_urls, image_with_roles, video_urls, audio_urls) decides whether the request runs as text-to-video, image-to-video, first/last-frame transition, or reference-driven generation. See pricing on the model page.

Quick example

curl https://reapi.ai/api/v1/videos/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "doubao-seedance-2.5-face",
    "prompt": "A kitten yawning at the camera, cinematic warm tones",
    "resolution": "720p",
    "size": "16:9",
    "duration": 5
  }'
import requests

resp = requests.post(
    "https://reapi.ai/api/v1/videos/generations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "doubao-seedance-2.5-face",
        "prompt": "A kitten yawning at the camera, cinematic warm tones",
        "resolution": "720p",
        "size": "16:9",
        "duration": 5,
    },
    timeout=30,
)
print(resp.json())
const r = await fetch("https://reapi.ai/api/v1/videos/generations", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "doubao-seedance-2.5-face",
    prompt: "A kitten yawning at the camera, cinematic warm tones",
    resolution: "720p",
    size: "16:9",
    duration: 5,
  }),
});
console.log(await r.json());
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]any{
        "model":      "doubao-seedance-2.5-face",
        "prompt":     "A kitten yawning at the camera, cinematic warm tones",
        "resolution": "720p",
        "size":       "16:9",
        "duration":   5,
    })
    req, _ := http.NewRequest("POST",
        "https://reapi.ai/api/v1/videos/generations", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    out, _ := io.ReadAll(resp.Body)
    fmt.Println(string(out))
}

Authentication

Every call needs a Bearer token. Generate keys at reapi.ai/settings/apikeys.

Authorization: Bearer YOUR_API_KEY

Keys carry the active workspace's billing scope — there is no separate project header.

Endpoint

POST /api/v1/videos/generations
GET  /api/v1/tasks/{id}

Submission is async. The POST returns immediately with a task_id; the task endpoint returns the same envelope until completion. Polling does not consume credits.

Variants

Two variants, one parameter shape. Pick via model:

Model idResolutions
doubao-seedance-2.5-face480p / 720p / 1080p
doubao-seedance-2.5-eco720p / 1080p

doubao-seedance-2.5-eco is the economy tier: the same request body and the same modes documented below, starting at 720p rather than 480p. It bills on its own per-second rates — see the model page for the current numbers.

Picture quality on the economy tier may be below the standard variant. The price reflects that. Generation also takes roughly 50–100 s longer than the standard tier. That is a typical range, not a guarantee. Everything else is identical: content_filter, duration: -1, omni_reference_task_type, reference media, output_format, the response envelope and the error codes.

reAPI never silently substitutes one variant for another: resolution: "480p" on the economy tier returns 400, never an auto-substituted clip.

Request body

Mode is implicit — which media fields you set decides text-to-video, image-to-video, first/last-frame, or reference-driven generation. Audio-only reference (just audio_urls) is supported, and reference images / videos may contain real people.

FieldTypeDefaultNotes
modelstring—doubao-seedance-2.5-face or doubao-seedance-2.5-eco. Required.
promptstring—Describe the video, up to 20000 chars. Optional when any reference material is present (with content_filter: true); required for pure text-to-video and whenever content_filter is false. Wrap spoken lines in double quotes to steer the generated speech.
durationinteger5Output length in seconds: 4–30, or -1 to let the model pick the best length (required for video-edit prompts — see Task types). -1 reserves credits at the 30 s cap and settles to the actual output length once the video is ready — the difference is refunded automatically.
sizestringadaptive16:9 / 9:16 / 1:1 / 4:3 / 3:4 / 21:9 / adaptive. Locked to adaptive in three cases: a first_frame/last_frame entry in image_with_roles (output follows the first frame), and omni_reference_task_type of edit or extend (output keeps the source clip's shape). Plain reference images place no restriction — pick any ratio.
resolutionstring720p480p / 720p / 1080p. The economy tier starts at 720p — see Variants.
bitrate_modeenum"default"default: no processing; standard: smaller files; high: lighter compression. No extra generation charge.
generate_audiobooleantrueGenerate synced speech, sound effects and background music (mono).
output_formatstringmp4mp4 / mov. mov uses high color-precision encoding (H.264 4:4:4, video/quicktime) for pro post-production; some players can't play it. Delivered URLs end in .mov and are served as video/quicktime.
omni_reference_task_typestringautoauto / reference / edit / extend. Declares which reference job this is so its rules are checked at submit instead of mid-run — see Task types. Declaring edit also makes duration default to -1, so you can simply omit it.
watermarkbooleanfalseStamp an "AI generated" mark in the bottom-right corner.
return_last_framebooleanfalseReturn output.last_frame_url for continuous chaining.
seedinteger—Random seed. Sent upstream on every request; the same seed gives a similar result but is not guaranteed to be byte-identical. Omitted → random.
toolsobject[]—[{ "type": "web_search" }] to let the model query the web.
image_urlsstring[]—Up to 30 reference images (jpeg / png / webp / bmp / tiff / gif / heic / heif, each < 30 MB). Public HTTP(S) URLs.
image_with_rolesobject[]—Images with an explicit role: { url, role } where role is first_frame, last_frame, or reference_image. At most one first_frame and one last_frame (they may be the same image); up to 30 entries in total. May be combined with video_urls / audio_urls — the upstream then treats the frames as reference images (multimodal reference job).
video_urlsstring[]—Up to 10 reference clips (mp4 / mov, 480p–4K, each ≤ 200 MB), each 2–30 s, combined ≤ 30 s.
audio_urlsstring[]—Up to 10 reference audio tracks (wav / mp3, each ≤ 15 MB), each 2–30 s, combined ≤ 30 s.
content_filterbooleantrueSafety checking. Set false to run the task on the unmoderated route — see content_filter below.
draftboolean—true renders a 480p draft you can later turn into a 1080p final. Resolution must be 480p (omitted → 480p); prompt is required; at most 30 images with either content filter setting. doubao-seedance-2.5-face only — see Draft mode.
draft_task_idstring—The id of a completed draft task. Renders its 1080p final; send only output options with it. Resolution must be 1080p (omitted → 1080p). See Draft mode.

Checked before anything is submitted or charged:

  • at least one of prompt or a reference field must be present
  • image_urls and image_with_roles are mutually exclusive (both carry reference images — pick one)
  • at most one first_frame and one last_frame, and a last_frame always needs a first_frame (there is no last-frame-only task type)
  • frame roles and reference_image cannot share one image_with_roles array — they are separate task types; put reference images in image_urls
  • a first_frame/last_frame entry forces size to adaptive
  • reference clips: each 2–30 s, 10 max, 30 s combined; reference audio: each 2–30 s, 10 max, 30 s combined
  • whatever omni_reference_task_type you declare, its own rules (below)
  • draft and draft_task_id are mutually exclusive; a draft needs a prompt, 480p and at most 15 images, a final needs 1080p and none of the fields it inherits (see Draft mode)

image_with_roles can be combined with video_urls / audio_urls: the upstream converts the frames to reference images and runs a multimodal reference job.

Referencing media in the prompt

Point the prompt at a specific reference with @Image 1, @Video 1 and @Audio 1. Numbering starts at 1 separately for each type, in the order the URLs appear in image_urls, video_urls and audio_urls. Say what each asset contributes (appearance, motion, timbre) and what it should not. reAPI forwards the prompt unchanged.

{
  "model": "doubao-seedance-2.5-face",
  "prompt": "The woman in @Image 1 walks down the street, following the camera movement of @Video 1, speaking in the voice of @Audio 1",
  "image_urls": ["https://example.com/woman.png"],
  "video_urls": ["https://example.com/camera-move.mp4"],
  "audio_urls": ["https://example.com/voice.mp3"],
  "duration": 10
}

bitrate_mode — enum, default "default"

Available across Seedance 2.0, Fast, Mini, and 2.5, including all channels. This is reAPI output processing after generation.

  • "default" or omitted: return the original file without processing or re-encoding. This is the default setting.
  • "standard": compress for smaller files and faster downloads.
  • "high": apply lighter compression to retain more detail than standard, usually producing a larger file. It does not enhance the original video.

Processing preserves resolution, frame timing, audio, and the MP4/MOV container. If encoding would increase file size, the original file is kept. The generation charge is unchanged. Processing adds time and supports source files up to 1 GiB; savings vary by video.

Legacy booleans remain accepted: false maps to "default", and true maps to "standard". Other values return 400 before charging. Processing or storage failures follow the existing task failure/refund policy; an unprocessed source URL is not silently substituted after a processing failure.

{ "bitrate_mode": "default" }

content_filter — boolean, default true

With the default (true) the request runs on the moderated route: prompts, reference material and output are checked, and a rejection fails the task with a refund.

Set content_filter: false to run the same request on the unmoderated route instead. What changes:

  • API keys only. A website session that sends content_filter: false is rejected with 400 before anything is charged; the playground always runs moderated.
  • prompt becomes required in every mode, including reference jobs.
  • Same parameters, same price. Every field, rule and rate in this document applies unchanged — which channel served the request is internal.
  • Output lands in an isolated bucket and its URLs stay valid for 30 days — mirror the files if you need them longer.

Platform terms apply to everything you generate on either route.

Draft mode

Render a cheap 480p draft first, and only pay for 1080p once the take is right. Available on doubao-seedance-2.5-face (both content_filter settings), not on the economy tier.

Step 1 — the draft. A normal request plus "draft": true, with three differences: prompt is required (even with reference media), at most 30 images with either content filter setting (across image_urls and image_with_roles), and resolution must be 480p (omit it and 480p is used). Every other media and task-type rule is unchanged.

{
  "model": "doubao-seedance-2.5-face",
  "prompt": "a fox sits in the grass, the camera slowly pulls back",
  "image_urls": ["https://example.com/reference.png"],
  "duration": 5,
  "size": "16:9",
  "draft": true
}

Poll the returned id until the task is completed.

Step 2 — the final. Send the draft's id as draft_task_id. The final re-renders the same take at 1080p.

{
  "model": "doubao-seedance-2.5-face",
  "draft_task_id": "task_01a0...",
  "output_format": "mov",
  "return_last_frame": true
}

The final inherits the draft's prompt, reference media, duration, aspect ratio, seed, audio setting, task type, web search and content_filter. Do not resend any of them — even an identical value is rejected with 400 before anything is charged. Only output_format, return_last_frame, watermark and bitrate_mode can be set, and resolution may only be 1080p.

  • A draft is usable for 7 days after it was created.
  • The draft must be a completed draft task from your own account. A draft made through the API is finalized through the API, and one made in the playground is finalized in the playground.
  • One draft can produce several finals; each is a separate task, billed separately.

Billing. The draft is billed as a normal 480p video (reference video seconds count as usual). The final is billed at the 1080p rate without video input, for the draft's duration plus the draft's reference-video seconds — the final re-renders the draft together with its reference clips, so those seconds are billed again. A draft with no reference video is billed on its output length alone. The video-input minimum applies to the draft but not to the final: a draft with a 2-second reference clip and duration: 10 bills 17 seconds, and its final bills 12. A draft made with duration: -1 reserves its final at the 30-second cap (plus any reference-video seconds) and settles to the delivered length.

Task types and constraints

Seedance 2.5 does more than generate new clips: give it a source video and it can also edit that video or extend it. Which job you get is decided by the model from your reference material and the wording of your prompt.

Three of these jobs carry hard parameter rules:

JobWhat it doesNeedsHard rules
Text-to-videonew clip from a promptpromptnone
First / last frameanimates between given framesimage_with_rolessize must be adaptive
Reference (reference)new clip guided by your images / clips / audioany reference fieldnone — any ratio, any duration
Edit (edit)changes the content of a source clip≥1 video_urls, source 4–30 sduration must be -1, size must be adaptive
Extend (extend)continues a source clip forwards or backwards≥1 video_urlssize must be adaptive

Declare the job and get errors for free

By default (omni_reference_task_type: "auto") the model reads your prompt and picks the job itself — and it only discovers a rule violation after the task is created and credits are reserved. You get a late failure and a refund.

Set the field explicitly and the rules are checked while you are still holding the HTTP connection:

{
  "model": "doubao-seedance-2.5-face",
  "prompt": "remove the parked car on the left",
  "video_urls": ["https://example.com/street.mp4"],
  "omni_reference_task_type": "edit"
}

duration is omitted on purpose: an edit keeps the source clip's length, so declaring edit sets it to -1 for you. Passing a fixed duration alongside edit is rejected — by us and by the upstream.

auto (default)declared explicitly
Wrong duration on an edittask starts, fails minutes later, refundedHTTP 400 at submit, no task, nothing charged
Feedback speedafter generationimmediate

Declaring the job does not force it. The model still reads your prompt, and if its own classification disagrees with what you declared the task fails with a task-type mismatch. Write the prompt to match the job you asked for — an edit prompt should describe a change to the existing footage ("remove the car", "make it night"), not a brand-new scene.

Leaving the field out keeps the previous behaviour exactly, so existing integrations need no changes.

Troubleshooting

FailureWhat it meansWhat to do
Synchronous 400 on submitA field violates the schema (bad resolution, size with first/last frames, missing prompt on text-to-video, …)The error names the field — fix and resubmit; nothing was charged
Synchronous 400 naming a format (… format matroska is not supported)A reference file is not in a format the model accepts — see Reference media formats. The check reads the file itself, so a renamed extension does not helpRe-encode: images to jpeg / png / webp, clips to H.264 mp4, audio to wav / mp3
Task fails with a parameter error after startingThe model classified your prompt as a video edit/extend task and the parameters don't match its rules (see the table above)Set duration: -1 for edits, keep size adaptive, or remove edit/extend wording; the reserve is fully refunded. To turn this into an instant 400 next time, declare omni_reference_task_type
Task fails with a task-type mismatchYou declared omni_reference_task_type but the model read your prompt as a different jobMatch the prompt to the job — an edit prompt must describe a change to the existing footage, not a new scene
Task fails citing sensitive contentReference material or the generated output was rejected by moderationFully refunded. Real-person references are supported and reviewed automatically — persistent rejections mean the material itself violates content policy
402 on submitNot enough credits for the reserve (auto-duration reserves at the 30 s cap before settling down)Top up, or set an explicit shorter duration
Task stays processingNormal for up to a few minutes — generation averages 2–5 min depending on length and referencesKeep polling; tasks that can never finish are failed and refunded automatically

No data: URIs. reAPI rejects base64 inputs platform-wide — every URL field must be a public HTTP(S) URL. Upload to your own object storage (S3, R2, OSS, …) and pass the URL.

Response envelope

Submit and poll share the same shape — only status and output fill in over time.

{
  "id": "task_018f5a3a1b6e7d9f8c2b4d6e8f0a2c4e",
  "model": "doubao-seedance-2.5-face",
  "status": "completed",
  "created_at": 1735000000,
  "output": {
    "video_urls": ["https://cdn.reapi.ai/media/tasks/.../0.mp4"],
    "last_frame_url": "https://cdn.reapi.ai/media/tasks/.../0.png"
  },
  "error": null
}

Poll GET /api/v1/tasks/{id} (see the Tasks reference) until status === "completed". output.video_urls holds the generated video URL (mp4, or mov when output_format: "mov" was set). output.last_frame_url is present when the request set return_last_frame: true.

Pricing

Seedance 2.5 bills per second of video, at a rate that depends on the resolution and on whether you supplied a reference video:

credits = ceil(per_second_rate × billable_seconds × 1000)     1 credit = $0.001

Live per-second rates are on the model page — that table is generated from the current price, so it is always the authoritative number.

The part worth reading is billable_seconds, because three rules make it differ from the duration you asked for. Failed jobs are always refunded in full.

1. A reference video is billed too, on top of the output

Send video_urls and you pay for the source footage plus the generated clip:

billable_seconds = ceil(total_length_of_video_urls) + duration

reAPI measures every reference clip server-side, so this is the real length of the file, not a value you declare. Reference images and audio are free — they add no seconds.

A 6-second source clip with duration: 5 bills 11 seconds, not 5.

2. Video-input requests have a minimum

When the input contains a video, the upstream charges a floor of ⌈5 × duration / 3⌉ seconds however short your source clip is. You pay the larger of the two numbers:

billable_seconds = max( ceil(reference_seconds) + duration,  ceil(5 × duration / 3) )
durationreference clipinput + outputflooryou pay
5 s2 s7 s9 s9 s
5 s6 s11 s9 s11 s
10 s3 s13 s17 s17 s
10 s12 s22 s17 s22 s

Short source clips are where this bites: a 2-second reference with a 5-second output costs the same as a 9-second job. Longer sources pass the floor and pay their real length.

3. duration: -1 reserves at 30 seconds, then refunds

-1 asks the model to choose the length, so there is no number to price at submit. reAPI reserves credits at the 30-second cap and settles to the real length once the video is delivered — the difference is refunded automatically.

This is why a -1 request can return 402 on an account that could easily afford the video it actually produces: the reserve, not the final price, has to fit. Set an explicit duration if you need a tighter hold.

Both other rules still apply to -1: with a reference video the reserve is computed from 30 seconds of output, and the settled charge is recomputed from the delivered length.

Table of Contents