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.0

ByteDance Seedance 2.0 — async video generation of 4–15 seconds with native audio on reAPI. Full parameter reference, request modes, content filter, and billing dimensions.

ByteDance's async video model on reAPI. Seedance 2.0 turns text, photos, clips, or audio into video of 4–15 seconds at 480p up to 4k, with generated speech, sound effects and music. 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. Two variants share one endpoint and one parameter shape — pick the variant via model. 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.0-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.0-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.0-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.0-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

Three variants, one parameter shape. Pick via model:

Model idResolutionsduration: -1
doubao-seedance-2.0-face480p / 720p / 1080p / 4k
doubao-seedance-2.0-fast-face480p / 720p
doubao-seedance-2.0-eco720p / 1080p / 4k

All three accept real-person reference images and clips, and all three carry the content_filter switch. The Fast variant is cheaper and quicker and caps at 720p.

doubao-seedance-2.0-eco is the economy tier: the same request body and the same modes, 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 variants. 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, reference media, bitrate_mode, the response envelope and the error codes.

reAPI never silently substitutes one variant for another: resolution: "1080p" on the Fast variant returns 400, never an auto-downgraded clip. The same holds for resolution: "480p" on the economy tier.

Request body

Mode is implicit — which media fields you set decides text-to-video, image-to-video, first/last-frame, or reference-driven generation (see Task types). Face variants accept real-person reference images and clips.

FieldTypeDefaultNotes
modelstringdoubao-seedance-2.0-face, doubao-seedance-2.0-fast-face or doubao-seedance-2.0-eco. Required.
promptstringDescribe the video: 3–20000 chars (≤ 500 recommended — quality drops past that on the upstream model). Required on every request, in every mode. Wrap spoken lines in double quotes to steer the generated speech.
durationinteger5Output length in seconds: 415. doubao-seedance-2.0-face also accepts -1 to let the model pick the length — see Pricing. Not available on the Fast variant, and not at 4k with the content filter on.
sizestringadaptive16:9 / 9:16 / 1:1 / 4:3 / 3:4 / 21:9 / adaptive (match the input image / video). The Fast variants default to 16:9.
resolutionstring720p480p / 720p / 1080p / 4k, lowercase only. 480p, 1080p and 4k are all variant-gated — see the table above.
bitrate_modeenum"default"default: no processing; standard: smaller files; high: lighter compression. No extra generation charge — see bitrate_mode.
generate_audiobooleantrueGenerate synced speech, sound effects and background music. Independent of audio_urls, which is a reference for the model, not a synthesis toggle.
watermarkbooleanfalseStamp an "AI generated" mark in the bottom-right corner.
return_last_framebooleanfalseReturn output.last_frame_url for continuous chaining.
toolsobject[][{ "type": "web_search" }] to let the model query the web.
image_urlsstring[]Up to 9 reference images (jpeg / png / webp / bmp / tiff / gif / heic / heif). Public HTTP(S) URLs. 1–2 images animate from them (I2V); more act as references.
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, and a last_frame needs a first_frame; up to 9 entries. Frame roles cannot be mixed with reference_image in one array, and cannot be combined with video_urls / audio_urls.
video_urlsstring[]Up to 3 reference clips (mp4 / mov, H.264 / H.265 with AAC / MP3 audio, 300–6000 px per side), combined ≤ 15 s.
audio_urlsstring[]Up to 3 reference audio tracks (wav / mp3), each 2–15 s, combined ≤ 15 s. Needs an image (image_urls or a reference_image entry) or video_urls alongside.
content_filterbooleantrueSafety checking. Set false to run the task on the unmoderated route — see content_filter below.

Checked before anything is submitted or charged:

  • prompt is present on every request (3–20000 chars)
  • 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, and frame roles cannot be combined with video_urls / audio_urls
  • audio_urls needs a visual reference (an image or a clip) alongside it
  • reference clips: 3 max, 15 s combined; reference audio: each 2–15 s, 3 max, 15 s combined
  • 1080p / 4k and -1 only on doubao-seedance-2.0-face

There is no seed on Seedance 2.0 — the upstream model does not support one, so the field is rejected rather than silently ignored.

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.
  • Same parameters, same price. Every field, tier gate and rate in this document applies unchanged — which channel served the request is internal. On the Fast variant the route still caps at 720p.
  • 4k gains auto duration. duration: -1 at 4k is only available with content_filter: false; with the filter on, pick an explicit duration for 4k.
  • 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.

{
  "model": "doubao-seedance-2.0-face",
  "prompt": "A kitten yawning at the camera, cinematic warm tones",
  "resolution": "720p",
  "duration": 5,
  "content_filter": false
}

Task types and constraints

Seedance 2.0 picks its job from the media fields you send — there is no mode parameter:

JobWhat it doesNeedsHard rules
Text-to-videonew clip from a promptprompt onlynone
Image-to-videoanimates / extends from reference imagesprompt + image_urls (1–9)none
First / last frameanimates between given framesprompt + image_with_roles (1–2 frames)frames cannot be combined with video_urls / audio_urls
Referencenew clip guided by clips and / or audio, optionally imagesprompt + video_urls and / or audio_urls (+ optional image_urls)audio needs an image or a clip alongside; clips and audio ≤ 15 s combined each

Mutex rules. The single legal multi-field shape is image_urls + video_urls + audio_urls (a multimodal reference job). Any other combination — image_urls with image_with_roles, frame roles with video_urls / audio_urls, audio on its own — is rejected with 400 (code 20003) before anything is charged.

Troubleshooting

FailureWhat it meansWhat to do
Synchronous 400 on submitA field violates the schema (bad resolution for the variant, an illegal field combination, missing prompt, …)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. 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
Synchronous 400 content_filter cannot be disabled from the websiteThe request came from a browser session with content_filter: falseCall the endpoint with an API key
400 with code 30002 on a reference videoreAPI could not read the clip's length to price itMake sure the URL is public and the file is a readable mp4 / mov; nothing was charged
Task fails citing sensitive contentReference material or the generated output was rejected by moderationFully refunded. Real-person references are supported on the Face variants 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 15 s cap, and a reference video is billed on top of the output)Top up, or set an explicit shorter duration
Task stays processingNormal for a few minutes — generation time grows with 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.0-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
}
FieldTypeNotes
idstringTask identifier — keep it for polling and audit
modelstringEcho of the submitted model
statusstringprocessing / completed / failed
created_atintegerSubmission unix timestamp
outputobject | nullnull until completion
output.video_urlsstring[]Generated MP4 URL(s)
output.last_frame_urlstring | nullPresent only when the request set return_last_frame: true
errorobject | nullPopulated on failed{ code, message }

Poll GET /api/v1/tasks/{id} (see the Tasks reference) until status === "completed". Generated URLs expire — mirror them to your own storage if you need long-term retention.

Validation errors

All cases below return HTTP 400 with the noted code. Pattern-match on code, not message — message strings carry request-specific context (field names, observed values) and are not a stable contract.

TriggerCodeMessage
Missing prompt20002prompt: Invalid input: expected string, received undefined
prompt shorter than 3 chars20003prompt: Too small: expected string to have >=3 characters
prompt longer than 20,000 chars20003prompt: Too big: expected string to have <=20000 characters
image_urls and image_with_roles together20003image_urls and image_with_roles cannot be used simultaneously
first_frame / last_frame + video_urls or audio_urls20003first_frame / last_frame entries cannot be combined with video_urls or audio_urls (use role "reference_image" for a reference job)
audio_urls without visual reference20003audio_urls must be used together with image_urls or video_urls
image_urls > 920003at most 9 image_urls allowed, got N
image_with_roles > 920003at most 9 image_with_roles allowed, got N
image_with_roles[i].role invalid20003image_with_roles[i].role must be first_frame, last_frame or reference_image, got "..."
video_urls > 320003at most 3 video_urls allowed, got N
video_urls clip frame out of range (300–6000px / 0.41–8.3MP / aspect 0.4–2.5)20003video_urls[i] resolution WxH is out of range
video_urls combined > 15s20003video_urls total duration X.XXs exceeds the 15s limit
audio_urls > 320003at most 3 audio_urls allowed, got N
audio_urls clip outside 2–15s20003audio_urls[i] duration X.XXs is out of range (must be 2–15s)
audio_urls combined > 15s20003audio_urls total duration X.XXs exceeds the 15s limit
image_urls / image_with_roles[].url entry not jpeg / png / webp / bmp / tiff / gif / heic / heif20003image_urls[i] format h264 is not supported (images must be jpeg, png, webp, bmp, tiff, gif, heic or heif)
video_urls clip not an mp4 / mov container20003video_urls[i] format matroska is not supported (videos must be mp4 or mov)
video_urls clip not H.264 / H.265, or its audio track not AAC / MP320003video_urls[i] video codec vp9 is not supported (must be H.264 or H.265/HEVC) / video_urls[i] audio track codec opus is not supported (must be AAC or MP3)
audio_urls entry not wav / mp320003audio_urls[i] format matroska is not supported (audio must be wav or mp3)
image_with_roles with a last_frame but no first_frame20003image_with_roles with a last_frame also needs a first_frame
image_with_roles mixing a frame role with reference_image20003image_with_roles cannot mix first_frame/last_frame with reference_image
duration outside 4–15 (or -1 on a tier without auto duration)20003duration: Too small: expected number to be >=4 / duration: Too big: expected number to be <=15
duration: -1 with resolution: 4k (content filter on)20003duration: -1 is not available at 4k with the content filter on — pick an explicit duration (4-15) for 4k, or use 1080p or lower for auto duration
1080p / 4k on a Fast variant20003resolution=1080p is not supported by <variant> (use doubao-seedance-2.0 or doubao-seedance-2.0-face)
tools[i].type not web_search20003tools[i].type must be "web_search", got "..."
content_filter: false from a website session20003content_filter cannot be disabled from the website. Submit this request with an API key instead.
Any URL field carrying a data: URI20003<field> entries must be public URLs; base64 data URIs are not supported
Reference video probe fails30002Could not determine source video duration for billing: ...

The full envelope is { "error": { "code", "message", "request_id" } } — see the Errors catalog for wire format and request_id correlation.

Pricing

Seedance 2.0 bills per second of video, at a rate that depends on three axes:

  • Variantdoubao-seedance-2.0-face or doubao-seedance-2.0-fast-face
  • Resolution480p / 720p / 1080p / 4k
  • Modetext (no media references) or ref (any of image_urls, image_with_roles, video_urls, audio_urls is set); ref rates are lower than text rates at every cell
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. Failed jobs are always refunded in full. Two rules make billable_seconds differ from the duration you asked for.

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 5-second source clip with duration: 6 bills 11 seconds, not 6; the same request without video_urls bills 6 seconds at the (higher) text rate.

2. duration: -1 reserves at 15 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 15-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 afford the video it actually produces: the reserve, not the final price, has to fit.

Recipes

Text-to-video:

{
  "model": "doubao-seedance-2.0-face",
  "prompt": "A kitten yawning at the camera, slow push-in, warm tones",
  "resolution": "720p",
  "size": "16:9",
  "duration": 5
}

First / last frame transition:

{
  "model": "doubao-seedance-2.0-face",
  "prompt": "Smooth transition from day to night",
  "image_with_roles": [
    { "url": "https://your-cdn.com/day.jpg",   "role": "first_frame" },
    { "url": "https://your-cdn.com/night.jpg", "role": "last_frame"  }
  ],
  "duration": 5
}

Reference clip plus reference audio (both billed: the clip's length on top of duration):

{
  "model": "doubao-seedance-2.0-face",
  "prompt": "A scene of a person speaking",
  "video_urls": ["https://your-cdn.com/reference.mp4"],
  "audio_urls": ["https://your-cdn.com/speech.wav"],
  "size": "16:9",
  "duration": 11
}

Continuous chain — ask for the last frame, then feed it to the next call as image_urls:

{
  "model": "doubao-seedance-2.0-face",
  "prompt": "The kitten approaches the camera",
  "image_urls": ["https://your-cdn.com/kitten-start.png"],
  "return_last_frame": true
}

Table of Contents