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.

Zadania

Wszystkie strony dokumentacji

Każde wywołanie POST /v1/generate tworzy zadanie. GET /v1/tasks/{id} zwraca jego bieżący stan, a po zakończeniu także pliki wynikowe i ostateczny koszt.

Zapytanie

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

Pole poll_url z odpowiedzi /v1/generate zawiera już pełny adres.

Odpowiedź

json
{
  "id": "task_8f2k...",
  "status": "succeeded",
  "model": "seedance-2.5",
  "output": [
    { "type": "video", "url": "https://...", "duration": 5, "width": 1280, "height": 720 }
  ],
  "cost": { "amount": "3.10", "currency": "PLN" },
  "error": null,
  "created_at": "2026-09-27T10:15:02Z",
  "completed_at": "2026-09-27T10:16:41Z"
}
PoleTypOpis
idstringId zadania
statusstringqueued, running, succeeded albo failed
modelstringId modelu
outputarrayPliki wynikowe, wypełnione przy succeeded
costobject{amount, currency} pobrane za zadanie. 0 przy failed
errorobject lub null{type, message} przy failed
created_atstringZnacznik czasu ISO 8601
completed_atstring lub nullZnacznik czasu ISO 8601, ustawiany po zakończeniu

Statusy

StatusZnaczenieKońcowy
queuedPrzyjęte, czeka na start. Środki są zablokowanenie
runningGenerowanie trwanie
succeededWynik gotowy, cost pobranytak
failedGenerowanie się nie udało, blokada zwolniona, płacisz 0tak

Elementy output

PoleWystępuje przyOpis
typewszystkichimage, video albo audio
urlwszystkichTymczasowy link do pobrania
width, heightobraz, wideoPiksele
durationwideo, audioSekundy

Zadanie nieudane:

json
{
  "id": "task_3xq1...",
  "status": "failed",
  "model": "kling-3.0",
  "output": [],
  "cost": { "amount": "0.00", "currency": "PLN" },
  "error": { "type": "upstream_error", "message": "The model could not complete this request." },
  "created_at": "2026-09-27T10:20:00Z",
  "completed_at": "2026-09-27T10:21:12Z"
}

Odpytywanie

Sprawdzaj zadanie co kilka sekund, aż status będzie końcowy. Obrazom zwykle wystarczy kilka sekund, wideo potrafi trwać kilka minut.

python
import os, time, requests

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

def wait_for_task(task_id: str, timeout: int = 900) -> dict:
    delay, deadline = 2, 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, 15)  # wydłużaj odstęp do 15 s
    raise TimeoutError(f"zadanie {task_id} trwa dłużej niż {timeout} s")

task = requests.post(
    f"{API}/generate",
    headers=HEADERS,
    json={"model": "kling-3.0", "input": {"prompt": "A paper boat drifting down a rainy street", "duration": 5}},
    timeout=30,
).json()

done = wait_for_task(task["id"])
print(done["status"], done["cost"], done["output"] or done["error"])
javascript
const API = "https://jantaris.com/v1";
const headers = { Authorization: `Bearer ${process.env.JANTARIS_API_KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function waitForTask(id, timeoutMs = 900_000) {
  let delay = 2000;
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    const task = await (await fetch(`${API}/tasks/${id}`, { headers })).json();
    if (task.status === "succeeded" || task.status === "failed") return task;
    await sleep(delay);
    delay = Math.min(delay * 1.5, 15000);
  }
  throw new Error(`zadanie ${id} nadal trwa`);
}

const started = await (await fetch(`${API}/generate`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ model: "kling-3.0", input: { prompt: "A paper boat drifting down a rainy street", duration: 5 } }),
})).json();

const done = await waitForTask(started.id);
console.log(done.status, done.cost, done.output ?? done.error);

Przy długich zadaniach albo wielu zadaniach naraz webhooki zastępują pętlę odpytywania.

Pobieranie wyników

Linki w output są tymczasowe. Pobierz pliki, które chcesz zachować, i trzymaj je u siebie.

python
import pathlib

def download_outputs(task: dict, folder: str = "out") -> list[pathlib.Path]:
    ext = {"image": "png", "video": "mp4", "audio": "mp3"}
    paths = []
    pathlib.Path(folder).mkdir(exist_ok=True)
    for i, item in enumerate(task["output"]):
        path = pathlib.Path(folder) / f"{task['id']}_{i}.{ext[item['type']]}"
        with requests.get(item["url"], stream=True, timeout=120) as r:
            r.raise_for_status()
            with open(path, "wb") as f:
                for chunk in r.iter_content(1 << 20):
                    f.write(chunk)
        paths.append(path)
    return paths
javascript
import { writeFile, mkdir } from "node:fs/promises";

async function downloadOutputs(task, folder = "out") {
  await mkdir(folder, { recursive: true });
  for (const [i, item] of task.output.entries()) {
    const res = await fetch(item.url);
    const buf = Buffer.from(await res.arrayBuffer());
    await writeFile(`${folder}/${task.id}_${i}`, buf);
  }
}

Rozszerzenie pliku w przykładzie jest zgadywane po typie. Jeśli potrzebujesz dokładnego formatu, odczytaj nagłówek Content-Type pobieranego pliku.

Błędy

Statuserror.typeKiedy
401authentication_errorZły albo brakujący klucz
404not_foundZadanie nie istnieje albo należy do innego konta

Szczegóły: Błędy.