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.

Webhooki

Wszystkie strony dokumentacji

Podaj webhook_url w POST /v1/generate, a Jantaris wyśle na ten adres zapytanie POST, gdy zadanie dojdzie do succeeded albo failed. Bez pętli odpytywania.

Treść

Ciało to ten sam JSON, który zwraca GET /v1/tasks/{id}:

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"
}

Nagłówki

NagłówekWartość
Content-Typeapplication/json
x-jantaris-eventtask.succeeded albo task.failed
x-jantaris-signaturesha256=<hex>, HMAC-SHA256 surowego ciała zapytania z twoim sekretem webhooka

Sekret webhooka znajdziesz w panelu. Trzymaj go na serwerze, tak jak klucz API.

Weryfikacja podpisu

Licz HMAC-SHA256 z surowych bajtów ciała dokładnie w takiej postaci, w jakiej przyszły, przed parsowaniem JSON-a, i porównuj z nagłówkiem w stałym czasie. Zapytania z niezgodnym podpisem odrzucaj.

python
# pip install flask
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ["JANTARIS_WEBHOOK_SECRET"].encode()
seen = set()  # na produkcji tabela w bazie

@app.post("/jantaris-hook")
def jantaris_hook():
    raw = request.get_data()  # surowe bajty
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    received = request.headers.get("x-jantaris-signature", "")
    if not hmac.compare_digest(expected, received):
        abort(401)

    task = request.get_json()
    event = request.headers.get("x-jantaris-event")
    if task["id"] in seen:
        return "", 200  # duplikat
    seen.add(task["id"])

    enqueue_processing(task, event)  # twój kod: wrzuć do kolejki i szybko odpowiedz
    return "", 200
javascript
// npm install express
import express from "express";
import crypto from "node:crypto";

const app = express();
const SECRET = process.env.JANTARIS_WEBHOOK_SECRET;
const seen = new Set(); // na produkcji tabela w bazie

app.post("/jantaris-hook", express.raw({ type: "application/json" }), (req, res) => {
  const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
  const received = req.get("x-jantaris-signature") ?? "";
  const ok =
    expected.length === received.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
  if (!ok) return res.sendStatus(401);

  const task = JSON.parse(req.body.toString("utf8"));
  if (seen.has(task.id)) return res.sendStatus(200);
  seen.add(task.id);

  queueMicrotask(() => processTask(task, req.get("x-jantaris-event"))); // twój kod
  res.sendStatus(200);
});

app.listen(3000);

Częsty błąd: weryfikacja na JSON.stringify(req.body) po parserze JSON. Ponownie zserializowany JSON różni się od oryginalnych bajtów i podpis się nie zgodzi. Licz podpis z surowego ciała.

Ponowienia

Pierwsza próba doręczenia idzie od razu po zakończeniu zadania. Jeśli twój endpoint nie odpowie statusem 2xx (albo nie odpowie wcale), Jantaris ponawia do 5 razy, z coraz dłuższymi przerwami:

PonowienieOdstęp od poprzedniej próby
110 s
21 min
35 min
430 min
52 h

Po ostatnim nieudanym ponowieniu doręczenie przepada. Samo zadanie dalej jest dostępne przez GET /v1/tasks/{id}.

Zasady obsługi

  • Odpowiadaj 2xx szybko. Zapisz treść, cięższą pracę (pobieranie plików, transkodowanie) wrzuć do kolejki i zwróć odpowiedź. Wolna odpowiedź liczy się jak błąd i uruchamia ponowienie.
  • Odrzucaj duplikaty po id zadania. Ponowienie może dojść, mimo że pierwsze doręczenie już obsłużyłeś, np. gdy twoja odpowiedź 200 zginęła w sieci. Zapisuj obsłużone id i pomijaj powtórki.
  • Pobieraj wyniki od razu. Linki w output są tymczasowe.
  • Miej plan B. Jeśli serwer leżał dłużej niż okno ponowień, wywołaj GET /v1/tasks/{id} dla zadań, o których nie dostałeś informacji.

Testy lokalne

webhook_url musi być osiągalny z internetu. W trakcie pracy wystaw lokalny port przez dowolny tunel i podaj publiczny adres jako webhook_url. Możesz też odtworzyć zapisaną treść curl-em, samodzielnie ją podpisując:

bash
BODY='{"id":"task_test","status":"succeeded","model":"gpt-image-2.5","output":[],"cost":{"amount":"0.00","currency":"PLN"},"error":null}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$JANTARIS_WEBHOOK_SECRET" | sed 's/^.* //')
curl -X POST http://localhost:3000/jantaris-hook \
  -H "Content-Type: application/json" \
  -H "x-jantaris-event: task.succeeded" \
  -H "x-jantaris-signature: sha256=$SIG" \
  -d "$BODY"