# Seedance 2.5

> Новейшая видеомодель ByteDance: ролики до 30 секунд со звуком, по описанию, кадрам и образцам.

Seedance 2.5 — новейшая видеомодель ByteDance. Снимает ролики от 4 до 30 секунд в 480p, 720p и 1080p со звуком: по описанию, по первому и последнему кадру, по образцам (до 30 фото, 10 видео и 10 звуковых дорожек), а также меняет и продолжает ваше видео.

Длину можно выбрать «Авто» — модель решит сама: списывается цена 30 секунд, лишнее возвращается сразу после готовности.

Одна модель `seedance-2.5` · ~4 мин. Что получится, задаётся полями `input` (описание, кадры, образцы, `video_mode`, длительность) — отдельных эндпоинтов «оживить / изменить» нет.

## Возможности

- `prompt` — до **30000** символов
- `duration: "auto"` / `-1` — длину выбирает модель (на сайте: **auto (-1)**)
- `video_mode`: `auto` · `reference` · `edit` · `extend`
- `watermark` — метка «AI generated»
- `output_format`: `mp4` (по умолчанию) или `mov`
- `return_last_frame` — URL последнего кадра для продолжения
- `generate_audio` — звук в ролике
- `nsfw_check` — проверка до списания
- `web_search` / `tools: [{"type":"web_search"}]` — свежие сведения из сети

## Цена

| Разрешение | Цена за секунду | С вашим видео, за секунду |
|---|---|---|
| 480p | $0.125 | $0.075 |
| 720p | $0.281 | $0.169 |
| 1080p | $0.501 | $0.299 |

- Цена = цена секунды × длина ролика, округляется вверх до $0.001. Списывается при создании задачи и полностью возвращается, если задача не удалась.
- С вашим видео считаются секунды исходного ролика плюс секунды результата.
- На сайте — галочка **auto (-1)** рядом с длительностью (не пункт в списке). В API: `duration: "auto"` или `-1` — длину выберет модель, до 30 сек. При создании списывается цена за 30 сек (плюс секунды вашего видео, если оно есть). Когда видео готово, цена пересчитывается по реальной длине, разница сразу возвращается на баланс (в истории — «Возврат за неиспользованные секунды видео»). Итоговая цена — `costUsd` в recordInfo, длина — `duration` в `resultJson`. При `video_mode: "edit"` длина результата — как у вашего ролика.

## Лимиты медиа

| Тип | Ограничения |
|---|---|
| Фото | до **30**; JPG / PNG / WebP (также BMP / TIFF / GIF / HEIC при публичной https-ссылке; либо `asset://…` если ID уже есть); загрузка через [files/upload](https://docs.mixmedia.tech/endpoints/upload) — до **30 МБ** на файл |
| Видео | до **10**; вместе ≤ **30 с** (каждый клип 2…30 с); MP4 / MOV → на сервере в MP4; загрузка ≤ **200 МБ** |
| Аудио | до **10**; вместе ≤ **30 с**; MP3 / WAV; загрузка ≤ **200 МБ**; можно только звук без фото/видео |

Фото — публичные https или upload; видео и звук — только через files/upload.

## Типы задач и ограничения

| `video_mode` | Что нужно | Заметки |
|---|---|---|
| `auto` | описание; медиа по желанию | по умолчанию; модель сама выберет reference / edit / extend |
| `reference` | образцы фото / видео / звука | герой, место, движение, стиль |
| `edit` | `video_urls` | длина и соотношение сторон как у вашего ролика; ролик ≥ 4 с |
| `extend` | `video_urls` | продолжение ролика |

Поле `omni_reference_task_type` — синоним `video_mode` (принимается в API).

**Совет:** при `video_urls` на сайте подставляются `aspect_ratio: adaptive` и `duration: auto` / `-1` (галочка **auto (-1)**) — модель чувствительна к малейшему несовпадению длины. Вы можете задать другие значения вручную.

### Черновик 480p → финал 1080p

1. Создайте задачу с `draft: true` (разрешение принудительно `480p`).
2. Дождитесь `success`, затем `POST` с `draft_task_id` = ваш `taskId` (без `prompt` и медиа). Финал — `1080p`; секунды образцов видео повторно не тарифицируются.
3. Можно менять только `output_format`, `watermark`, `return_last_frame`. Черновик действует 7 дней. `draft` и `draft_task_id` вместе нельзя.

На сайте: галочка «Черновик 480p»; в недавних работах кнопка **1080p**.


## Параметры (поле `input`)

| Параметр | Описание | Значения (по умолчанию — жирным) |
|---|---|---|
| `prompt` | Что происходит в ролике: сцена, движение, камера, свет, стиль | текст, до 30000 символов |
| `first_frame_url` | Первый кадр: ссылка на фото (https), с него начнётся видео | `"https://…"` |
| `last_frame_url` | Последний кадр (по желанию, только вместе с первым) | `"https://…"` |
| `image_urls` | Фото-образцы (https) | `["https://…"]`, до 30 |
| `video_urls` | Ваши видео (MP4): сначала загрузите их через files/upload и передайте полученные ссылки | `["https://…"]`, до 10 |
| `audio_urls` | Звук (MP3): сначала загрузите через files/upload | `["https://…"]`, до 10 |
| `video_mode` | Тип задачи с вашим видео: `auto` (по умолчанию) — модель сама поймёт по описанию, `reference` — образец, `edit` — изменение (длительность и соотношение сторон как у вашего видео), `extend` — продление. Без поля — `auto` | **`auto`** (модель поймёт по описанию) · `reference` (образец) · `edit` (изменение) · `extend` (продление) |
| `resolution` | Разрешение видео | `480p` (стандартное) · **`720p`** (высокое (HD)) · `1080p` (Full HD) |
| `aspect_ratio` | Соотношение сторон | **`adaptive`** (под загруженное) · `16:9` (горизонтальное) · `9:16` (вертикальное) · `1:1` (квадратное) · `4:3` (традиционное) · `3:4` (вертикальное традиционное) · `21:9` (сверхширокое) |
| `duration` | Длительность видео в секундах | от 4 до 30 сек, либо `auto` / `-1` (длину выберет модель) (по умолчанию **`5`**) |
| `generate_audio` | Видео со звуком | `true` `false` (по умолчанию `true`) |
| `return_last_frame` | Вернуть URL последнего кадра (для продолжения ролика) | `true` `false` (по умолчанию `false`) |
| `output_format` | Контейнер результата: `mp4` (по умолчанию) или `mov` | **`mp4`** `mov` |
| `draft` | Черновик 480p | `true` `false` (по умолчанию `false`) |
| `web_search` | Веб-поиск: свежие сведения из интернета (реальные места, события, товары) | `true` `false` (по умолчанию `false`) |
| `watermark` | Водяной знак «AI generated» на видео | `true` `false` (по умолчанию `false`) |
| `nsfw_check` | Проверка содержимого: сначала проверить описание и фото на запрещённое; если нельзя — задача не создаётся и ничего не списывается | `true` `false` (по умолчанию `false`) |
| `seed` | Номер варианта: то же число с тем же описанием даёт похожий результат; пусто или -1 — случайный | -1…4294967295 |
| `trim_video_to` | Обрезать каждое ваше видео до N секунд: остаётся начало ролика. Видео короче — без изменений | целое число от 2 до 30 |
| `trim_to_duration` | Обрезать каждое ваше видео до выбранной длины `duration`: остаётся начало ролика. При `duration: "auto"` или `video_mode: "edit"` — до лимита модели | `true` `false` (по умолчанию `false`) |
| `auto_trim` | Если видео вместе длиннее 30 сек — обрезать их самим, а не выдавать ошибку (сначала самое длинное) | `true` `false` (по умолчанию `false`) |

## Примеры

### Только описание

```bash
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"seedance-2.5","input":{"prompt":"Дрон пролетает над осенним лесом на рассвете, туман, кинематографично","resolution":"720p","aspect_ratio":"adaptive","duration":"5"}}'
```

```python
import os, requests

r = requests.post(
    "https://mixmedia.tech/api/v1/jobs/createTask",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
      "model": "seedance-2.5",
      "input": {
        "prompt": "Дрон пролетает над осенним лесом на рассвете, туман, кинематографично",
        "resolution": "720p",
        "aspect_ratio": "adaptive",
        "duration": "5"
      }
    },
)
print(r.json())  # {"code": 200, "data": {"taskId": "..."}}
```

```javascript
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "model": "seedance-2.5",
    "input": {
      "prompt": "Дрон пролетает над осенним лесом на рассвете, туман, кинематографично",
      "resolution": "720p",
      "aspect_ratio": "adaptive",
      "duration": "5"
    }
  }),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
```

### С первым кадром

```bash
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"seedance-2.5","input":{"prompt":"Герой медленно поворачивается к камере, ветер развевает волосы","first_frame_url":"https://mixmedia.tech/static/img/previews/gpt-t2i.jpg","resolution":"720p","duration":"5"}}'
```

```python
import os, requests

r = requests.post(
    "https://mixmedia.tech/api/v1/jobs/createTask",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
      "model": "seedance-2.5",
      "input": {
        "prompt": "Герой медленно поворачивается к камере, ветер развевает волосы",
        "first_frame_url": "https://mixmedia.tech/static/img/previews/gpt-t2i.jpg",
        "resolution": "720p",
        "duration": "5"
      }
    },
)
print(r.json())  # {"code": 200, "data": {"taskId": "..."}}
```

```javascript
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "model": "seedance-2.5",
    "input": {
      "prompt": "Герой медленно поворачивается к камере, ветер развевает волосы",
      "first_frame_url": "https://mixmedia.tech/static/img/previews/gpt-t2i.jpg",
      "resolution": "720p",
      "duration": "5"
    }
  }),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
```

### С образцами

```bash
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"seedance-2.5","input":{"prompt":"Дрон пролетает над осенним лесом на рассвете, туман, кинематографично","image_urls":["https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"],"resolution":"720p","aspect_ratio":"adaptive","duration":"5"}}'
```

```python
import os, requests

r = requests.post(
    "https://mixmedia.tech/api/v1/jobs/createTask",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
      "model": "seedance-2.5",
      "input": {
        "prompt": "Дрон пролетает над осенним лесом на рассвете, туман, кинематографично",
        "image_urls": [
          "https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
        ],
        "resolution": "720p",
        "aspect_ratio": "adaptive",
        "duration": "5"
      }
    },
)
print(r.json())  # {"code": 200, "data": {"taskId": "..."}}
```

```javascript
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "model": "seedance-2.5",
    "input": {
      "prompt": "Дрон пролетает над осенним лесом на рассвете, туман, кинематографично",
      "image_urls": [
        "https://mixmedia.tech/static/img/previews/gpt-t2i.jpg"
      ],
      "resolution": "720p",
      "aspect_ratio": "adaptive",
      "duration": "5"
    }
  }),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
```

### С вашим видео

```bash
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"seedance-2.5","input":{"prompt":"Сделай ролик в стиле аниме, остальное не меняй","video_urls":["https://mixmedia.tech/files/<id>.mp4"],"video_mode":"edit","resolution":"720p","duration":"5"}}'
```

```python
import os, requests

r = requests.post(
    "https://mixmedia.tech/api/v1/jobs/createTask",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
      "model": "seedance-2.5",
      "input": {
        "prompt": "Сделай ролик в стиле аниме, остальное не меняй",
        "video_urls": [
          "https://mixmedia.tech/files/<id>.mp4"
        ],
        "video_mode": "edit",
        "resolution": "720p",
        "duration": "5"
      }
    },
)
print(r.json())  # {"code": 200, "data": {"taskId": "..."}}
```

```javascript
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "model": "seedance-2.5",
    "input": {
      "prompt": "Сделай ролик в стиле аниме, остальное не меняй",
      "video_urls": [
        "https://mixmedia.tech/files/<id>.mp4"
      ],
      "video_mode": "edit",
      "resolution": "720p",
      "duration": "5"
    }
  }),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
```

## Обрезать своё видео

Ваши видео вместе — до 30 сек. Слишком длинный ролик не нужно резать заранее:

- `trim_to_duration: true` — обрезать каждое видео до выбранной длины `duration`;
- `trim_video_to: N` — оставить N секунд от начала;
- `auto_trim: true` — если видео вместе длиннее лимита, обрезать их ровно до лимита, а не выдавать ошибку.

Обрезка бесплатная, а цена считается уже по обрезанным секундам — меньше секунд, дешевле.

```bash
curl -X POST https://mixmedia.tech/api/v1/jobs/createTask \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"seedance-2.5","input":{"prompt":"Сделай ролик в стиле аниме, остальное не меняй","video_urls":["https://mixmedia.tech/files/<id>.mp4"],"video_mode":"edit","resolution":"720p","duration":"5","trim_to_duration":true,"auto_trim":true}}'
```

```python
import os, requests

r = requests.post(
    "https://mixmedia.tech/api/v1/jobs/createTask",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={
      "model": "seedance-2.5",
      "input": {
        "prompt": "Сделай ролик в стиле аниме, остальное не меняй",
        "video_urls": [
          "https://mixmedia.tech/files/<id>.mp4"
        ],
        "video_mode": "edit",
        "resolution": "720p",
        "duration": "5",
        "trim_to_duration": True,
        "auto_trim": True
      }
    },
)
print(r.json())  # {"code": 200, "data": {"taskId": "..."}}
```

```javascript
const r = await fetch("https://mixmedia.tech/api/v1/jobs/createTask", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "model": "seedance-2.5",
    "input": {
      "prompt": "Сделай ролик в стиле аниме, остальное не меняй",
      "video_urls": [
        "https://mixmedia.tech/files/<id>.mp4"
      ],
      "video_mode": "edit",
      "resolution": "720p",
      "duration": "5",
      "trim_to_duration": true,
      "auto_trim": true
    }
  }),
});
console.log(await r.json()); // { code: 200, data: { taskId: "..." } }
```

Один файл при загрузке — до 30 сек. Без этих параметров слишком длинные видео дают ошибку `400` с подсказкой.

## Создание и результат

1. `POST /api/v1/jobs/createTask` с `model` и `input`.
2. Поллите `GET /api/v1/jobs/recordInfo?taskId=…` каждые 3–5 с (или [callback](https://docs.mixmedia.tech/callbacks)).

### Успешный createTask (HTTP 200)

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_...",
    "task_id": "task_...",
    "status": "submitted"
  }
}
```

### Готовая задача (recordInfo)

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_...",
    "task_id": "task_...",
    "state": "success",
    "status": "completed",
    "costUsd": "0.384",
    "refunded": false,
    "resultJson": {
      "videos": [
        {
          "url": "https://…/out.mp4"
        }
      ],
      "duration": 8
    },
    "lastFrameUrl": "https://…/last.jpg"
  }
}
```

Алиасы: `task_id` = `taskId`; `status`: `pending` / `processing` / `completed` / `failed` рядом с `state`. Ссылка на ролик — в `resultJson`. `size` — синоним `aspect_ratio` в `input`.


Фото можно передать любыми публичными https-ссылками или загрузить через [files/upload](https://docs.mixmedia.tech/endpoints/upload). Видео и звук — только через files/upload.

## Обработка ошибок

Ответ API — JSON `{"code", "msg", "data"}`; при ошибке есть строковое поле `error` (тип). **На `/api/v1/*` HTTP-статус совпадает с `code` в теле.**

### Примеры тел ответа

**400**

```json
{
  "code": 400,
  "msg": "input.duration: must be between 4 and 30, or \"auto\" / -1",
  "data": null,
  "error": "invalid_request_error"
}
```

**401**

```json
{
  "code": 401,
  "msg": "Authentication failed. Please check your API key",
  "data": null,
  "error": "authentication_error"
}
```

**402**

```json
{
  "code": 402,
  "msg": "Insufficient balance. Please top up and try again. Available: $0.01, required: $0.015. Top up at https://ai.aimixmedia.site/cabinet/billing",
  "data": {
    "balance": "0.0100",
    "required": "0.0150",
    "currency": "USD",
    "topUpUrl": "https://mixmedia.tech/cabinet/billing"
  },
  "error": "payment_required"
}
```

**429**

```json
{
  "code": 429,
  "msg": "Rate limit exceeded: 10 createTask/upload requests per 10 s per key. Retry after 8s",
  "data": null,
  "error": "rate_limit_error"
}
```

**500**

```json
{
  "code": 500,
  "msg": "Internal server error",
  "data": null,
  "error": "server_error"
}
```

### Коды при createTask / upload

| code | error | Что значит | Что делать |
|---|---|---|---|
| 400 | `invalid_request_error` | Неверный параметр или тело | Смотрите `msg` |
| 400 | `unsupported_model` | Нет такой модели | [Список моделей](https://docs.mixmedia.tech/models) |
| 400 | `nsfw_content_detected` | Отклонено проверкой содержимого (`nsfw_check`) | Измените описание или файлы |
| 401 | `authentication_error` | Нет ключа или он неверный | Проверьте ключ |
| 402 | `payment_required` | Не хватает денег | Пополните баланс |
| 403 | `permission_error` | Нет доступа | Напишите в поддержку |
| 429 | `rate_limit_error` | Слишком много запросов | Подождите `Retry-After` |
| 505 | `model_disabled` | Модель временно отключена | Выберите другую |
| 500 | `server_error` | Сбой у нас | Повторите позже |

Примеры `msg`: `Authentication failed. Please check your API key` (401); `Insufficient balance. Please top up and try again…` (402).

### Ошибки задачи (recordInfo)

Если задача уже создана и завершилась неудачей: `state: "fail"` (алиас `status: "failed"`), `failCode` / `failMsg`, объект `error: { code, message, type }`. Деньги возвращаются (`refunded: true`).

| failCode | error.type | Что значит |
|---|---|---|
| 400 | `nsfw_content_detected` / `invalid_request_error` | Модерация / правила безопасности |
| 422 | `invalid_request_error` | Модель не приняла параметры (длина, режим, разрешение, файл) |
| 501 | `server_error` | Модель не смогла сгенерировать (`failMsg`) |
| 504 | `timeout_error` | Слишком долго — повторите |
| 500 / 503 | `server_error` | Сервис временно недоступен |

### Типичные отказы для этой модели

- `duration` вне диапазона, или `auto` / `-1` если авто-длина не поддерживается (только Seedance 2.5)
- `resolution` / `aspect_ratio` (`size`) / `video_mode` не из списка выше
- `video_mode` = `edit` или `extend` без `video_urls`; для `edit` — ролик короче 4 с
- Слишком длинные образцы видео/звука без `auto_trim` / `trim_*` → `400`
- `nsfw_check: true` — при отказе **сразу HTTP 400** (`nsfw_content_detected`), задача не создаётся и деньги не списываются

### Лимиты запросов

| Что | Лимит |
|---|---|
| createTask и upload | 20 за 10 с на ключ |
| recordInfo / list / balance | 100 за 10 с на ключ |

Сверх лимита — HTTP 429 и `Retry-After`.
