> ## Documentation Index
> Fetch the complete documentation index at: https://oxenai-eric-revamp-getting-started.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Seedance 2.0 - Image to Video

> Image-to-video with optional start-to-end frame transitions, flexible duration and aspect ratio, resolution up to 1080p, and optional synchronized audio.

<CardGroup cols={1}>
  <Card title="Try Seedance 2.0 - Image to Video in the Workbench" icon="flask" href="https://www.oxen.ai/ai/workbench?model=bytedance-seedance-2-0-image-to-video">
    Run this model interactively, tune parameters, and compare outputs.
  </Card>
</CardGroup>

**Model ID:** `bytedance-seedance-2-0-image-to-video`

ByteDance Seedance 2 image-to-video animates a starting frame from a text motion prompt, with optional end-frame control for transitions. It supports 480p, 720p, or 1080p output, durations from 4–15 seconds or automatic length from the prompt, multiple aspect ratios (including auto from the input image), and synchronized audio (effects, ambience, and lip-synced speech).

## Example request

<Tip>
  Use the [Workbench](https://www.oxen.ai/ai/workbench?model=bytedance-seedance-2-0-image-to-video) 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.
</Tip>

<Tabs>
  <Tab title="Sync">
    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](/inference-api/reference/video_generation) for more details.

    <Tabs>
      <Tab title="Minimal">
        <CodeGroup>
          ```bash cURL theme={null}
          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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }'
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          response.raise_for_status()
          print(response.json())
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Basic parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }'
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          response.raise_for_status()
          print(response.json())
          ```
        </CodeGroup>
      </Tab>

      <Tab title="All parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "resolution": "720p",
            "duration": "auto",
            "aspect_ratio": "auto",
            "generate_audio": true
          }'
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "resolution": "720p",
                  "duration": "auto",
                  "aspect_ratio": "auto",
                  "generate_audio": true
              },
          )
          response.raise_for_status()
          print(response.json())
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Async">
    See the [async queue reference](/inference-api/reference/async_queue) for more details.

    <Tabs>
      <Tab title="Minimal">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }' | jq -r '.generations[0].generation_id')

          # Poll the single generation until it 404s (terminal state).
          while curl -s -o /dev/null -w "%{http_code}" \
              -H "Authorization: Bearer $OXEN_API_KEY" \
              "https://hub.oxen.ai/api/ai/queue/$GEN_ID" | grep -q "^200$"; do
            sleep 5
          done
          echo "Done. See the 'Async with SSE' tab to receive the result URL."
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          enqueue.raise_for_status()
          generation_id = enqueue.json()["generations"][0]["generation_id"]

          while True:
              resp = requests.get(
                  f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
                  headers=HEADERS,
              )
              if resp.status_code == 404:
                  break
              time.sleep(5)
          print("Done. See the 'Async with SSE' tab to receive the result URL.")
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Basic parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }' | jq -r '.generations[0].generation_id')

          # Poll the single generation until it 404s (terminal state).
          while curl -s -o /dev/null -w "%{http_code}" \
              -H "Authorization: Bearer $OXEN_API_KEY" \
              "https://hub.oxen.ai/api/ai/queue/$GEN_ID" | grep -q "^200$"; do
            sleep 5
          done
          echo "Done. See the 'Async with SSE' tab to receive the result URL."
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          enqueue.raise_for_status()
          generation_id = enqueue.json()["generations"][0]["generation_id"]

          while True:
              resp = requests.get(
                  f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
                  headers=HEADERS,
              )
              if resp.status_code == 404:
                  break
              time.sleep(5)
          print("Done. See the 'Async with SSE' tab to receive the result URL.")
          ```
        </CodeGroup>
      </Tab>

      <Tab title="All parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "resolution": "720p",
            "duration": "auto",
            "aspect_ratio": "auto",
            "generate_audio": true
          }' | jq -r '.generations[0].generation_id')

          # Poll the single generation until it 404s (terminal state).
          while curl -s -o /dev/null -w "%{http_code}" \
              -H "Authorization: Bearer $OXEN_API_KEY" \
              "https://hub.oxen.ai/api/ai/queue/$GEN_ID" | grep -q "^200$"; do
            sleep 5
          done
          echo "Done. See the 'Async with SSE' tab to receive the result URL."
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "resolution": "720p",
                  "duration": "auto",
                  "aspect_ratio": "auto",
                  "generate_audio": true
              },
          )
          enqueue.raise_for_status()
          generation_id = enqueue.json()["generations"][0]["generation_id"]

          while True:
              resp = requests.get(
                  f"https://hub.oxen.ai/api/ai/queue/{generation_id}",
                  headers=HEADERS,
              )
              if resp.status_code == 404:
                  break
              time.sleep(5)
          print("Done. See the 'Async with SSE' tab to receive the result URL.")
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="Async with SSE">
    See the [async queue reference](/inference-api/reference/async_queue) for more details.

    <Tabs>
      <Tab title="Minimal">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }' | 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 .
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          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
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Basic parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
          }' | 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 .
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png"
              },
          )
          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
          ```
        </CodeGroup>
      </Tab>

      <Tab title="All parameters">
        <CodeGroup>
          ```bash cURL theme={null}
          # 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-0-image-to-video",
            "prompt": "<prompt>",
            "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
            "resolution": "720p",
            "duration": "auto",
            "aspect_ratio": "auto",
            "generate_audio": true
          }' | 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 .
          ```

          ```python Python theme={null}
          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-0-image-to-video",
                  "prompt": "<prompt>",
                  "input_image": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "tail_image_url": "https://hub.oxen.ai/api/repos/elau/assets/file/main/bloxy/bloxy_cropped_512x512.png",
                  "resolution": "720p",
                  "duration": "auto",
                  "aspect_ratio": "auto",
                  "generate_audio": true
              },
          )
          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
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

## Fetch model details

The [models endpoint](/inference-api/reference/models/overview) returns the full model object, including its `json_request_schema`.

```bash theme={null}
curl -H "Authorization: Bearer $OXEN_API_KEY" https://hub.oxen.ai/api/ai/models/bytedance-seedance-2-0-image-to-video
```

## Request parameters

### Required parameters

| Field         | Type     | Default | Description                                                                                                 |
| ------------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `prompt`      | `string` | —       | The text prompt describing the desired motion and action for the video.                                     |
| `input_image` | `string` | —       | The URL of the starting frame image to animate. Supported formats: JPEG, PNG, WebP. Max 30 MB. Format: uri. |

### Optional parameters

| Field            | Type      | Default  | Description                                                                                                                                                                                                                      |
| ---------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tail_image_url` | `string`  | —        | The URL of the image to use as the last frame of the video. When provided, the generated video will transition from the starting image to this ending image. Supported formats: JPEG, PNG, WebP. Max 30 MB. Format: uri.         |
| `resolution`     | `string`  | `"720p"` | Video resolution - 480p for faster generation, 720p for balance, 1080p for highest quality. One of: 480p, 720p, 1080p.                                                                                                           |
| `duration`       | `string`  | `"auto"` | Duration of the video in seconds. Supports 4 to 15 seconds, or auto to let the model decide based on the prompt. One of: auto, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15.                                                         |
| `aspect_ratio`   | `string`  | `"auto"` | The aspect ratio of the generated video. Use 16:9 for landscape, 9:16 for portrait/vertical, 1:1 for square, 21:9 for ultrawide cinematic, or auto to infer from the input image. One of: auto, 21:9, 16:9, 4:3, 1:1, 3:4, 9:16. |
| `generate_audio` | `boolean` | `true`   | Whether to generate synchronized audio for the video, including sound effects, ambient sounds, and lip-synced speech.                                                                                                            |
| `seed`           | `integer` | —        | Random seed for reproducibility. Note that results may still vary slightly even with the same seed.                                                                                                                              |
