> ## Documentation Index
> Fetch the complete documentation index at: https://docs-vip.apigo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Seedance video generation example

> Import reference assets, generate a video with Seedance 2.0 and fetch the result.

## Flow

1. [CreateAssetGroup](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/create-asset-group.md) to create an asset group and get `Result.Id`.
2. [CreateAsset](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/create-asset.md) to import an asset from a URL and get `Result.Id`.
3. [GetAsset](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/get-asset.md) until `Status=Active`.
4. [Create a video generation task](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/create-task.md) that references the asset as `asset://<asset ID>`, and get `id`.
5. [Get the video generation task](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/get-task.md) until `status=succeeded`, then download `content.video_url`.

Steps 1–3 use HMAC-SHA256 signing and steps 4–5 use Bearer, both with the same API key.

## Complete example

Python 3.9+, standard library only.

```python seedance_demo.py theme={null}
import hashlib
import hmac
import json
import os
import time
from datetime import datetime, timezone
from urllib.error import HTTPError
from urllib.request import Request, urlopen

API_KEY = os.environ["APIGO_API_KEY"]
HOST = "api-vip.apigo.ai"
MODEL = "dreamina-seedance-2-0-260128"
IMAGE_URL = "https://ark-project.tos-cn-beijing.volces.com/doc_image/r2v_tea_pic1.jpg"


def send(request):
    try:
        with urlopen(request, timeout=60) as resp:
            return json.loads(resp.read())
    except HTTPError as e:
        raise SystemExit(f"HTTP {e.code}: {e.read().decode('utf-8', 'replace')}")


def asset_api(action, body):
    """Asset library management API: HMAC-SHA256 signing."""
    payload = json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
    x_date = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
    day = x_date[:8]
    query = f"Action={action}&Version=2024-01-01"
    body_hash = hashlib.sha256(payload).hexdigest()
    signed_headers = "content-type;host;x-content-sha256;x-date"
    canonical_request = "\n".join([
        "POST", "/", query,
        f"content-type:application/json\nhost:{HOST}\n"
        f"x-content-sha256:{body_hash}\nx-date:{x_date}\n",
        signed_headers, body_hash,
    ])
    scope = f"{day}/ap-southeast-1/ark/request"
    string_to_sign = "\n".join([
        "HMAC-SHA256", x_date, scope,
        hashlib.sha256(canonical_request.encode("utf-8")).hexdigest(),
    ])
    signing_key = API_KEY.encode("utf-8")
    for part in (day, "ap-southeast-1", "ark", "request"):
        signing_key = hmac.new(signing_key, part.encode("utf-8"), hashlib.sha256).digest()
    signature = hmac.new(signing_key, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()

    return send(Request(f"https://{HOST}/?{query}", data=payload, method="POST", headers={
        "Content-Type": "application/json",
        "X-Date": x_date,
        "X-Content-Sha256": body_hash,
        "Authorization": f"HMAC-SHA256 Credential={API_KEY}/{scope}, "
                         f"SignedHeaders={signed_headers}, Signature={signature}",
    }))["Result"]


def task_api(method, path, body=None):
    """Video generation API: Bearer authentication."""
    data = json.dumps(body).encode("utf-8") if body is not None else None
    return send(Request(f"https://{HOST}{path}", data=data, method=method, headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    }))


# 1. Create an asset group
group_id = asset_api("CreateAssetGroup", {"Name": "demo-assets", "GroupType": "AIGC"})["Id"]
print("group:", group_id)

# 2. Import an image asset
asset_id = asset_api("CreateAsset", {
    "GroupId": group_id,
    "URL": IMAGE_URL,
    "AssetType": "Image",
    "Name": "tea-reference",
})["Id"]
print("asset:", asset_id)

# 3. Wait until the asset is ready
while True:
    asset = asset_api("GetAsset", {"Id": asset_id})
    print("asset status:", asset["Status"])
    if asset["Status"] == "Active":
        break
    if asset["Status"] == "Failed":
        raise SystemExit(f"Asset processing failed: {asset.get('Error')}")
    time.sleep(5)

# 4. Create a video generation task
task_id = task_api("POST", "/api/v3/contents/generations/tasks", {
    "model": MODEL,
    "content": [
        {"type": "text", "text": "Steam slowly rises from the cup in image 1 as the camera pushes in slightly."},
        {"type": "image_url", "role": "reference_image", "image_url": {"url": f"asset://{asset_id}"}},
    ],
    "duration": 5,
    "resolution": "720p",
    "ratio": "16:9",
    "generate_audio": False,
    "watermark": False,
})["id"]
print("task:", task_id)

# 5. Poll for the result
while True:
    task = task_api("GET", f"/api/v3/contents/generations/tasks/{task_id}")
    print("task status:", task["status"])
    if task["status"] not in ("queued", "running"):
        break
    time.sleep(10)

if task["status"] != "succeeded":
    raise SystemExit(f"Task ended: {task['status']} {task.get('error')}")

with urlopen(task["content"]["video_url"], timeout=300) as resp, open("output.mp4", "wb") as f:
    f.write(resp.read())
print("saved: output.mp4")
```

Run:

```bash theme={null}
export APIGO_API_KEY="your API key"
python3 seedance_demo.py
```

## cURL example

The asset library management API requires a signature and cannot be called with hand-written cURL. See [Authentication and conventions](https://docs-vip.apigo.ai/en/api-reference/endpoints/seedance/asset-overview.md#authentication) for signing. The video generation API uses Bearer and can be called directly:

```bash theme={null}
curl https://api-vip.apigo.ai/api/v3/contents/generations/tasks \
  -H "Authorization: Bearer $APIGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "dreamina-seedance-2-0-260128",
    "content": [
      {"type": "text", "text": "Steam slowly rises from the cup in image 1 as the camera pushes in slightly."},
      {"type": "image_url", "role": "reference_image", "image_url": {"url": "asset://<asset ID>"}}
    ],
    "duration": 5,
    "resolution": "720p",
    "ratio": "16:9",
    "generate_audio": false,
    "watermark": false
  }'
```

```bash theme={null}
curl https://api-vip.apigo.ai/api/v3/contents/generations/tasks/<task ID> \
  -H "Authorization: Bearer $APIGO_API_KEY"
```

## Other reference media combinations

> [tab] Image + audio
>
> Audio must be combined with an image or video. Set `generate_audio` to `true` when using reference audio.
>
> ```json theme={null}
> {
>   "model": "dreamina-seedance-2-0-260128",
>   "content": [
>     {"type": "text", "text": "Use image 1 as the visual reference and audio 1 as the soundtrack. Do not add dialogue."},
>     {"type": "image_url", "role": "reference_image", "image_url": {"url": "asset://<image asset ID>"}},
>     {"type": "audio_url", "role": "reference_audio", "audio_url": {"url": "asset://<audio asset ID>"}}
>   ],
>   "duration": 5,
>   "ratio": "16:9",
>   "generate_audio": true,
>   "watermark": false
> }
> ```

> [tab] Video (with original sound)
>
> The reference video must contain audible sound. Set `generate_audio` to `true`.
>
> ```json theme={null}
> {
>   "model": "dreamina-seedance-2-0-260128",
>   "content": [
>     {"type": "text", "text": "Use video 1 as the visual and sound reference, keeping the subject, scene and original sound."},
>     {"type": "video_url", "role": "reference_video", "video_url": {"url": "asset://<video asset ID>"}}
>   ],
>   "duration": 5,
>   "ratio": "16:9",
>   "generate_audio": true,
>   "watermark": false
> }
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.