
seedance-2.5/reference-to-video generates a new clip guided by one or more existing video clips — plus optional reference images and audio — instead of starting from a blank prompt or a single still frame. Feed it footage of a character, a set, or a camera move and a text prompt, and it produces new video that follows those references. This guide has a copy-pasteable curl and Python example, the exact input schema, pricing, and the errors you'll actually hit.
sk-...) from the API Keys dashboard..mp4). Optionally, URLs for a reference image and/or reference audio.requests installed (pip install requests).Every generation model on hiapi runs through the same unified endpoint, POST /v1/tasks. seedance-2.5/reference-to-video is called exactly like every other model — same auth header, same async task lifecycle — only model and input change. The model id is seedance-2.5/reference-to-video, with the /reference-to-video suffix; it is not an optional modality tag.
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.5/reference-to-video",
"input": {
"prompt": "the same character walks through a rain-lit street, neon reflections on wet pavement",
"reference_video_urls": ["https://your-cdn.example.com/reference-clip.mp4"],
"duration": 4,
"resolution": "720p"
}
}'
A successful call returns a task id immediately — generation itself happens asynchronously:
{"code":200,"data":{"taskId":"tk-hiapi-01XXXXXXXXXXXXXXXXXXXXXXXX"},"message":"success"}
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-01XXXXXXXXXXXXXXXXXXXXXXXX \
-H "Authorization: Bearer sk-<your-api-key>"
While the clip is rendering, status is "handling". Once it finishes:
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01XXXXXXXXXXXXXXXXXXXXXXXX",
"model": "seedance-2.5/reference-to-video",
"status": "success",
"storage": "temp",
"created": 1786327257,
"completed": 1786327501,
"output": [
{"artifactId": "72583", "type": "video", "url": "https://temp.hiapi.ai/.../result.mp4", "expireAt": 1786932195}
]
},
"message": "success"
}
output[0].url is a temporary, expiring link — expireAt is a Unix timestamp. Download or re-host the clip right away; don't store the hot link.
import time
import requests
API_KEY = "sk-<your-api-key>"
BASE = "https://api.hiapi.ai/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
def create_task(prompt, reference_video_urls, duration=4, resolution="720p", aspect_ratio=None):
payload = {
"model": "seedance-2.5/reference-to-video",
"input": {
"prompt": prompt,
"reference_video_urls": reference_video_urls,
"duration": duration,
"resolution": resolution,
},
}
if aspect_ratio:
payload["input"]["aspect_ratio"] = aspect_ratio
resp = requests.post(f"{BASE}/tasks", headers=HEADERS, json=payload, timeout=30)
resp.raise_for_status()
return resp.json()["data"]["taskId"]
def wait_for_result(task_id, interval=5, timeout=600):
deadline = time.time() + timeout
while time.time() < deadline:
resp = requests.get(f"{BASE}/tasks/{task_id}", headers=HEADERS, timeout=30)
resp.raise_for_status()
data = resp.json()["data"]
if data["status"] == "success":
return data["output"][0]["url"]
if data["status"] == "failed":
raise RuntimeError(f"task {task_id} failed: {data}")
time.sleep(interval)
raise TimeoutError(f"task {task_id} did not finish in {timeout}s")
task_id = create_task(
prompt="the same character walks through a rain-lit street, neon reflections on wet pavement",
reference_video_urls=["https://your-cdn.example.com/reference-clip.mp4"],
)
video_url = wait_for_result(task_id)
print(video_url)
reference_video_urls is the only required reference field (an array, minimum one URL — you can pass more than one clip). On top of it you can layer:
reference_image_urls — additional still-image references (array).reference_audio_urls — reference audio, for matching a voice or sound character (array).{
"model": "seedance-2.5/reference-to-video",
"input": {
"prompt": "same character and voice, now standing on a rooftop at sunset",
"reference_video_urls": [
"https://your-cdn.example.com/reference-clip-1.mp4",
"https://your-cdn.example.com/reference-clip-2.mp4"
],
"reference_image_urls": ["https://your-cdn.example.com/character-ref.jpg"],
"reference_audio_urls": ["https://your-cdn.example.com/voice-ref.mp3"],
"duration": 6,
"resolution": "720p",
"aspect_ratio": "9:16"
}
}
A reference input doesn't have to be freshly generated — any video, image, or audio file you already host at a public URL works. If you already have footage of the character or scene you want to keep consistent, point reference_video_urls at that instead of generating a new reference clip first.
aspect_ratio accepts one of: 16:9, 4:3, 1:1, 3:4, 9:16, 21:9, adaptive. This is a real, settable enum on this model — unlike some other Seedance modes, it is not locked to a single value.
The input schema is strict (additionalProperties: false) — sending any of these gets rejected before generation starts: seed, negative_prompt, ratio (use aspect_ratio), fps, audio_urls / image_urls (use the reference_-prefixed names).
duration: integer, 4–30 seconds.resolution: "480p" or "720p".{
"model": "seedance-2.5/reference-to-video",
"input": { "...": "..." },
"callback": { "url": "https://your-server.example.com/hiapi/callback", "when": "final" }
}
callback sits next to input, not inside it. when currently only accepts "final" — one POST when the task reaches a terminal state (success or failed), not incremental progress. If your callback endpoint isn't receiving that POST, check why hiapi task callbacks don't fire before assuming the task itself failed.
POST /v1/tasks doesn't take a client-supplied idempotency key — every call creates a new task and, for a paid model like this one, a new charge. If a request times out on your end, check whether you already captured a taskId from that attempt before retrying, rather than resubmitting blindly.
An invalid or under-permissioned key fails synchronously, before any task is created:
HTTP 401
{"error":{"code":"permission_denied","message":"This API key cannot use the selected model. Please check permissions or use another key. If the issue persists, contact support with request ID: <id>","request_id":"<id>","type":"hiapi_error"}}
permission_denied means the key exists but isn't authorized for seedance-2.5/reference-to-video specifically — check model access in the API Keys dashboard before assuming the request body is wrong.
Do I need a reference video, or can I use just an image?
reference_video_urls is required — at least one video URL. reference_image_urls and reference_audio_urls are additive, not substitutes.
Can I pass more than one reference video?
Yes, reference_video_urls is an array and accepts multiple clips.
What aspect ratios are supported?
16:9, 4:3, 1:1, 3:4, 9:16, 21:9, or adaptive.
Why did my request fail with a schema error even though the field name looked right?
The schema is strict and rejects unknown fields outright — common mistakes are sending seed, ratio instead of aspect_ratio, or image_urls/audio_urls instead of the reference_-prefixed names.
How much does a single clip cost? $0.2714 per output second at 720p — a 4-second clip is about $1.09. There's no separate cheaper tier for shorter clips.
Why did I get a 401 with a key I know is valid?
permission_denied means the key isn't scoped for this model, not that the key itself is invalid. Check the key's model permissions in the dashboard.