EN ZalogujZałóż konto
Startujemy w październiku 2026. Działają konta, katalog modeli, kalkulator i dokumentacja. Studio jest dostępne w podglądzie; generowanie czeka na uruchomienie.

Seedance 2.5 w Pythonie - wideo przez API krok po kroku

Ile kosztuje sekunda wideo z Seedance 2.5 przez API, jak wysłać zadanie w curl i Pythonie, odebrać plik MP4 i nie płacić za nieudane generacje.

Seedance 2.5 przez API Jantarisa kosztuje od 1,51 zł za sekundę i płacisz tylko za sekundy gotowego wideo. Wysyłasz POST /v1/generate z modelem seedance-2.5, dostajesz identyfikator zadania, a po minucie czy kilku odbierasz plik MP4 z GET /v1/tasks/{id}. Poniżej masz działające przykłady w curl i Pythonie, przeliczenie kosztów dla typowych długości i listę błędów, na które sam się nadziałem.

Czym jest Seedance 2.5 i co potrafi

Seedance 2.5 to model wideo od ByteDance Seed, pokazany 31 lipca 2026. Producent chwali się trzema rzeczami: do 30 sekund wideo w jednym przebiegu, dźwięk generowany razem z obrazem (efekty, mowa, muzyka) i bardzo szerokie wejście referencyjne. Według ogłoszenia ByteDance jedno zadanie może dostać do 30 obrazów, 10 klipów wideo i 10 ścieżek audio jako referencje. Do tego dochodzi edycja istniejącego wideo i przedłużanie klipu w kolejnych rundach.

Dla mnie najważniejsza zmiana względem 2.0 to długość. Wcześniej rolkę 25-sekundową trzeba było sklejać z kilku ujęć i pilnować, żeby postać nie zmieniała twarzy między cięciami. Teraz jedno ujęcie na całą długość rolki jest realne.

Czego nie obiecuję: rozdzielczości. Oficjalne materiały ByteDance jej nie podają, a różne platformy oferują 480p, 720p, czasem 1080p. W Jantarisie listę dozwolonych wartości zwraca schemat modelu:

bash
curl https://jantaris.com/v1/models/seedance-2.5

W odpowiedzi szukaj pola input_schema - tam są dozwolone resolution, aspect_ratio i zakres duration. Endpoint jest publiczny, klucz nie jest potrzebny.

Ile kosztuje Seedance 2.5 przez API

Cena Seedance 2.5 to od 1,51 zł za sekundę. Rozliczenie jest za sekundę wygenerowanego wideo, więc koszt klipu to po prostu cena za sekundę razy długość.

Długość klipuJak liczyćTypowe użycie
5 s5 × od 1,51 zł za sekundętest promptu, B-roll
10 s10 × od 1,51 zł za sekundękrótkie ujęcie reklamowe
15 s15 × od 1,51 zł za sekundęrolka z jednym ujęciem
30 s30 × od 1,51 zł za sekundępełna rolka w jednym przebiegu

Na koncie PL cena jest w złotówkach brutto, z 23% VAT, a fakturę dostajesz automatycznie po każdym doładowaniu. Aktualne stawki wszystkich modeli wideo są w cenniku.

Dwie rzeczy, które zmieniają realny koszt bardziej niż sama stawka:

  • Nieudane generacje nie są płatne. Jeśli zadanie skończy się statusem failed, blokada środków wraca w całości, a cost wynosi 0.
  • Poprawki są płatne. Jeśli wideo się wygenerowało, ale ci się nie podoba, to jest udana generacja. Dlatego testuję prompty na 5 sekundach, a dopiero potem puszczam pełną długość.

Przed wysłaniem zadania wiesz, ile zapłacisz. Odpowiedź na POST /v1/generate zawiera estimated_cost, a ta kwota jest blokowana na saldzie do czasu zakończenia zadania.

Pierwsze wideo w curl

Potrzebujesz konta i klucza. Rejestracja zajmuje chwilę, minimalne doładowanie to 40 zł, a klucz (sk-jt-...) tworzysz w panelu. Szczegóły w szybkim starcie.

Klucz trzymam w zmiennej środowiskowej:

bash
export JANTARIS_API_KEY="sk-jt-..."

Wysłanie zadania:

bash
curl https://jantaris.com/v1/generate \
  -H "Authorization: Bearer $JANTARIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5",
    "input": {
      "prompt": "A fisherman pulls a net onto a wooden boat at dawn, slow handheld camera, mist over the water, waves and seagulls",
      "duration": 5,
      "resolution": "720p",
      "aspect_ratio": "16:9",
      "generate_audio": true
    }
  }'

Serwer odpowiada od razu kodem 202:

json
{
  "id": "task_8f2k...",
  "object": "task",
  "status": "queued",
  "model": "seedance-2.5",
  "estimated_cost": { "amount": "...", "currency": "PLN" },
  "poll_url": "https://jantaris.com/v1/tasks/task_8f2k..."
}

Status sprawdzasz tak:

bash
curl https://jantaris.com/v1/tasks/task_8f2k... \
  -H "Authorization: Bearer $JANTARIS_API_KEY"

Gdy status zmieni się na succeeded, w polu output jest link do pliku. Link jest ważny ograniczony czas, więc pobieraj od razu.

Seedance 2.5 w Pythonie: pełny skrypt

Ten skrypt wysyła zadanie, czeka na wynik z rosnącym odstępem między zapytaniami i zapisuje MP4 na dysku. Używam go jako bazy do większości swoich eksperymentów.

python
import os
import time
import pathlib
import requests

API = "https://jantaris.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['JANTARIS_API_KEY']}"}


def generate_video(prompt: str, duration: int = 5, aspect_ratio: str = "16:9",
                   resolution: str = "720p", image_url: str | None = None) -> dict:
    payload = {
        "model": "seedance-2.5",
        "input": {
            "prompt": prompt,
            "duration": duration,
            "resolution": resolution,
            "aspect_ratio": aspect_ratio,
            "generate_audio": True,
        },
    }
    if image_url:
        payload["input"]["image_url"] = image_url

    r = requests.post(f"{API}/generate", headers=HEADERS, json=payload, timeout=30)
    if r.status_code != 202:
        raise RuntimeError(f"{r.status_code}: {r.json()['error']['message']}")
    task = r.json()
    print("zadanie:", task["id"], "szacowany koszt:", task["estimated_cost"])
    return task


def wait_for_task(task_id: str, timeout: int = 900) -> dict:
    delay, deadline = 3, time.time() + timeout
    while time.time() < deadline:
        task = requests.get(f"{API}/tasks/{task_id}", headers=HEADERS, timeout=30).json()
        if task["status"] in ("succeeded", "failed"):
            return task
        time.sleep(delay)
        delay = min(delay * 1.5, 20)
    raise TimeoutError(task_id)


def download(task: dict, folder: str = "wideo") -> list[pathlib.Path]:
    pathlib.Path(folder).mkdir(exist_ok=True)
    saved = []
    for i, item in enumerate(task["output"]):
        path = pathlib.Path(folder) / f"{task['id']}_{i}.mp4"
        with requests.get(item["url"], stream=True, timeout=180) as r:
            r.raise_for_status()
            with open(path, "wb") as f:
                for chunk in r.iter_content(1 << 20):
                    f.write(chunk)
        saved.append(path)
    return saved


if __name__ == "__main__":
    task = generate_video(
        "Close-up of hands kneading dough on a floured table, warm kitchen light, "
        "slow push-in, soft ambient sound",
        duration=5,
    )
    done = wait_for_task(task["id"])
    if done["status"] == "succeeded":
        print("koszt:", done["cost"], "pliki:", download(done))
    else:
        print("nieudane, nic nie płacisz:", done["error"])

Kilka uwag do kodu:

  • timeout=30 przy POST wystarcza, bo serwer nie czeka na wideo, tylko przyjmuje zadanie.
  • Pętla odpytuje najpierw co 3 sekundy, potem rzadziej, maksymalnie co 20. Przy wideo nie ma sensu odpytywać częściej.
  • generate_audio: True włącza dźwięk generowany razem z obrazem. Jeśli podkład i tak dokładasz w montażu, ustaw False.
  • Parametr ?wait=60 działa też przy wideo, ale Seedance zwykle potrzebuje więcej niż minutę, więc przy wideo go nie używam. Przy obrazach to wygodny skrót, opisuję go w poradniku o obrazach w Pythonie.

Wideo z obrazu (image-to-video)

Kiedy zależy mi na konkretnym kadrze, na przykład produkt w określonym ustawieniu albo postać z wcześniej zrobionej grafiki, podaję pierwszą klatkę w image_url. Obraz musi być dostępny pod publicznym adresem HTTPS.

python
task = generate_video(
    prompt="The camera slowly orbits the bottle, light reflections move across the glass, "
           "condensation drops run down",
    duration=5,
    aspect_ratio="9:16",
    image_url="https://twoja-domena.pl/pliki/butelka.png",
)

Pierwszą klatkę robię najczęściej w Nano Banana Pro albo GPT Image 2.5, a dopiero potem animuję. Ta kolejność jest tańsza: obraz kosztuje ułamek sekundy wideo, więc kompozycję poprawiam na obrazach, a do Seedance idzie już gotowy kadr. Cały ten łańcuch z kosztami rozpisałem w tekście ile kosztuje rolka z AI.

Webhook zamiast odpytywania

Przy kilkunastu zadaniach naraz pętla z odpytywaniem robi się niewygodna. Wtedy dodaję webhook_url, a Jantaris wysyła POST z tym samym JSON-em, który zwraca GET /v1/tasks/{id}, kiedy zadanie się skończy.

bash
curl https://jantaris.com/v1/generate \
  -H "Authorization: Bearer $JANTARIS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "seedance-2.5",
    "input": { "prompt": "Rain on a neon street at night, slow dolly", "duration": 10, "aspect_ratio": "9:16" },
    "webhook_url": "https://twoj-serwer.pl/jantaris-hook"
  }'

Każde powiadomienie ma nagłówek x-jantaris-signature z podpisem HMAC-SHA256 ciała żądania. Sekret webhooka bierzesz z panelu. Minimalny odbiornik we Flasku:

python
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["JANTARIS_WEBHOOK_SECRET"].encode()

@app.post("/jantaris-hook")
def hook():
    expected = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("x-jantaris-signature", "")):
        abort(401)
    task = request.get_json()
    if task["status"] == "succeeded":
        print("gotowe:", task["output"][0]["url"])
    return "", 204

Dokładny format podpisu i zasady ponawiania są w dokumentacji webhooków.

Prompty do Seedance 2.5, które działają

Po kilkudziesięciu generacjach mam kilka zasad:

  1. Pisz po angielsku. Polskie prompty model rozumie, ale angielskie dają u mnie przewidywalniejszy ruch kamery.
  2. Opisuj ruch kamery wprost: "slow push-in", "handheld", "static tripod shot", "orbit". Bez tego model wymyśla ruch sam, często za dużo.
  3. Dźwięk też opisz. Przy generate_audio: true dopisuję na końcu, co ma być słychać: "waves and seagulls", "quiet cafe chatter".
  4. Kwestie mówione daj w cudzysłowie i po angielsku. Polską mowę w modelach wideo traktuję jako loterię, lektora nagrywam osobno.
  5. Jedno ujęcie, jedna akcja. Trzydzieści sekund kusi, żeby wcisnąć całą fabułę. Lepiej działa jedna czynność rozpisana dokładnie.

Błędy API i co z nimi robić

KodCo znaczyCo robię
401zły albo brak kluczasprawdzam zmienną JANTARIS_API_KEY
402saldo niższe niż estimated_costdoładowuję (BLIK działa od ręki)
404literówka w identyfikatorze modelupoprawiam na seedance-2.5
422parametr poza schematem, np. zła rozdzielczośćczytam error.message, porównuję z input_schema
429za dużo zapytańczekam i ponawiam z opóźnieniem
502błąd po stronie dostawcyponawiam później

Zadanie, które zostało przyjęte, a potem się nie udało, nie zwraca błędu HTTP. Ma po prostu status: "failed" i obiekt error. Pełna lista jest w dokumentacji błędów.

Seedance 2.5 czy inny model wideo

Seedance 2.5 wybieram, kiedy potrzebuję długiego ujęcia z dźwiękiem albo dużo referencji. Do krótkich, filmowych ujęć z bardzo dopracowanym światłem sprawdzam też Veo 3.1 (Quality), a przy ujęciach wielokadrowych Kling 3.0. Zestawienie z tabelą parametrów i cen jest w porównaniu API do wideo AI. Jeśli wolisz klikać zamiast pisać kod, ten sam model i to samo saldo są w Jantaris Studio.

FAQ

Ile kosztuje 10 sekund wideo z Seedance 2.5?

Dziesięciokrotność ceny za sekundę, czyli 10 × od 1,51 zł za sekundę. Dokładną kwotę dla konkretnego zadania zobaczysz w polu estimated_cost od razu po jego wysłaniu.

Jak długie wideo generuje Seedance 2.5?

Według ByteDance do 30 sekund w jednym przebiegu. Zakres parametru duration dostępny w Jantarisie sprawdzisz w schemacie modelu pod GET /v1/models/seedance-2.5.

Czy płacę za nieudane generacje?

Nie. Gdy zadanie kończy się statusem failed, zablokowane środki wracają na saldo w całości, a koszt wynosi 0.

Czy mogę dostać fakturę VAT za Seedance 2.5?

Tak. Na koncie PL faktura VAT z NIP-em wystawia się automatycznie po każdym doładowaniu, a płacić można BLIK-iem albo kartą.

Jak długo są dostępne wygenerowane pliki?

Linki z pola output są ważne ograniczony czas, więc pobieraj pliki od razu po zakończeniu zadania. W Studio historia generacji zostaje na koncie.