Image to Video
Generate a video from a first frame, optionally with a last frame (Seedance 2.5 image_to_video).
Seedance 2.5 starts the video from your image, and can also end on a last frame, generating what happens in between.
Create a task
https://api.nanoapi.ai/v1/tasksUse the shared create endpoint with model: "seedance-2.5". It usually responds in under 1 second and the cost is frozen within a few seconds; the video usually takes several minutes. Get the result once the task has finished.
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <API key>, see Authentication. |
Content-Type | Yes | application/json |
Idempotency-Key | No | A unique string for every new task, ideally a UUID (1–255 characters). See Preventing duplicate tasks. |
Body
| Parameter | Type | Required | Description |
|---|---|---|---|
model | string | Yes | seedance-2.5. |
mode | string | Yes | image_to_video. |
image_urls | string[] | Yes | 1–2 images: the first is the first frame, the second (optional) the last frame. Both must be landscape or both portrait (not checked when one is square), otherwise the task fails with invalid_media. Each is an http(s) link of at most 4096 characters that can be downloaded directly, not a private address. |
prompt | string | No | How the scene should change, at most 8000 characters. Refer to the images as @Image1 and @Image2, see Referring to files. |
resolution | string | Yes | 480p, 720p or 1080p. Sets the price. |
aspect_ratio | string | Yes | auto, 21:9, 16:9, 4:3, 1:1, 3:4 or 9:16. auto follows the first frame. |
duration | integer | Yes | Output length in seconds, 4–30. It's what you pay for, see Pricing. |
generate_audio | boolean | No | Whether the output has sound, default true. Same price either way. |
webhook_url | string | No | Notified when the task succeeds or fails: https, up to 2048 characters, not a private, loopback or reserved address. See Webhooks. |
video_url, video_urls and audio_urls aren't accepted: sending any of them returns 400 invalid_request with param set to it.
A first and a last frame, 720p, 5 seconds, aspect ratio auto (follows the first frame):
curl https://api.nanoapi.ai/v1/tasks \
-H "Authorization: Bearer $NANOAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.5",
"mode": "image_to_video",
"image_urls": [
"https://example.com/start.jpg",
"https://example.com/end.jpg"
],
"prompt": "The woman walks toward the camera",
"aspect_ratio": "auto",
"resolution": "720p",
"duration": 5
}'Response: 200 OK. data is the newly created task, with only these fields; each one is described in Create a task: Response. Keep data.id to get the result: once the task succeeds, the video is at data.outputs[0].url of the retrieved task or the webhook. The task can still fail after it's created (for example a file can't be downloaded), so go by what retrieving the task or the webhook tells you.
{
"code": 200,
"message": "success",
"data": {
"object": "task",
"id": "tk_01jbd2s8x4c6v9b3n5m7q1w4e8",
"model": "seedance-2.5",
"status": "queued",
"error": null,
"created_at": "2026-10-31T08:30:00Z"
}
}Pricing
cost = duration × price per second of the resolutionLoading the current prices…
Example: the request above (720p, 5 seconds) costs 5 × the 720p price per second.
Billed seconds are the duration you ask for, whether you send one image or two. Prices change, so read the current ones from GET /v1/products (the prices rows whose mode is this mode) instead of hard-coding them; billing.frozen on the retrieved task is what counts. All Seedance 2.5 prices: Seedance 2.5 → Pricing.
Errors
Create request errors: the request fails with an HTTP error and no task is created. Specific to this mode:
| Status | error.type | When | What to do |
|---|---|---|---|
400 | invalid_request | image_urls is missing or has more than 2 images (image_urls takes at most 2 images for mode image_to_video), video_url, video_urls or audio_urls was sent, or resolution, aspect_ratio or duration isn't one of the values above. param names the parameter. | Fix the parameter param names and send the request again. |
Other errors of the create endpoint (401, 402, 429 and so on): Create a task → Errors.
Task failures: the create request succeeded (200) and the task later turned failed. There's no HTTP status: the reason is the task's error.type, from retrieving the task or the webhook.
error.type | When | What to do |
|---|---|---|
invalid_media | An image can't be downloaded or read (corrupt or an unsupported format), or one frame is landscape and the other portrait (The first and last frames must have the same orientation: both landscape or both portrait.). Found when the files are downloaded, a few seconds after the task is submitted. The frozen amount is returned in full. | Use publicly downloadable images, both landscape or both portrait, and create the task again. |
Failure reasons shared by every mode (such as a balance too low for the task): Seedance 2.5 → Errors; all of them: Failure reasons.