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.
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
#Header und Payload
| Header | Gesendet, wenn | Was Sie damit tun |
|---|---|---|
| X-Xiaoxiang-Signature | Nur 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-Event | Jede Zustellung. | task.completed oder task.failed — routen Sie anhand dieses Werts, statt den Zweck aus dem Payload abzuleiten. |
| X-Xiaoxiang-Event-Id | Jede Zustellung. | Bleibt bei Wiederholungen desselben Ereignisses gleich. Speichern Sie ihn und verwerfen Sie Duplikate — das ist Ihr Deduplizierungsschlüssel. |
| Feld | Typ | Vorhanden | Beschreibung |
|---|---|---|---|
| event_id | string | Immer | Entspricht X-Xiaoxiang-Event-Id. Deduplizieren Sie darüber. |
| event | string | Immer | "task.completed" oder "task.failed". |
| task_id | string | Immer | Die vom Einreichungsaufruf zurückgegebene ID — Ihr Join-Schlüssel. |
| status | string | Immer | Endstatus im Video-Vokabular — "completed" oder "failed", auch bei Bild- und Musik-Tasks. |
| model | string | Wenn bekannt | Modell, das den Task erzeugt hat. Fehlt, wenn unbekannt. |
| url | string | Bei Erfolg | Ergebnis-URL, wenn der Task erfolgreich war. Bevorzugen Sie /content für einen stabilen Plattformlink. |
| fail_reason | string | Bei Fehlschlag | Nur bei Fehlschlag vorhanden. |
| quota | integer | Immer | Tatsächlich verbrauchtes Kontingent in internen Einheiten. Gleichen Sie mit dem Nutzungsprotokoll ab, nicht mit diesem Feld. |
| created_at | integer | Immer | Unix-Sekunden, Einreichung des Tasks. |
| finished_at | integer | Immer | Unix-Sekunden, Übergang in den Endzustand. |
{
"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
Immer noch nicht gelöst?
Senden Sie uns die Anfrage-ID oder die Fehlermeldung, und wir sehen uns das an.