Try Seedance 2.5 - Text to Video in the Workbench
Run this model interactively, tune parameters, and compare outputs.
bytedance-seedance-2-5-text-to-video
ByteDance Seedance 2.5 generates video from a text prompt, with synchronized audio on by default. Supports 480p, 720p, and 1080p output (1080p uses 10-bit color and H.265/HEVC encoding), durations from 4 to 30 seconds, and multiple aspect ratios.
Draft mode renders a quick 480p preview for checking the scene, motion, and prompt. Its draft task ID then renders the final 1080p video with the same prompt, media, and settings, and stays valid for seven days after the draft is created.
Example request
Use the Workbench as a request builder: configure parameters for this model in the UI, then open the API tab to copy the exact cURL or Python call.
- Sync
- Async
- Async with SSE
This blocks until the video is ready (typically 5-15 minutes). Prefer Async or Async with SSE for anything beyond quick experimentation.See the video generation reference for more details.
- Minimal
- All parameters
curl -X POST https://hub.oxen.ai/api/ai/videos/generate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
}'
import os
import requests
response = requests.post(
"https://hub.oxen.ai/api/ai/videos/generate",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['OXEN_API_KEY']}",
},
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
},
)
response.raise_for_status()
print(response.json())
curl -X POST https://hub.oxen.ai/api/ai/videos/generate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
}'
import os
import requests
response = requests.post(
"https://hub.oxen.ai/api/ai/videos/generate",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['OXEN_API_KEY']}",
},
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
},
)
response.raise_for_status()
print(response.json())
See the async queue reference for more details.
- Minimal
- All parameters
# Enqueue, capture the generation id.
GEN_ID=$(curl -s -X POST https://hub.oxen.ai/api/ai/queue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
}' | jq -r '.generations[0].generation_id')
# Poll until the generation reaches a terminal status.
while true; do
STATUS=$(curl -s -H "Authorization: Bearer $OXEN_API_KEY" \
"https://hub.oxen.ai/api/ai/queue/$GEN_ID" | jq -r '.status')
echo "Status: $STATUS"
case $STATUS in succeeded|failed|cancelled) break;; esac
sleep 5
done
# Print the result.
curl -s -H "Authorization: Bearer $OXEN_API_KEY" \
"https://hub.oxen.ai/api/ai/queue/$GEN_ID" | jq .
import os
import time
import requests
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['OXEN_API_KEY']}",
}
enqueue = requests.post(
"https://hub.oxen.ai/api/ai/queue",
headers=HEADERS,
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
},
)
enqueue.raise_for_status()
generation_id = enqueue.json()["generations"][0]["generation_id"]
while True:
data = requests.get(
f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
headers=HEADERS,
).json()
if data["status"] in {"succeeded", "failed", "cancelled"}:
break
time.sleep(5)
if data["status"] == "succeeded":
print(f"Result: {data['result_url']}")
else:
print(f"Generation {data['status']}: {data.get('error_message')}")
# Enqueue, capture the generation id.
GEN_ID=$(curl -s -X POST https://hub.oxen.ai/api/ai/queue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
}' | jq -r '.generations[0].generation_id')
# Poll until the generation reaches a terminal status.
while true; do
STATUS=$(curl -s -H "Authorization: Bearer $OXEN_API_KEY" \
"https://hub.oxen.ai/api/ai/queue/$GEN_ID" | jq -r '.status')
echo "Status: $STATUS"
case $STATUS in succeeded|failed|cancelled) break;; esac
sleep 5
done
# Print the result.
curl -s -H "Authorization: Bearer $OXEN_API_KEY" \
"https://hub.oxen.ai/api/ai/queue/$GEN_ID" | jq .
import os
import time
import requests
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Bearer {os.environ['OXEN_API_KEY']}",
}
enqueue = requests.post(
"https://hub.oxen.ai/api/ai/queue",
headers=HEADERS,
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
},
)
enqueue.raise_for_status()
generation_id = enqueue.json()["generations"][0]["generation_id"]
while True:
data = requests.get(
f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
headers=HEADERS,
).json()
if data["status"] in {"succeeded", "failed", "cancelled"}:
break
time.sleep(5)
if data["status"] == "succeeded":
print(f"Result: {data['result_url']}")
else:
print(f"Generation {data['status']}: {data.get('error_message')}")
See the async queue reference for more details.
- Minimal
- All parameters
# Enqueue, capture the generation id.
GEN_ID=$(curl -s -X POST https://hub.oxen.ai/api/ai/queue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
}' | jq -r '.generations[0].generation_id')
# Stream the SSE channel, grab the data line that follows a
# media_generation_completed event for our id, and pretty-print it.
curl -sN -H "Authorization: Bearer $OXEN_API_KEY" https://hub.oxen.ai/api/events \
| awk -v id="$GEN_ID" '
/^event: media_generation_completed$/ { expect=1; next }
/^data: / && expect {
payload = substr($0, 7)
if (index(payload, "\"generation_id\":\"" id "\"")) { print payload; exit }
expect = 0
}
' | jq .
import json
import os
import requests
API_KEY = os.environ["OXEN_API_KEY"]
AUTH = {"Authorization": f"Bearer {API_KEY}"}
enqueue = requests.post(
"https://hub.oxen.ai/api/ai/queue",
headers={**AUTH, "Content-Type": "application/json"},
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>"
},
)
enqueue.raise_for_status()
generation_id = enqueue.json()["generations"][0]["generation_id"]
with requests.get(
"https://hub.oxen.ai/api/events",
headers=AUTH,
stream=True,
) as stream:
event_name = None
for line in stream.iter_lines(decode_unicode=True):
if line.startswith("event: "):
event_name = line.removeprefix("event: ")
elif line.startswith("data: ") and event_name == "media_generation_completed":
payload = json.loads(line.removeprefix("data: "))
if payload.get("generation_id") == generation_id:
print(payload)
break
# Enqueue, capture the generation id.
GEN_ID=$(curl -s -X POST https://hub.oxen.ai/api/ai/queue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OXEN_API_KEY" \
-d '{
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
}' | jq -r '.generations[0].generation_id')
# Stream the SSE channel, grab the data line that follows a
# media_generation_completed event for our id, and pretty-print it.
curl -sN -H "Authorization: Bearer $OXEN_API_KEY" https://hub.oxen.ai/api/events \
| awk -v id="$GEN_ID" '
/^event: media_generation_completed$/ { expect=1; next }
/^data: / && expect {
payload = substr($0, 7)
if (index(payload, "\"generation_id\":\"" id "\"")) { print payload; exit }
expect = 0
}
' | jq .
import json
import os
import requests
API_KEY = os.environ["OXEN_API_KEY"]
AUTH = {"Authorization": f"Bearer {API_KEY}"}
enqueue = requests.post(
"https://hub.oxen.ai/api/ai/queue",
headers={**AUTH, "Content-Type": "application/json"},
json={
"model": "bytedance-seedance-2-5-text-to-video",
"prompt": "<prompt>",
"generate_audio": true,
"aspect_ratio": "16:9",
"duration": "auto",
"resolution": "720p",
"draft": false,
"output_format": "mp4",
"watermark": false
},
)
enqueue.raise_for_status()
generation_id = enqueue.json()["generations"][0]["generation_id"]
with requests.get(
"https://hub.oxen.ai/api/events",
headers=AUTH,
stream=True,
) as stream:
event_name = None
for line in stream.iter_lines(decode_unicode=True):
if line.startswith("event: "):
event_name = line.removeprefix("event: ")
elif line.startswith("data: ") and event_name == "media_generation_completed":
payload = json.loads(line.removeprefix("data: "))
if payload.get("generation_id") == generation_id:
print(payload)
break
Fetch model details
The models endpoint returns the full model object, including itsjson_request_schema.
curl -H "Authorization: Bearer $OXEN_API_KEY" https://hub.oxen.ai/api/ai/models/bytedance-seedance-2-5-text-to-video
Request parameters
Required parameters
| Field | Type | Default | Description |
|---|---|---|---|
prompt | string | — | The text prompt used to generate the video. |
Optional parameters
| Field | Type | Default | Description |
|---|---|---|---|
generate_audio | boolean | true | Whether to generate synchronized audio for the video, including sound effects, ambient sounds, and lip-synced speech. |
aspect_ratio | string | "16:9" | Aspect Ratio One of: adaptive, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16. |
duration | ['integer', 'string'] | "auto" | Duration Range: 4 – 30. |
resolution | string | "720p" | Resolution One of: 480p, 720p, 1080p. |
draft | boolean | false | Generate a quick 480p preview to check the scene and motion before the full-quality render. |
draft_task_id | string | — | Render the final 1080p video from a draft, reusing its prompt, media, and settings. Draft task IDs expire seven days after the draft is created. |
output_format | string | "mp4" | Output video format. mp4 for broad compatibility, mov for high color precision in professional post-production workflows. One of: mp4, mov. |
watermark | boolean | false | Whether to add an ‘AI generated’ watermark to the output. |