aisplice

In Ihre App einbauen

Ergebnis-Callbacks

Webhooks verkürzen die Zeit zwischen dem Abschluss eines Tasks und dem Moment, in dem Ihre App davon erfährt. Sie sind eine Zustellungsoptimierung: drei Versuche, dann gibt das Gateway auf. Der Status-Endpunkt bleibt die maßgebliche Quelle.

#Callback beim Einreichen registrieren

Übergeben Sie webhook_url in der Einreichungsanfrage. Fügen Sie webhook_secret hinzu, dann wird jede Zustellung signiert — ohne es keine.

submit.sh
curl https://www.aisplice.store/v1/videos \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: video-job-8842" \
  -d '{
    "model": "doubao-seedance-2.5",
    "prompt": "A cinematic product scene",
    "webhook_url": "https://your.app/hooks/ai-tasks",
    "webhook_secret": "whsec_replace_me"
  }'

Muss öffentlich routbar sein

localhost, 127.0.0.1, private Adressbereiche, Link-Local- und Cloud-Metadaten-Adressen werden beim Einreichen des Tasks abgelehnt — nicht erst bei der Zustellung. Nutzen Sie während der Entwicklung einen Tunnel.

http oder https, beim Einreichen auflösbar

Der Hostname wird aufgelöst und jede zurückgegebene Adresse geprüft. Ein nicht auflösbarer Name lässt die Einreichung scheitern.

Zustellung nach bestem Bemühen

Drei Wiederholungen, danach hört das Gateway auf und protokolliert nur noch. Der Status-Endpunkt bleibt die maßgebliche Quelle.

localhost wird beim Einreichen des Tasks abgelehnt

Der Callback-Host wird aufgelöst und geprüft, bevor der Task angenommen wird; eine private oder Loopback-Adresse lässt also schon das Einreichen scheitern — nicht erst die Zustellung eine Stunde später. Richten Sie webhook_url während der Entwicklung auf einen öffentlichen Tunnel, oder lassen Sie es weg und fragen Sie ab.

#Header und Payload

HeaderGesendet, wennWas Sie damit tun
X-Xiaoxiang-SignatureNur wenn der Task mit webhook_secret eingereicht wurde.sha256=<hex HMAC-SHA256 des Roh-Bodys>. Vor dem Parsen prüfen, mit einem Vergleich in konstanter Zeit.
X-Xiaoxiang-EventJede Zustellung.task.completed oder task.failed — routen Sie anhand dieses Werts, statt den Zweck aus dem Payload abzuleiten.
X-Xiaoxiang-Event-IdJede Zustellung.Bleibt bei Wiederholungen desselben Ereignisses gleich. Speichern Sie ihn und verwerfen Sie Duplikate — das ist Ihr Deduplizierungsschlüssel.
FeldTypVorhandenBeschreibung
event_idstringImmerEntspricht X-Xiaoxiang-Event-Id. Deduplizieren Sie darüber.
eventstringImmer"task.completed" oder "task.failed".
task_idstringImmerDie vom Einreichungsaufruf zurückgegebene ID — Ihr Join-Schlüssel.
statusstringImmerEndstatus im Video-Vokabular — "completed" oder "failed", auch bei Bild- und Musik-Tasks.
modelstringWenn bekanntModell, das den Task erzeugt hat. Fehlt, wenn unbekannt.
urlstringBei ErfolgErgebnis-URL, wenn der Task erfolgreich war. Bevorzugen Sie /content für einen stabilen Plattformlink.
fail_reasonstringBei FehlschlagNur bei Fehlschlag vorhanden.
quotaintegerImmerTatsächlich verbrauchtes Kontingent in internen Einheiten. Gleichen Sie mit dem Nutzungsprotokoll ab, nicht mit diesem Feld.
created_atintegerImmerUnix-Sekunden, Einreichung des Tasks.
finished_atintegerImmerUnix-Sekunden, Übergang in den Endzustand.
delivery.json
{
  "event_id": "task_8f21c...:task.completed",
  "event": "task.completed",
  "task_id": "8f21c0d2-...",
  "status": "completed",
  "model": "doubao-seedance-2.5",
  "url": "https://cdn.example.com/renders/8f21c0d2.mp4",
  "quota": 128000,
  "created_at": 1789000000,
  "finished_at": 1789000184
}

#Rohen Anfrage-Body prüfen

Berechnen Sie HMAC-SHA256 über genau die empfangenen Bytes, vor jedem JSON-Parsing — eine erneute Serialisierung des Payloads ändert die Bytes und macht den Vergleich ungültig. Vergleichen Sie in konstanter Zeit und lehnen Sie bei Abweichung ab.

import crypto from "node:crypto";

// Express: express.raw({ type: "application/json" }) — not express.json().
export function handleTaskWebhook(req, res) {
  const received = req.get("X-Xiaoxiang-Signature") ?? "";
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", process.env.WEBHOOK_SECRET)
      .update(req.body)              // Buffer of the raw body
      .digest("hex");

  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).end();
  }

  const event = JSON.parse(req.body.toString("utf8"));
  // Deduplicate first, acknowledge fast, then do the work off-request.
  if (!seen.add(req.get("X-Xiaoxiang-Event-Id"))) return res.status(200).end();
  queue.push(event);
  res.status(200).end();
}

#Zustellung und Deduplizierung

Innerhalb von 15 Sekunden bestätigen

Das ist das Zustellungs-Timeout. Alles Langsamere zählt als fehlgeschlagener Versuch, stellen Sie die Arbeit also in eine Queue und geben Sie zuerst 2xx zurück.

Anhand der Event-ID deduplizieren

X-Xiaoxiang-Event-Id bleibt bei Wiederholungen gleich. Speichern Sie sie und verwerfen Sie Duplikate, bevor Sie den Geschäftszustand ändern.

Drei Wiederholungen, danach Stille

Fehlgeschlagene Zustellungen werden nach 5 s, 30 s und 2 min wiederholt. Danach protokolliert das Gateway nur noch — es kommt nichts mehr.

#Einen Abgleich-Poller beibehalten

Webhook-Zustellung nach bestem Bemühen

Lassen Sie einen selten laufenden Job über Tasks laufen, die in Ihrer Datenbank noch keinen Endzustand haben — schon ein Deployment während eines Zustellungsfensters kann eine Zustellung verpassen lassen. Fragen Sie den Status-Endpunkt ab, korrigieren Sie die Zeile und betrachten Sie den Webhook nur als Latenzgewinn.

Immer noch nicht gelöst?

Senden Sie uns die Anfrage-ID oder die Fehlermeldung, und wir sehen uns das an.