Public Model / seedance
Seedance 2 API pricing
Estimate your video's cost, generate it through the API, and download the result. Explore current rates, a video demo, and a complete Python example.
- Availability
- Available
- Tasks
- Create Video
- Published rates from
- $0.0575
Seedance 2 · video demo
From orbit to a field-side selfie
A rapid dive through clouds and patchwork fields lands on a handheld selfie in golden wheat. The prompt gives each scene its own timing, camera direction, and dialogue.
- Video length
- 5 seconds
- Frame size
- 720 × 1280
- Format
- 9:16 · audio
The original prompt
"'SCENE 1: Earth from space, camera rapidly zooming in continuously — punching through white clouds, green landscape appears, patchwork fields getting closer, golden wheat field rushing up, camera keeps diving toward a single person standing in the middle of the field — a voiceover says "did you know that most people have no idea about this" — 2 seconds. SCENE 2: Seamless transition landing on a young guy in a white t-shirt standing in the wheat field, waist-high golden stalks around him, wind blowing his hair, he's already mid-sentence looking directly at a front-facing phone camera held at arm's length saying "let me explain why this changes everything", wide eyes, leaning into the camera, gesturing with his free hand. Bright afternoon sunlight, blue sky, raw selfie camera quality — 3 seconds. "Try this prompt through the API →
Request calculator
Configure Seedance 2
Controls and rates come directly from the checked public catalog.
Interactive calculator
Price a direct generation
Choose a task, configure its inputs, and see the current catalog price.
Step 1
Choose a generation type
Step 2
Configure generation
Step 3
Reference total
- Generation
- $1.648 seconds x $0.205
- Minimum request
- $0.345
The API estimate for your exact request is authoritative before paid work starts.
Worked costs
What would your request cost?
Estimate a new text-to-video request with audio and no reference media. These catalog examples are rounded to the nearest cent.
Short draft
$0.38
4 seconds · 480p · one output
Five-second vertical video
$1.03
5 seconds · 720p · one output
Higher-resolution video
$2.55
5 seconds · 1080p · one output
Duration and resolution change the price. Reference-video requests use a different rate and include total reference-video length in billable duration. The API estimate for your exact inputs is authoritative.
Python quickstart
From prompt to a downloaded video.
Use the original prompt in a new five-second, 720p Seedance 2 request with audio. The script estimates the cost, creates a generation, waits for it to finish, and saves the video. Each generation can produce a different result.
- 1. Get API accessCreate a Console workspace, add prepaid balance, and create an organization API key. Generation requires enough available balance for the current estimate.
- 2. Check the estimateDownload seedance-2.py and run it with uv. The default command only estimates the request and needs no API key.
- 3. Generate when readySet ENTIREFEED_API_KEY, pass a unique idempotency key, and confirm the displayed estimate. Keep that key to recover the same request after a network error.
# Requires uv: https://docs.astral.sh/uv/getting-started/installation/
# Free estimate; no API key required
uv run seedance-2.py
# Paid generation after confirmation
export ENTIREFEED_API_KEY="your-organization-api-key"
uv run seedance-2.py --generate --idempotency-key earth-selfie-001
# Resume an existing generation without creating another
uv run seedance-2.py --resume gen_YOUR_GENERATION_IDView the complete Python script
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests>=2.32,<3"]
# ///
"""Default: free estimate only. Paid creation requires --generate and confirmation."""
import argparse
import json
import os
import re
import time
from pathlib import Path
from urllib.parse import urljoin, urlparse
import requests
API_BASE = "https://api.entirefeed.com/v1"
PAYLOAD = json.loads("{\"task\":\"video.create\",\"model\":\"seedance-2\",\"input\":{\"prompt\":\"\\\"'SCENE 1: Earth from space, camera rapidly zooming in continuously — punching through white clouds, green landscape appears, patchwork fields getting closer, golden wheat field rushing up, camera keeps diving toward a single person standing in the middle of the field — a voiceover says \\\"did you know that most people have no idea about this\\\" — 2 seconds. SCENE 2: Seamless transition landing on a young guy in a white t-shirt standing in the wheat field, waist-high golden stalks around him, wind blowing his hair, he's already mid-sentence looking directly at a front-facing phone camera held at arm's length saying \\\"let me explain why this changes everything\\\", wide eyes, leaning into the camera, gesturing with his free hand. Bright afternoon sunlight, blue sky, raw selfie camera quality — 3 seconds. \\\"\",\"duration_seconds\":5,\"resolution\":\"720p\",\"aspect_ratio\":\"9:16\",\"generate_audio\":true}}")
def api(method, path, *, key=None, **kwargs):
# Never forward the API key to a media download or another origin.
url = urljoin(API_BASE + "/", path)
if urlparse(url).netloc != urlparse(API_BASE).netloc or urlparse(url).scheme != "https":
raise ValueError("Unexpected API URL")
headers = kwargs.pop("headers", {})
if key:
headers["Authorization"] = f"Bearer {key}"
response = requests.request(method, url, headers=headers, timeout=60, **kwargs)
response.raise_for_status()
return response.json()
def main():
parser = argparse.ArgumentParser(description="Estimate, generate, and download a Seedance 2 video.")
action = parser.add_mutually_exclusive_group()
action.add_argument("--generate", action="store_true", help="Enable a paid request after confirmation.")
parser.add_argument("--idempotency-key", help="Reuse this key to recover the same intended request.")
action.add_argument("--resume", metavar="GENERATION_ID", help="Read an existing generation; creates no new work.")
parser.add_argument("--output", type=Path, default=Path("seedance-demo.mp4"))
args = parser.parse_args()
key = os.environ.get("ENTIREFEED_API_KEY")
if (args.generate or args.resume) and args.output.exists():
raise SystemExit(f"{args.output} already exists. Choose another --output path.")
if args.resume:
if not key:
raise SystemExit("Set ENTIREFEED_API_KEY to resume.")
if not re.fullmatch(r"gen_[a-zA-Z0-9]+", args.resume):
raise SystemExit("Expected a gen_... generation ID.")
current = api("GET", f"generations/{args.resume}", key=key)
status_url = f"{API_BASE}/generations/{args.resume}"
else:
estimate = api("POST", "estimate", json=PAYLOAD)
print("Current estimate:", json.dumps(estimate["estimated_cost"], indent=2))
if not args.generate:
print("Estimate only: no media generated and no balance spent.")
print("To generate, add --generate --idempotency-key YOUR_UNIQUE_REQUEST_KEY.")
return
if not key or not args.idempotency_key:
raise SystemExit("Set ENTIREFEED_API_KEY and pass --idempotency-key before generating.")
print("Creating reserves balance using the current price, which can change after this estimate.")
if input("Type GENERATE to create this paid request: ").strip() != "GENERATE":
print("No generation created.")
return
print(f"Request key: {args.idempotency_key}. Keep it to recover this request after a network error.")
current = api(
"POST", "generations", key=key, json=PAYLOAD,
headers={"Idempotency-Key": args.idempotency_key},
)
status_url = current["links"]["self"]
generation_id = current["id"]
print(f"Generation: {generation_id}")
print(f"Resume with: uv run seedance-2.py --resume {generation_id}")
deadline = time.monotonic() + 900
# Always fetch the complete record, even if create returned an immediate success.
while True:
current = api("GET", status_url, key=key)
status = current["status"]
print("Status:", status)
if status not in {"queued", "running"}:
break
if time.monotonic() >= deadline:
raise SystemExit(f"Still active. Resume {generation_id}; do not create another request.")
time.sleep(5)
if current["status"] != "succeeded":
print(json.dumps(current.get("error"), indent=2))
print("Usage:", json.dumps(current.get("usage"), indent=2))
raise SystemExit(f"Stopped at {current['status']}. See Console for details.")
assets = (current.get("output") or {}).get("assets", [])
video = next((asset for asset in assets if asset.get("type") == "video"), None)
if not video:
raise SystemExit("Succeeded, but no video asset was returned.")
if urlparse(video["url"]).scheme != "https":
raise SystemExit("Unexpected download URL.")
# A separate request keeps the API credential off the asset host.
partial = args.output.with_name(args.output.name + ".part")
# Only remove a partial file created by this attempt if the download fails.
output = partial.open("xb")
try:
with output:
with requests.get(video["url"], stream=True, timeout=120) as response:
response.raise_for_status()
for chunk in response.iter_content(chunk_size=1024 * 1024):
output.write(chunk)
except (requests.RequestException, OSError):
partial.unlink(missing_ok=True)
raise
partial.rename(args.output)
print("Saved:", args.output)
print("Usage:", json.dumps(current.get("usage"), indent=2))
if __name__ == "__main__":
try:
main()
except requests.RequestException as error:
raise SystemExit(
f"Request failed: {error}. Resume the generation ID if available; "
"otherwise reuse the same idempotency key and unchanged payload."
) from error
The script stops on failed, cancelled, or manual-review status. A deliberate retry is new paid work. Read the retry guide before creating another generation.
Before your first request
Can I check the price before creating an account?
Yes. POST /v1/estimate is public and requires no API key. It creates no media and spends no balance. Creating media requires an API key and sufficient prepaid balance.
How long does generation take?
Read the generation status while the request is queued or running. The script polls until it finishes and prints a resume command if it takes longer than its 15-minute waiting window. That window is a script setting, not a completion-time promise.
What happens if a generation fails or I retry it?
Failure or cancellation does not necessarily mean no billable work occurred. Check the returned usage and Console details. Reusing an idempotency key recovers the same intended request; a deliberate retry creates a new generation and balance reservation.
Can I add image or video references?
Seedance 2 accepts reference images, videos, audio, and first/last frames through its request controls. Estimate again after changing the inputs; reference-video duration affects the cost.
Where do I get the finished video?
A successful generation returns output.assets. The script downloads the video asset to seedance-demo.mp4. Asset URLs can expire, so save the finished file to your own storage.
Best fit
Use Seedance 2 when a production needs the widest Seedance resolution range or a reference-led clip with explicit duration pricing.
Use cases
- 4K product sequences
- Reference-video recreation
Know before building
- Reference-video requests bill against output duration plus total reference-video length.
Generated contract
Tasks, controls, and rates
Published rates
- video.create
- Varies by output duration, resolution, total reference video length
- $0.0575 / second$0.345 minimum
Request controls
Lifecycle: queued -> running -> succeeded -> failed -> cancelled -> manual_review
Output fields: assets