> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Seedance 2

POST https://api.beatapi.io/v1/videos/tasks
Content-Type: application/json

Generate 4–15 second videos at 480p, 720p, 1080p or 4K from text, a first and last frame, or up to 9 images, 3 videos and 3 audio clips as references.- Asynchronous: the create call returns a task ID; the video arrives when the task succeeds (usually a few minutes).
- Four ways in: text only, a first frame, a first and last frame, or reference images, videos and audio in any mix (audio needs at least one image or video beside it).
- The only Seedance model with 4K output; 1080p cannot be combined with reference images.
- Sound is generated by default (`generate_audio`) and does not change the price.
- Billed by the size and length of the video, plus the length of any reference videos. A failed task costs nothing.POST/v1/videos/tasksTry itOpens this model in the API Explorer. Enter your BeatAPI API key to create a task: the call is real and is billed to your own balance.## Model IDsFour Seedance models share this endpoint. The values below come straight from the gateway contract; only Seedance 2.5 accepts `task_type`, `output_format` and `seed`.| Model ID          | `duration` (s) | `resolution`                  | Max reference images | Max reference videos | Max reference audio | Choose it when                                                                                      |
| ----------------- | -------------- | ----------------------------- | -------------------- | -------------------- | ------------------- | --------------------------------------------------------------------------------------------------- |
| `seedance-2.5`    | 4–30           | `480p`, `720p`, `1080p`       | 30                   | 10                   | 10                  | You need clips up to 30 seconds, large reference sets, editing or extending a video, or MOV output. |
| **`seedance-2`**  | 4–15           | `480p`, `720p`, `1080p`, `4k` | 9                    | 3                    | 3                   | You need 4K output, or 1080p at a lower price than 2.5.                                             |
| `seedance-2-fast` | 4–15           | `480p`, `720p`                | 9                    | 3                    | 3                   | You want a lower price at 480p or 720p and keep `generate_audio`.                                   |
| `seedance-2-mini` | 4–15           | `480p`, `720p`                | 9                    | 3                    | 3                   | Price matters most; 480p or 720p, no `generate_audio` field.                                        |## Endpoint and authentication`POST https://api.beatapi.io/v1/videos/tasks`Authorization
string
RequiredYour BeatAPI API key, sent as `Bearer <BEATAPI_API_KEY>`. Create keys in the [Dashboard](https://beatapi.io/dashboard). Keep keys on your server; never ship them in a browser or mobile app.Send the body as JSON with `Content-Type: application/json`. `Idempotency-Key` is optional: send a unique value (at most 255 characters) per logical request and reuse it only to retry that exact body. Within 24 hours a retry with the same key and body returns the first response again with `Idempotent-Replayed: true`; the same key with a different body returns `409 idempotency_conflict`. Responses other than 2xx are not stored, so a retry after a 400 or 402 runs again.## How a request works`POST` the parameters below to the endpoint. A `201` means the task was accepted and its price reserved from your balance; the work runs in the background. Save `data.id`.Call `GET /v1/tasks/{task_id}` and wait `data.poll_after_seconds` between calls (5 s for images, 8 s for videos) until `status` is `succeeded` or `failed`. Or register a [webhook](/webhooks) for `task.succeeded` and `task.failed`; keep polling as the fallback, because a task stopped by the processing timeout sends no event.On `succeeded`, download every `data.output.media[].url` and store the files you need; BeatAPI does not promise how long result URLs stay available. On `failed`, read `data.error_code` and `data.error_message`: the reserved amount was returned to your balance, and `data.retryable` says whether sending the same request again can succeed.## Input modes| Mode                 | Required inputs                                                                               | Notes                                                                                                                                                 |
| -------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| Text to video        | `model`, `prompt`                                                                             | Send no media arrays.                                                                                                                                 |
| First frame          | `model`, `prompt`, `images` (1 link)                                                          | The video starts from the image.                                                                                                                      |
| First and last frame | `model`, `prompt`, `images` (2 links)                                                         | `images[0]` is the first frame, `images[1]` the last.                                                                                                 |
| References           | `model`, `prompt`, at least one of `reference_images`, `reference_videos`, `reference_audios` | Any mix, but audio needs at least one reference image or video beside it. Cannot be combined with `images`. With 1080p, reference images are refused. |## Request parametersmodel
string
RequiredThe model to run.**Value**: `seedance-2`**If the value is wrong**- Missing: `"model" is required`
- An image model sent to this endpoint: `"model" nano-banana-2 is served by POST /v1/images/tasks, not this endpoint`prompt
string
RequiredWhat happens in the video: subject, action, camera movement, style and sound. With references, say what each input is for.**Length**: 1–5000 characters- Length is counted in characters (a CJK character counts as one).
- Refer to inputs by their position, for example “the first reference image” or “the second reference video”.**If the value is wrong**- Missing: `"prompt" is required`
- Empty or longer than the limit: `"prompt" has an unsupported length`images
string[]
OptionalA first frame, or a first and a last frame.**Items**: 1–2  \
Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`.- One link: the video starts from this image. Two links: `images[0]` is the first frame and `images[1]` the last.
- For more pictures, or pictures that guide the video without being frames, use `reference_images` instead.**If the value is wrong**- More than two links: `"images" accepts at most 2 items`
- Combined with any reference\_\* field: `Cannot combine "images" with reference inputs in one task`
- Not an https\:// link: `"images[0]" must be a public HTTPS URL`reference_images
string[]
OptionalPictures that guide the content, characters, products or style of the video.**Items**: 1–9  \
Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`.- Images are used in list order; refer to them in the prompt by position.
- Not available with `resolution: "1080p"`; use 480p, 720p or 4K, or drop the reference images.**If the value is wrong**- More than the maximum: `"reference_images" accepts at most 9 items`
- Combined with `images`: `Cannot combine "images" with reference inputs in one task`
- Sent with `resolution: "1080p"`: `Seedance 2.0 does not support 1080p in reference image scenarios`reference_videos
string[]
OptionalVideos to take motion, camera work or content from.**Items**: 1–3  \
Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`.- Each link must return an MP4 or MOV file whose host allows byte-range requests: the gateway reads the length of every clip before creating the task, because reference seconds are billed.
- Each clip runs 1.8 to 15 seconds and all clips together at most 15 seconds.Reference videos add to the price for every second they run (see Billing). Trim them to the part you need.**If the value is wrong**- More than the maximum: `"reference_videos" accepts at most 3 items`
- The clip cannot be read: `A reference video could not be read: reference_videos[0]: its host does not allow byte-range requests. Send an MP4 or MOV file at a public HTTPS URL whose host allows byte-range requests.`reference_audios
string[]
OptionalMusic, voice or sound to follow. Audio cannot be the only reference: send at least one reference image or video with it.**Items**: 1–3  \
Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`.- WAV and MP3 clips are measured against the limits below; other formats are passed to the model unmeasured.**If the value is wrong**- More than the maximum: `"reference_audios" accepts at most 3 items`
- Audio without any reference image or video: `seedance-2 audio reference requires at least one reference image or video`duration
integer
OptionalDefault: 5Length of the video in seconds, a whole number.**Default**: `5`  \
**Range**: 4–15- If you leave it out, `5` is sent.**If the value is wrong**- Outside the range or not a whole number: `"duration" is outside its supported range`aspect_ratio
string
OptionalDefault: adaptiveShape of the video as width:height. `adaptive` lets the model choose from the inputs.**Allowed values**: `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`  \
**Default**: `adaptive`- With `adaptive` the reservation assumes the largest frame of the chosen resolution, so it can be slightly higher than with a fixed ratio.**If the value is wrong**- A value not in the list: `"aspect_ratio" must be one of: [adaptive 21:9 16:9 4:3 1:1 3:4 9:16]`resolution
string
OptionalDefault: 720pOutput resolution. Higher resolution costs more per second.**Allowed values**: `480p`, `720p`, `1080p`, `4k`  \
**Default**: `720p`- `4k` and `4K` mean the same thing; both are accepted. The other values are lower case.
- 1080p cannot be combined with `reference_images`.4K is the most expensive setting, about twice the per-second price of 1080p (see Billing).**If the value is wrong**- A value not in the list (for example `2k` or `720P`): `"resolution" must be one of: [480p 720p 1080p 4k 4K]`
- `1080p` with `reference_images`: `Seedance 2.0 does not support 1080p in reference image scenarios`generate_audio
boolean
OptionalDefault: trueWhether the video has a generated soundtrack. The price is the same either way.**Default**: `true`**If the value is wrong**- Not true or false: `"generate_audio" must be a boolean`The gateway also checks these combinations before creating the task:- images cannot be combined with reference inputs## Input media limitsThe gateway reads every input before the task is created and refuses one outside these limits with a `400 bad_request` that names the input. Nothing is charged.| Media  | Limits checked before the task is created                                                   |
| ------ | ------------------------------------------------------------------------------------------- |
| Images | width and height 300–6000 px; aspect ratio (width ÷ height) 0.4–2.5; at most 30 MB each     |
| Videos | each 1.8–15 s; 15 s in total; at least 407,696 pixels per frame (width × height); 24–60 FPS |
| Audio  | each 2–15 s; 15 s in total                                                                  |- Reference videos must be MP4 or MOV, at a public HTTPS link whose host answers byte-range requests. A clip whose length cannot be read is always refused, because its seconds are billed.
- Image size is checked when the host reports it. Use JPEG, PNG or WebP; a file the model cannot use fails the task after submission with `bad_request`, and the task is refunded.
- Limits are reported in the order length, sides, aspect ratio, pixels, frame rate and size. The message names the input by list and position, counting from 0 like the field errors: `reference_videos[0] is 1.5 seconds long; this model takes reference video of 1.8 to 15 seconds.`
- Lengths are measured with a 0.1-second tolerance. Sizes are checked only when the host reports them.
- Image and audio links are refused at create only when the host answers with a 4xx error or returns an empty file, for example `images[1] could not be downloaded: the URL returned HTTP 404.`; other problems with them surface after submission.
- A clip at 23.976 FPS counts as below 24 and is refused; re-export it at 24 FPS or higher.
- Have a local file? Upload it with `POST /v1/files` and pass the returned `data.url`.## Combination rulesThese are checked when the task is created, in this order. A request that breaks one is refused with `400 bad_request` and costs nothing.| Request                                               | Refused with                                                                |
| ----------------------------------------------------- | --------------------------------------------------------------------------- |
| `images` together with any `reference_*` field        | `Cannot combine "images" with reference inputs in one task`                 |
| `reference_audios` without a reference image or video | `seedance-2 audio reference requires at least one reference image or video` |
| `resolution: "1080p"` with `reference_images`         | `Seedance 2.0 does not support 1080p in reference image scenarios`          |## Fields this model does not acceptSending one of these is refused before anything is charged, instead of being ignored:- Fields of other video models, such as `seed`, `task_type`, `output_format` (Seedance 2.5 only), `watermark`, `quality`, `sound`, `multi_shots` or `character_orientation` → `field "seed" is not supported by model seedance-2` (with the field you sent).
- A name no BeatAPI video model uses → `unknown field: <name>`.## Estimating the priceThe video tokens of a task are `N = W × H × (24 × D + 1 + 24 × R) / 1024`, where `W × H` is the frame size in pixels at the chosen resolution and aspect ratio (1280 × 720 for 720p at 16:9, 864 × 496 for 480p at 16:9), `D` is the output length in seconds and `R` the total length of the reference videos in seconds (0 without any). The price is `N` times the rate per million video tokens. Without reference video: about $6.932 (480p and 720p), $7.685 (1080p) and $3.918 (4K). With reference video: about $4.219, $4.671 and $2.411.For example, 5 seconds at 720p and 16:9 without reference video is 1280 × 720 × 121 / 1024 = 108,900 tokens, about \$0.755. This is an estimate; `usage` on the task shows what was reserved and charged.## Request examples```bash title="cURL"
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "duration": 5,
  "aspect_ratio": "16:9",
  "resolution": "720p"
}'
``````python title="Python"
import os
import requests

response = requests.post(
    "https://api.beatapi.io/v1/videos/tasks",
    headers={"Authorization": f"Bearer {os.environ['BEATAPI_API_KEY']}"},
    json={
      "model": "seedance-2",
      "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
      "duration": 5,
      "aspect_ratio": "16:9",
      "resolution": "720p"
    },
    timeout=60,
)
body = response.json()
if not response.ok:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
task = body["data"]
print(task["id"], task["status"])
``````javascript title="JavaScript"
const response = await fetch('https://api.beatapi.io/v1/videos/tasks', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.BEATAPI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "model": "seedance-2",
    "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
    "duration": 5,
    "aspect_ratio": "16:9",
    "resolution": "720p"
  }),
});
const body = await response.json();
if (!response.ok) throw new Error(`${response.status} ${body.error.code}: ${body.error.message}`);
console.log(body.data.id, body.data.status);
```### Text to videoA 5-second 720p landscape clip with sound.```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "duration": 5,
  "aspect_ratio": "16:9",
  "resolution": "720p"
}'
```### First frameThe video starts from the image.```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "Animate the singer with a slow push-in and natural fabric movement",
  "images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "duration": 5,
  "resolution": "1080p"
}'
```### First and last frameThe video moves from the first image to the second.```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move",
  "images": [
    "https://media.beatapi.io/samples/smart-bottle.png",
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "duration": 6,
  "resolution": "720p"
}'
```### Image and audio referencesA performance that follows a character image and a music clip. With `reference_images`, use 480p, 720p or 4K, not 1080p.```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera",
  "reference_images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "duration": 8,
  "resolution": "720p"
}'
```### Image, video and audio referencesReplace the video link with your own MP4 or MOV of 15 seconds or less. Every second of the reference video is billed (see Billing).```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music",
  "reference_images": [
    "https://media.beatapi.io/samples/smart-bottle.png"
  ],
  "reference_videos": [
    "https://your-cdn.example.com/clips/source.mp4"
  ],
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "duration": 8,
  "resolution": "720p"
}'
```### 4KThe highest resolution. `4k` and `4K` are the same.```bash
curl --request POST \
  --url https://api.beatapi.io/v1/videos/tasks \
  --header "Authorization: Bearer $BEATAPI_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "seedance-2",
  "prompt": "A slow aerial shot over a coastal city at sunrise, gulls and distant traffic",
  "duration": 5,
  "aspect_ratio": "16:9",
  "resolution": "4K"
}'
```## Responses### Create a task (201)The task object. `output` is `null` until the task succeeds. Fields marked “while running” disappear once the task finishes.```json
{
  "data": {
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "object": "task",
    "task_kind": "video",
    "capability_id": "seedance-2",
    "capability_version": 1,
    "media_type": "video",
    "model": "seedance-2",
    "status": "queued",
    "stage": "queued",
    "created_at": 1791993600,
    "updated_at": 1791993600,
    "completed_at": null,
    "poll_after_seconds": 8,
    "output": null,
    "usage": {
      "credits_reserved": 0.754841,
      "credits_settled": 0,
      "credits_refunded": 0,
      "credits_charged": 0.754841,
      "billable_duration_seconds": 5
    },
    "request_id": "req_5f0c2a9e4b7d4e31",
    "error_code": null,
    "error_message": null
  }
}
```| Field                                  | Type              | Description                                                                                                                              |
| -------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `data.id`                              | `string`          | Task ID: `task_` followed by 32 letters and digits. Use it to poll and to match webhook events.                                          |
| `data.object`                          | `string`          | Always `task`.                                                                                                                           |
| `data.task_kind`                       | `string`          | `image` or `video`.                                                                                                                      |
| `data.capability_id`                   | `string`          | The model ID you sent.                                                                                                                   |
| `data.capability_version`              | `integer`         | Contract version of the model, currently `1`.                                                                                            |
| `data.media_type`                      | `string`          | `image` or `video`.                                                                                                                      |
| `data.model`                           | `string`          | The model ID you sent (same as `capability_id`).                                                                                         |
| `data.status`                          | `string`          | `queued`, `processing`, `succeeded` or `failed`. Only the last two are final.                                                            |
| `data.stage`                           | `string`          | Repeats `status`; kept for older clients.                                                                                                |
| `data.created_at`                      | `integer`         | When the task was created, Unix seconds.                                                                                                 |
| `data.updated_at`                      | `integer`         | Last change, Unix seconds.                                                                                                               |
| `data.completed_at`                    | `integer \| null` | When the task finished, Unix seconds; `null` while it runs.                                                                              |
| `data.poll_after_seconds`              | `integer`         | While running: how long to wait before the next poll (5 for images, 8 for videos).                                                       |
| `data.typical_seconds`                 | `object`          | While running, when enough recent tasks exist: `p50` and `p90` completion times in seconds over the last `window`, from `samples` tasks. |
| `data.output`                          | `object \| null`  | The result; `null` until `status` is `succeeded`. See the output fields below.                                                           |
| `data.usage.credits_reserved`          | `number`          | USD held from your balance when the task was created.                                                                                    |
| `data.usage.credits_charged`           | `number`          | USD this task costs; `0` on a failed task.                                                                                               |
| `data.usage.credits_settled`           | `number`          | USD finally taken; set when the task succeeds, otherwise `0`.                                                                            |
| `data.usage.credits_refunded`          | `number`          | USD returned to your balance; equals the reservation on a failed task once the refund is recorded.                                       |
| `data.usage.billable_duration_seconds` | `integer`         | Video only: the seconds the price is based on. Absent when the model reports no duration.                                                |
| `data.request_id`                      | `string`          | Request ID. Include it when you contact support.                                                                                         |
| `data.error_code`                      | `string \| null`  | Failure code; `null` unless the task failed.                                                                                             |
| `data.error_message`                   | `string \| null`  | What went wrong and what to change; `null` unless the task failed.                                                                       |### Finished task`GET /v1/tasks/{task_id}` returns HTTP 200 with `status: "succeeded"` and the result in `data.output`.```json
{
  "data": {
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "object": "task",
    "task_kind": "video",
    "capability_id": "seedance-2",
    "capability_version": 1,
    "media_type": "video",
    "model": "seedance-2",
    "status": "succeeded",
    "stage": "succeeded",
    "created_at": 1791993600,
    "updated_at": 1791993690,
    "completed_at": 1791993690,
    "output": {
      "media": [
        {
          "type": "video",
          "url": "https://media.beatapi.io/outputs/task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ/0.mp4",
          "mime_type": "video/mp4"
        }
      ],
      "r2_url": "https://media.beatapi.io/outputs/task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ/0.mp4"
    },
    "usage": {
      "credits_reserved": 0.754841,
      "credits_settled": 0.754841,
      "credits_refunded": 0,
      "credits_charged": 0.754841,
      "billable_duration_seconds": 5
    },
    "request_id": "req_5f0c2a9e4b7d4e31",
    "error_code": null,
    "error_message": null
  }
}
```#### Output fields| Field                      | Type       | Description                                                                            |
| -------------------------- | ---------- | -------------------------------------------------------------------------------------- |
| `output.media`             | `object[]` | The generated files; one video for this model.                                         |
| `output.media[].type`      | `string`   | Always `video`.                                                                        |
| `output.media[].url`       | `string`   | HTTPS link to the stored video. Download and keep it; no retention period is promised. |
| `output.media[].mime_type` | `string`   | Always `video/mp4`.                                                                    |
| `output.r2_url`            | `string`   | The video URL again, for older clients. Read `media` instead.                          |### Failed taskA failed task is still HTTP 200 on `GET /v1/tasks/{task_id}`: the failure is in the body. The reservation is returned in full, so nothing is charged.```json
{
  "data": {
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "object": "task",
    "task_kind": "video",
    "capability_id": "seedance-2",
    "capability_version": 1,
    "media_type": "video",
    "model": "seedance-2",
    "status": "failed",
    "stage": "failed",
    "created_at": 1791993600,
    "updated_at": 1791993690,
    "completed_at": 1791993690,
    "output": null,
    "usage": {
      "credits_reserved": 0.754841,
      "credits_settled": 0,
      "credits_refunded": 0.754841,
      "credits_charged": 0,
      "billable_duration_seconds": 5
    },
    "retryable": true,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "error_code": "processing_failed",
    "error_message": "The task failed during processing on our side. Retry; a failed task is refunded."
  }
}
```| Field                | Type      | Description                                                                                                                                                                                                            |
| -------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `data.error_code`    | `string`  | One of `bad_request` and `content_policy_violation` (change the request) or `processing_unavailable`, `processing_timeout`, `processing_failed` and `result_transfer_failed` (try again later). See [Errors](/errors). |
| `data.error_message` | `string`  | A sentence that names the problem and the fix.                                                                                                                                                                         |
| `data.retryable`     | `boolean` | Present only on a failed task: `true` when the same request can succeed if you send it again.                                                                                                                          |
| `data.usage`         | `object`  | Once the refund is recorded (normally at the moment the task fails): `credits_charged` and `credits_settled` are `0`, and `credits_refunded` equals `credits_reserved`.                                                |## Complete exampleCreate a task, wait for it with the server’s polling hint, and print the result URLs. Set `BEATAPI_API_KEY` in your environment and install `requests`.```python
import os
import time
import uuid

import requests

API = "https://api.beatapi.io"
HEADERS = {"Authorization": f"Bearer {os.environ['BEATAPI_API_KEY']}"}


def create_task(body: dict) -> dict:
    # One Idempotency-Key per logical request: a retry with the same key cannot create a second task.
    headers = {**HEADERS, "Idempotency-Key": str(uuid.uuid4())}
    for attempt in range(3):
        response = requests.post(f"{API}/v1/videos/tasks", headers=headers, json=body, timeout=60)
        if response.status_code in (429, 503) and attempt < 2:
            time.sleep(int(response.headers.get("Retry-After", 10)))
            continue
        break
    try:
        payload = response.json()
    except ValueError:  # an edge error page is not JSON
        response.raise_for_status()
        raise
    if not response.ok:
        error = payload["error"]
        raise RuntimeError(f"{response.status_code} {error['code']}: {error['message']} (request_id={error.get('request_id')})")
    return payload["data"]


def wait_for_task(task_id: str, timeout_seconds: int = 1800) -> dict:
    deadline = time.monotonic() + timeout_seconds
    while time.monotonic() < deadline:
        response = requests.get(f"{API}/v1/tasks/{task_id}", headers=HEADERS, timeout=30)
        if response.status_code == 429 or response.status_code >= 500:
            time.sleep(int(response.headers.get("Retry-After", 10)))
            continue
        response.raise_for_status()
        task = response.json()["data"]
        if task["status"] in ("succeeded", "failed"):
            return task
        time.sleep(task.get("poll_after_seconds", 5))
    raise TimeoutError(f"task {task_id} is still running; keep polling later")


task = create_task({
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "duration": 5,
  "aspect_ratio": "16:9",
  "resolution": "720p"
})
print("created", task["id"])
task = wait_for_task(task["id"])
if task["status"] == "failed":
    raise SystemExit(f"{task['error_code']}: {task['error_message']}")
for item in task["output"]["media"]:
    print(item["url"])
```## Billing- The price follows the size and length of the video: more seconds, a higher resolution or a larger frame cost more. Sound does not change it; reference images and audio add nothing.
- Without reference video, a 16:9 clip costs about $0.070 (480p), $0.150 (720p), $0.373 (1080p) or $0.762 (4K) per second. Other aspect ratios differ by a few percent.
- With `reference_videos`, the whole request moves to the lower “with video input” rate, and every second of reference video counts like a second of output: about $0.042 (480p), $0.091 (720p), $0.227 (1080p) or $0.469 (4K) per second of output plus reference, at 16:9.
- The table below shows 8-second clips; its “with video input” rows include an 8-second reference video.
- The price is reserved when the task is created. With `adaptive` the reservation assumes the largest frame of the resolution. You pay the reservation, or the actual amount if the delivered video comes to more.
- A failed task, including one refused by moderation after submission, is refunded in full.Current list prices, the same as on [Pricing](https://beatapi.io/pricing). An account with a negotiated discount pays less; `data.usage` on the task always shows the amount actually charged.| Option                           | List price (USD) |
| -------------------------------- | ---------------- |
| 8 sec · 480p · no video input    | \$0.559861       |
| 8 sec · 480p · with video input  | \$0.679805       |
| 8 sec · 720p · no video input    | \$1.204003       |
| 8 sec · 720p · with video input  | \$1.461945       |
| 8 sec · 1080p · no video input   | \$3.003463       |
| 8 sec · 1080p · with video input | \$3.64181        |
| 8 sec · 4K · no video input      | \$6.12471        |
| 8 sec · 4K · with video input    | \$7.518575       |## Common errors| Error or symptom                                                                                      | Cause                                                                                                                                                                           | Fix                                                                                                     |
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 400 `resolution "1080p" is not available for this model right now; available: …`                      | No line serving this model accepts that value at the moment; the same can happen for `aspect_ratio`.                                                                            | Use one of the listed values, or retry later.                                                           |
| 400 `field "seed" is not supported by model seedance-2`                                               | A field of another video model that this model does not accept (`seed`, `task_type`, `output_format`, `watermark`, `quality`, `sound`, `multi_shots`, `character_orientation`). | Remove the field. Only Seedance 2.5 takes `seed`, `task_type` and `output_format`.                      |
| 400 `"resolution" must be one of: [480p 720p 1080p 4k 4K]`                                            | `2k`, `720P` or another value.                                                                                                                                                  | Send `480p`, `720p`, `1080p` or `4k` (`4K` also works).                                                 |
| 400 `Seedance 2.0 does not support 1080p in reference image scenarios`                                | `resolution: "1080p"` together with `reference_images`.                                                                                                                         | Use 480p, 720p or 4K, or drop the reference images.                                                     |
| 400 `seedance-2 audio reference requires at least one reference image or video`                       | `reference_audios` sent alone.                                                                                                                                                  | Add a reference image or video.                                                                         |
| 400 `Cannot combine "images" with reference inputs in one task`                                       | Frames and `reference_*` in the same request.                                                                                                                                   | Use frames or references. For several pictures, put them all in `reference_images`.                     |
| 400 `"duration" is outside its supported range`                                                       | Not a whole number from 4 to 15, or sent as a string.                                                                                                                           | Send an integer such as `5`.                                                                            |
| 400 `A reference video could not be read: reference_videos[0]: …`                                     | Not an MP4 or MOV, a host without byte-range support, a 404, or an empty file.                                                                                                  | Host the clip on public HTTPS storage that supports range requests, or upload it with `POST /v1/files`. |
| 400 `reference_videos[0] is 1.5 seconds long; this model takes reference video of 1.8 to 15 seconds.` | A reference clip is shorter or longer than the limit.                                                                                                                           | Trim or replace the clip.                                                                               |
| 400 `The reference videos run 20 seconds in total; this model takes at most 15.`                      | The reference clips together are too long.                                                                                                                                      | Trim or drop clips.                                                                                     |
| Task `failed` with `content_policy_violation`                                                         | The prompt, an input or the result was refused by moderation (real people, public figures, copyrighted characters).                                                             | Change the input. Retrying unchanged fails again; nothing is charged.                                   |
| 402 `insufficient_credits`                                                                            | The balance is below the reservation; long reference videos, 4K and `adaptive` raise it.                                                                                        | Top up, shorten the references, or pick a fixed `aspect_ratio`.                                         |## HTTP errors at a glanceErrors before a task exists arrive as a non-2xx response, and nothing is charged. Branch on `error.code` or `error.retryable`; `message` names the problem. The full list and retry policy are on [Errors](/errors).```json
{
  "error": {
    "code": "bad_request",
    "message": "\"prompt\" is required",
    "retryable": false,
    "request_id": "req_5f0c2a9e4b7d4e31"
  }
}
```| HTTP status | `error.code`                                                                                  | What to do                                                                                                            |
| ----------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| 400         | `bad_request`, `content_policy_violation`                                                     | Fix the request; the message names the field. Do not retry unchanged.                                                 |
| 401         | `missing_api_key`, `invalid_api_key` (older clients may see `unauthorized`)                   | Send a valid key as `Authorization: Bearer <key>`.                                                                    |
| 402         | `insufficient_credits`                                                                        | Top up, or raise the key’s quota, then send it again.                                                                 |
| 403         | `forbidden`                                                                                   | The key or account may not use this model (for example, free credit only covers some models). Do not retry unchanged. |
| 404         | `not_found`                                                                                   | On `GET /v1/tasks/{task_id}`: the task does not exist for this key’s account. Check the ID.                           |
| 409         | `idempotency_conflict`                                                                        | Use a new `Idempotency-Key`, or wait for the first request with this key to finish.                                   |
| 429         | `rate_limit_exceeded`                                                                         | Wait `Retry-After` seconds (also `error.retry_after_seconds`), then retry.                                            |
| 500         | `internal_error`                                                                              | Retry with backoff; contact support with `request_id` if it continues.                                                |
| 503         | `processing_unavailable`, `processing_timeout`, `processing_failed`, `result_transfer_failed` | Nothing was charged. Retry with exponential backoff.                                                                  |

Reference: https://docs.beatapi.io/api-reference/video-api/seedance-2

## Authentication

- `Authorization` header (bearer token, required) — Send your API key as `Authorization: Bearer <BEATAPI_API_KEY>`.

## Servers

- `https://api.beatapi.io` (Direct, default)
- `https://api.beatapi.io` (API)

## Request

### Headers

- `Idempotency-Key` (string, optional) — Send the body as JSON with `Content-Type: application/json`. `Idempotency-Key` is optional: send a unique value (at most 255 characters) per logical request and reuse it only to retry that exact body. Within 24 hours a retry with the same key and body returns the first response again with `Idempotent-Replayed: true`; the same key with a different body returns `409 idempotency_conflict`. Responses other than 2xx are not stored, so a retry after a 400 or 402 runs again.

### Body (application/json)

This endpoint expects a Seedance2VideoRequest.

- `model` (enum, required) — The model to run. **Value**: `seedance-2` **If the value is wrong** - Missing: `"model" is required` - An image model sent to this endpoint: `"model" nano-banana-2 is served by POST /v1/images/tasks, not this endpoint`
  - Allowed values: `seedance-2`
- `prompt` (string, required) — What happens in the video: subject, action, camera movement, style and sound. With references, say what each input is for. **Length**: 1–5000 characters - Length is counted in characters (a CJK character counts as one). - Refer to inputs by their position, for example “the first reference image” or “the second reference video”. **If the value is wrong** - Missing: `"prompt" is required` - Empty or longer than the limit: `"prompt" has an unsupported length`
- `aspect_ratio` (enum, optional, default: adaptive) — Shape of the video as width:height. `adaptive` lets the model choose from the inputs. **Allowed values**: `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16` **Default**: `adaptive` - With `adaptive` the reservation assumes the largest frame of the chosen resolution, so it can be slightly higher than with a fixed ratio. **If the value is wrong** - A value not in the list: `"aspect_ratio" must be one of: [adaptive 21:9 16:9 4:3 1:1 3:4 9:16]`
  - Allowed values: `adaptive`, `21:9`, `16:9`, `4:3`, `1:1`, `3:4`, `9:16`
- `duration` (integer, optional, default: 5) — Length of the video in seconds, a whole number. **Default**: `5` **Range**: 4–15 - If you leave it out, `5` is sent. **If the value is wrong** - Outside the range or not a whole number: `"duration" is outside its supported range`
- `generate_audio` (boolean, optional, default: true) — Whether the video has a generated soundtrack. The price is the same either way. **Default**: `true` **If the value is wrong** - Not true or false: `"generate_audio" must be a boolean`
- `images` (list of string, optional) — A first frame, or a first and a last frame. **Items**: 1–2 Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`. - One link: the video starts from this image. Two links: `images[0]` is the first frame and `images[1]` the last. - For more pictures, or pictures that guide the video without being frames, use `reference_images` instead. **If the value is wrong** - More than two links: `"images" accepts at most 2 items` - Combined with any reference_* field: `Cannot combine "images" with reference inputs in one task` - Not an https:// link: `"images[0]" must be a public HTTPS URL`
- `reference_audios` (list of string, optional) — Music, voice or sound to follow. Audio cannot be the only reference: send at least one reference image or video with it. **Items**: 1–3 Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`. - WAV and MP3 clips are measured against the limits below; other formats are passed to the model unmeasured. **If the value is wrong** - More than the maximum: `"reference_audios" accepts at most 3 items` - Audio without any reference image or video: `seedance-2 audio reference requires at least one reference image or video`
- `reference_images` (list of string, optional) — Pictures that guide the content, characters, products or style of the video. **Items**: 1–9 Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`. - Images are used in list order; refer to them in the prompt by position. - Not available with `resolution: "1080p"`; use 480p, 720p or 4K, or drop the reference images. **If the value is wrong** - More than the maximum: `"reference_images" accepts at most 9 items` - Combined with `images`: `Cannot combine "images" with reference inputs in one task` - Sent with `resolution: "1080p"`: `Seedance 2.0 does not support 1080p in reference image scenarios`
- `reference_videos` (list of string, optional) — Videos to take motion, camera work or content from. **Items**: 1–3 Each item is a public `https://` URL. For a local file, [upload it first](/quick-guide#upload-an-input-file) with `POST /v1/files` and pass the returned `data.url`. - Each link must return an MP4 or MOV file whose host allows byte-range requests: the gateway reads the length of every clip before creating the task, because reference seconds are billed. - Each clip runs 1.8 to 15 seconds and all clips together at most 15 seconds. **Notes**: Reference videos add to the price for every second they run (see Billing). Trim them to the part you need. **If the value is wrong** - More than the maximum: `"reference_videos" accepts at most 3 items` - The clip cannot be read: `A reference video could not be read: reference_videos[0]: its host does not allow byte-range requests. Send an MP4 or MOV file at a public HTTPS URL whose host allows byte-range requests.`
- `resolution` (enum, optional, default: 720p) — Output resolution. Higher resolution costs more per second. **Allowed values**: `480p`, `720p`, `1080p`, `4k` **Default**: `720p` - `4k` and `4K` mean the same thing; both are accepted. The other values are lower case. - 1080p cannot be combined with `reference_images`. **Notes**: 4K is the most expensive setting, about twice the per-second price of 1080p (see Billing). **If the value is wrong** - A value not in the list (for example `2k` or `720P`): `"resolution" must be one of: [480p 720p 1080p 4k 4K]` - `1080p` with `reference_images`: `Seedance 2.0 does not support 1080p in reference image scenarios`
  - Allowed values: `480p`, `720p`, `1080p`, `4k`

## Response

### 201

The task object. `output` is `null` until the task succeeds. Fields marked “while running” disappear once the task finishes.

- `map from string to any`

## Errors

### 400 Bad Request Error

`bad_request`, `content_policy_violation` Fix the request; the message names the field. Do not retry unchanged.

- `map from string to any`

### 401 Unauthorized Error

`missing_api_key`, `invalid_api_key` (older clients may see `unauthorized`) Send a valid key as `Authorization: Bearer <key>`.

- `map from string to any`

### 402 Payment Required Error

`insufficient_credits` Top up, or raise the key’s quota, then send it again.

- `map from string to any`

### 403 Forbidden Error

`forbidden` The key or account may not use this model (for example, free credit only covers some models). Do not retry unchanged.

- `map from string to any`

### 409 Conflict Error

`idempotency_conflict` Use a new `Idempotency-Key`, or wait for the first request with this key to finish.

- `map from string to any`

### 429 Too Many Requests Error

`rate_limit_exceeded` Wait `Retry-After` seconds (also `error.retry_after_seconds`), then retry.

- `map from string to any`

### 500 Internal Server Error

`internal_error` Retry with backoff; contact support with `request_id` if it continues.

- `map from string to any`

### 503 Service Unavailable Error

`processing_unavailable`, `processing_timeout`, `processing_failed`, `result_transfer_failed` Nothing was charged. Retry with exponential backoff.

- `map from string to any`

## Examples

### Text to video

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "720p"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600,
    "usage": {
      "billable_duration_seconds": 5,
      "credits_charged": 0.754841,
      "credits_refunded": 0,
      "credits_reserved": 0.754841,
      "credits_settled": 0
    }
  }
}
```

**SDK Code**

```python Text to video
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
    "aspect_ratio": "16:9",
    "duration": 5,
    "resolution": "720p"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Text to video
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound","aspect_ratio":"16:9","duration":5,"resolution":"720p"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Text to video
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"720p\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Text to video
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"720p\"\n}"

response = http.request(request)
puts response.read_body
```

```java Text to video
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"720p\"\n}")
  .asString();
```

```php Text to video
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "720p"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Text to video
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"720p\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Text to video
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "A slow tracking shot through a rain-lit night market, neon reflections on wet stone, ambient crowd sound",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "720p"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### First frame

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "Animate the singer with a slow push-in and natural fabric movement",
  "duration": 5,
  "images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "1080p"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600
  }
}
```

**SDK Code**

```python First frame
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "Animate the singer with a slow push-in and natural fabric movement",
    "duration": 5,
    "images": ["https://media.beatapi.io/samples/neon-singer.png"],
    "resolution": "1080p"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript First frame
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"Animate the singer with a slow push-in and natural fabric movement","duration":5,"images":["https://media.beatapi.io/samples/neon-singer.png"],"resolution":"1080p"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go First frame
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"Animate the singer with a slow push-in and natural fabric movement\",\n  \"duration\": 5,\n  \"images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"1080p\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby First frame
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"Animate the singer with a slow push-in and natural fabric movement\",\n  \"duration\": 5,\n  \"images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"1080p\"\n}"

response = http.request(request)
puts response.read_body
```

```java First frame
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"Animate the singer with a slow push-in and natural fabric movement\",\n  \"duration\": 5,\n  \"images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"1080p\"\n}")
  .asString();
```

```php First frame
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "Animate the singer with a slow push-in and natural fabric movement",
  "duration": 5,
  "images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "1080p"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp First frame
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"Animate the singer with a slow push-in and natural fabric movement\",\n  \"duration\": 5,\n  \"images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"1080p\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift First frame
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "Animate the singer with a slow push-in and natural fabric movement",
  "duration": 5,
  "images": ["https://media.beatapi.io/samples/neon-singer.png"],
  "resolution": "1080p"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### First and last frame

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move",
  "duration": 6,
  "images": [
    "https://media.beatapi.io/samples/smart-bottle.png",
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "720p"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600
  }
}
```

**SDK Code**

```python First and last frame
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move",
    "duration": 6,
    "images": ["https://media.beatapi.io/samples/smart-bottle.png", "https://media.beatapi.io/samples/neon-singer.png"],
    "resolution": "720p"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript First and last frame
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move","duration":6,"images":["https://media.beatapi.io/samples/smart-bottle.png","https://media.beatapi.io/samples/neon-singer.png"],"resolution":"720p"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go First and last frame
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move\",\n  \"duration\": 6,\n  \"images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\",\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby First and last frame
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move\",\n  \"duration\": 6,\n  \"images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\",\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}"

response = http.request(request)
puts response.read_body
```

```java First and last frame
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move\",\n  \"duration\": 6,\n  \"images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\",\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}")
  .asString();
```

```php First and last frame
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move",
  "duration": 6,
  "images": [
    "https://media.beatapi.io/samples/smart-bottle.png",
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "720p"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp First and last frame
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move\",\n  \"duration\": 6,\n  \"images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\",\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift First and last frame
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "The camera pushes in from the bottle on the table to the singer on a neon stage in one continuous move",
  "duration": 6,
  "images": ["https://media.beatapi.io/samples/smart-bottle.png", "https://media.beatapi.io/samples/neon-singer.png"],
  "resolution": "720p"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Image and audio references

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera",
  "duration": 8,
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "reference_images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "720p"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600
  }
}
```

**SDK Code**

```python Image and audio references
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera",
    "duration": 8,
    "reference_audios": ["https://media.beatapi.io/samples/neon-singer-preview.mp3"],
    "reference_images": ["https://media.beatapi.io/samples/neon-singer.png"],
    "resolution": "720p"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Image and audio references
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera","duration":8,"reference_audios":["https://media.beatapi.io/samples/neon-singer-preview.mp3"],"reference_images":["https://media.beatapi.io/samples/neon-singer.png"],"resolution":"720p"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Image and audio references
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Image and audio references
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}"

response = http.request(request)
puts response.read_body
```

```java Image and audio references
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}")
  .asString();
```

```php Image and audio references
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera",
  "duration": 8,
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "reference_images": [
    "https://media.beatapi.io/samples/neon-singer.png"
  ],
  "resolution": "720p"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Image and audio references
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/neon-singer.png\"\n  ],\n  \"resolution\": \"720p\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Image and audio references
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "The singer from the first reference image performs on stage in time with the reference music, warm spotlights, slow orbiting camera",
  "duration": 8,
  "reference_audios": ["https://media.beatapi.io/samples/neon-singer-preview.mp3"],
  "reference_images": ["https://media.beatapi.io/samples/neon-singer.png"],
  "resolution": "720p"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Image, video and audio references

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music",
  "duration": 8,
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "reference_images": [
    "https://media.beatapi.io/samples/smart-bottle.png"
  ],
  "reference_videos": [
    "https://your-cdn.example.com/clips/source.mp4"
  ],
  "resolution": "720p"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600
  }
}
```

**SDK Code**

```python Image, video and audio references
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music",
    "duration": 8,
    "reference_audios": ["https://media.beatapi.io/samples/neon-singer-preview.mp3"],
    "reference_images": ["https://media.beatapi.io/samples/smart-bottle.png"],
    "reference_videos": ["https://your-cdn.example.com/clips/source.mp4"],
    "resolution": "720p"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Image, video and audio references
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music","duration":8,"reference_audios":["https://media.beatapi.io/samples/neon-singer-preview.mp3"],"reference_images":["https://media.beatapi.io/samples/smart-bottle.png"],"reference_videos":["https://your-cdn.example.com/clips/source.mp4"],"resolution":"720p"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Image, video and audio references
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\"\n  ],\n  \"reference_videos\": [\n    \"https://your-cdn.example.com/clips/source.mp4\"\n  ],\n  \"resolution\": \"720p\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Image, video and audio references
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\"\n  ],\n  \"reference_videos\": [\n    \"https://your-cdn.example.com/clips/source.mp4\"\n  ],\n  \"resolution\": \"720p\"\n}"

response = http.request(request)
puts response.read_body
```

```java Image, video and audio references
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\"\n  ],\n  \"reference_videos\": [\n    \"https://your-cdn.example.com/clips/source.mp4\"\n  ],\n  \"resolution\": \"720p\"\n}")
  .asString();
```

```php Image, video and audio references
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music",
  "duration": 8,
  "reference_audios": [
    "https://media.beatapi.io/samples/neon-singer-preview.mp3"
  ],
  "reference_images": [
    "https://media.beatapi.io/samples/smart-bottle.png"
  ],
  "reference_videos": [
    "https://your-cdn.example.com/clips/source.mp4"
  ],
  "resolution": "720p"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Image, video and audio references
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music\",\n  \"duration\": 8,\n  \"reference_audios\": [\n    \"https://media.beatapi.io/samples/neon-singer-preview.mp3\"\n  ],\n  \"reference_images\": [\n    \"https://media.beatapi.io/samples/smart-bottle.png\"\n  ],\n  \"reference_videos\": [\n    \"https://your-cdn.example.com/clips/source.mp4\"\n  ],\n  \"resolution\": \"720p\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Image, video and audio references
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "A product film: the bottle from the first reference image on a turntable, camera movement like the first reference video, cut to the beat of the reference music",
  "duration": 8,
  "reference_audios": ["https://media.beatapi.io/samples/neon-singer-preview.mp3"],
  "reference_images": ["https://media.beatapi.io/samples/smart-bottle.png"],
  "reference_videos": ["https://your-cdn.example.com/clips/source.mp4"],
  "resolution": "720p"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### 4K

**Request**

```json
{
  "model": "seedance-2",
  "prompt": "A slow aerial shot over a coastal city at sunrise, gulls and distant traffic",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "4k"
}
```

**Response**

```json
{
  "data": {
    "capability_id": "seedance-2",
    "capability_version": 1,
    "completed_at": null,
    "created_at": 1791993600,
    "error_code": null,
    "error_message": null,
    "id": "task_7Qm2Xc9LpR4vT8sKa1Nf6YbH3eWdJ0uZ",
    "media_type": "video",
    "model": "seedance-2",
    "object": "task",
    "output": null,
    "poll_after_seconds": 8,
    "request_id": "req_5f0c2a9e4b7d4e31",
    "stage": "queued",
    "status": "queued",
    "task_kind": "video",
    "updated_at": 1791993600
  }
}
```

**SDK Code**

```python 4K
import requests

url = "https://api.beatapi.io/v1/videos/tasks"

payload = {
    "model": "seedance-2",
    "prompt": "A slow aerial shot over a coastal city at sunrise, gulls and distant traffic",
    "aspect_ratio": "16:9",
    "duration": 5,
    "resolution": "4k"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript 4K
const url = 'https://api.beatapi.io/v1/videos/tasks';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"model":"seedance-2","prompt":"A slow aerial shot over a coastal city at sunrise, gulls and distant traffic","aspect_ratio":"16:9","duration":5,"resolution":"4k"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go 4K
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.beatapi.io/v1/videos/tasks"

	payload := strings.NewReader("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow aerial shot over a coastal city at sunrise, gulls and distant traffic\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"4k\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby 4K
require 'uri'
require 'net/http'

url = URI("https://api.beatapi.io/v1/videos/tasks")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow aerial shot over a coastal city at sunrise, gulls and distant traffic\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"4k\"\n}"

response = http.request(request)
puts response.read_body
```

```java 4K
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.beatapi.io/v1/videos/tasks")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow aerial shot over a coastal city at sunrise, gulls and distant traffic\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"4k\"\n}")
  .asString();
```

```php 4K
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.beatapi.io/v1/videos/tasks', [
  'body' => '{
  "model": "seedance-2",
  "prompt": "A slow aerial shot over a coastal city at sunrise, gulls and distant traffic",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "4k"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp 4K
using RestSharp;

var client = new RestClient("https://api.beatapi.io/v1/videos/tasks");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"model\": \"seedance-2\",\n  \"prompt\": \"A slow aerial shot over a coastal city at sunrise, gulls and distant traffic\",\n  \"aspect_ratio\": \"16:9\",\n  \"duration\": 5,\n  \"resolution\": \"4k\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift 4K
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "model": "seedance-2",
  "prompt": "A slow aerial shot over a coastal city at sunrise, gulls and distant traffic",
  "aspect_ratio": "16:9",
  "duration": 5,
  "resolution": "4k"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.beatapi.io/v1/videos/tasks")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```