RelayDanceRelayDance
HomeModelsPricingDocsGet API Key

Docs / Examples / Image-to-Video

Image-to-Video

Animate a still image into a short clip. The image goes into metadata.content[] as a reference_image, and the prompt cites it as @image1.

#Workflow

  1. Get a URL for your image: upload it via POST /v1/files, or use any public URL you already host
  2. Submit POST /v1/video/generations with the image in metadata.content[] and a prompt citing @image1
  3. Poll GET /v1/video/generations/{task_id} until succeeded, or set metadata.callback_url and wait for the webhook
  4. Download the clip from the url field

#cURL

terminalbash
# 1) Submit
curl https://relaydance.com/v1/video/generations \
  -H "Authorization: Bearer $RELAYDANCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-1-5-pro-with-audio",
    "prompt": "@image1 comes alive: gentle camera pull-back, hair moving in a soft breeze",
    "seconds": "5",
    "metadata": {
      "ratio": "16:9",
      "resolution": "720p",
      "content": [
        {
          "type": "image_url",
          "image_url": { "url": "https://example.com/portrait.jpg" },
          "role": "reference_image"
        }
      ]
    }
  }'
# -> { "task_id": "...", "status": "submitted" }

# 2) Poll (replace TASK_ID)
curl https://relaydance.com/v1/video/generations/TASK_ID \
  -H "Authorization: Bearer $RELAYDANCE_API_KEY"

#Python (upload + submit + poll)

image_to_video.pypython
import requests, os, time

BASE = "https://relaydance.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['RELAYDANCE_API_KEY']}"}

# 1) Upload the local image (skip if you already have a public URL)
upload = requests.post(
    f"{BASE}/files",
    headers=HEADERS,
    files={"file": open("portrait.jpg", "rb")},
)
image_url = upload.json()["url"]

# 2) Submit the video task
submit = requests.post(
    f"{BASE}/video/generations",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={
        "model": "seedance-1-5-pro-with-audio",
        "prompt": "@image1 comes alive: gentle camera pull-back, soft natural light",
        "seconds": "5",
        "metadata": {
            "ratio": "16:9",
            "resolution": "720p",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {"url": image_url},
                    "role": "reference_image",
                }
            ],
        },
    },
)
task_id = submit.json()["task_id"]

# 3) Poll until the clip is ready
while True:
    task = requests.get(f"{BASE}/video/generations/{task_id}", headers=HEADERS).json()
    if task["status"] == "succeeded":
        print("Video:", task["url"])
        break
    if task["status"] == "failed":
        raise RuntimeError(task)
    time.sleep(5)

#Node.js / TypeScript

imageToVideo.tstypescript
const BASE = "https://relaydance.com/v1";
const KEY = process.env.RELAYDANCE_API_KEY;

// 1) Submit with a hosted image URL
const submit = await fetch(`${BASE}/video/generations`, {
  method: "POST",
  headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "seedance-1-5-pro-with-audio",
    prompt: "@image1 comes alive: gentle camera pull-back, soft natural light",
    seconds: "5",
    metadata: {
      ratio: "16:9",
      resolution: "720p",
      content: [
        {
          type: "image_url",
          image_url: { url: "https://example.com/portrait.jpg" },
          role: "reference_image",
        },
      ],
    },
  }),
});
const { task_id } = await submit.json();

// 2) Poll
while (true) {
  const r = await fetch(`${BASE}/video/generations/${task_id}`, {
    headers: { Authorization: `Bearer ${KEY}` },
  });
  const task = await r.json();
  if (task.status === "succeeded") { console.log("Video:", task.url); break; }
  if (task.status === "failed") throw new Error(JSON.stringify(task));
  await new Promise((s) => setTimeout(s, 5000));
}
Prefer webhooks in production: add callback_url inside metadata and the final task JSON is POSTed to you, no polling loop needed.

#Model choices

ModelWhy pick it
seedance-1-5-pro-with-audioImage-to-video with a generated soundtrack
seedance-1-5-pro-no-audioSame family, silent output
doubao-seedance-2-0-1080pHighest fidelity, multi-reference fusion
happyhorse-1.0-i2vDedicated image-to-video model
Up to 9 reference images per request, cited as @image1 to @imageN in content[] order. Reference images are mutually exclusive with first/last-frame mode. See Video Generation for the full schema.