Zum Hauptinhalt springen

Implementierungsleitfaden

Den Auftrag abschließen, wenn die Anfrage längst weg ist.

Ein Medienauftrag überlebt den HTTP-Aufruf, der ihn erzeugt hat, die Seite, die ihn ausgelöst hat, und oft auch das Deployment, das gerade lief. Hier geht es darum, das zu überstehen.

Die Herausforderung

Die Verbindung ist nicht die Transaktion

Zwischen Absenden und fertiger Datei gibt es vier Stellen, an denen Arbeit verloren geht: ein blind wiederholter Erstellungsaufruf nach Timeout, ein nicht prüfbarer Callback, eine Abfrageschleife, die hämmert oder aufgibt, und eine Ergebnis-URL, die abgelaufen ist, während Sie noch überlegt haben.

01

Eine Wiederholung ohne Schlüssel ist eine zweite Rechnung

Mit Idempotency-Key liefert eine Wiederholung desselben Modells, derselben Eingabe und desselben Callbacks innerhalb von 24 Stunden den ursprünglichen Auftrag zurück, ohne erneut zu reservieren. Der Schlüssel gilt je API-Schlüssel; ein anderer Schlüssel mit demselben Wert erhält 409 ohne Task-ID.

02

Ein ungeprüfter Callback ist ein offener Endpunkt

Zustellungen tragen X-Webhook-Timestamp und eine Base64-HMAC-SHA256 in X-Webhook-Signature über taskId.timestamp.sha256(raw_body). Prüfen Sie gegen die Rohbytes in konstanter Zeit und weisen Sie alte Zeitstempel ab, bevor Sie Auftrags- oder Abrechnungszustand ändern.

03

Abfragen ohne Obergrenze führen zum Rate Limit

recordInfo ist Rückfallebene, kein Transport. Starten Sie bei etwa zwei Sekunden, erhöhen Sie um die Hälfte, deckeln Sie bei fünfzehn und hören Sie zu einer Frist auf, die Sie gewählt haben.

Der Ansatz

Ein dauerhafter Datensatz je Auftrag, geschrieben vor der Antwort

Speichern Sie Idempotenzschlüssel, taskId und Ihre eigene Korrelations-ID in derselben Transaktion, in der Sie dem Aufrufer antworten. Jedes spätere Ereignis – Callback, Abfrage, Wiederholung, Supportfrage – löst gegen diese Zeile auf, und eine doppelte Zustellung wird zur Aktualisierung statt zur zweiten Bestellung.

Erst prüfen, dann lesen. Die Signatur deckt die Rohbytes ab, also wird erst nach dem Vergleich geparst.

Verify the callback before you trust it

import { createHash, createHmac, timingSafeEqual } from "node:crypto";

// rawBody is the exact bytes that arrived. Parse only to read the task ID:
// the digest is always computed over those raw bytes, never over a re-encode.
export function verifyDelivery(rawBody, headers, webhookKey) {
  const timestamp = headers["x-webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const taskId = JSON.parse(rawBody).data.taskId;          // payload version 2
  const digest = createHash("sha256").update(rawBody).digest("hex");
  const expected = createHmac("sha256", webhookKey)
    .update(`${taskId}.${timestamp}.${digest}`)
    .digest("base64");

  const sent = Buffer.from(headers["x-webhook-signature"] ?? "", "utf8");
  const mine = Buffer.from(expected, "utf8");
  return sent.length === mine.length && timingSafeEqual(sent, mine);
}

Delivery headers

X-Webhook-Timestamp: 1788652800
X-Webhook-Signature: <base64>
X-Webhook-Payload-Version: 2

{
  "code": 200,
  "msg": "success",
  "request_id": "whd_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "data": { "taskId": "job_01k3…", "state": "succeeded", "settled": true, … }
}

Vertrag

Was Sie früh festhalten sollten

Asynchrone Medien-API: Aufträge und Webhooks — Was Sie früh festhalten sollten
Feld oder HeaderWert oder Grenze
Idempotency-Key24 h · scoped to one API key
X-Webhook-Signaturebase64(HMAC-SHA256)
signed stringtaskId.timestamp.sha256(raw_body)
X-Webhook-Payload-Version2 for new integrations

Horizontal wischen, um alle Spalten zu sehen.

Integration

Vom ersten Aufruf bis in die Produktion

  1. 01Idempotenzschlüssel erzeugen, speichern und damit createTask senden; callBackUrl auf einen HTTPS-Endpunkt an Port 80 oder 443 setzen.
  2. 02data.taskId in die Datenbank schreiben, bevor dem Aufrufer geantwortet wird; im 202 taucht sie zuerst auf.
  3. 03Callback annehmen, Signatur gegen den Rohkörper prüfen, über request_id deduplizieren und den Datensatz aktualisieren.
  4. 04Ersatzweise recordInfo mit exponentiellem Backoff abfragen und output.assets vor Ablauf der signierten URL kopieren.

Passung

Wann dieser Weg der richtige ist

Dafür geeignet

  • Alles, was Medien erzeugt. Bild-, Video- und Audio-Endpunkte sind konstruktionsbedingt asynchron.
  • Sie brauchen einen dauerhaften Nachweis darüber, was gesendet wurde, was es kosten sollte und wie es endete.

Dafür nicht geeignet

  • Sie rufen ein Textmodell auf. Das streamt innerhalb der Anfrage und rechnet nach gemessener Nutzung ab.
  • Der Browser soll den Auftrag besitzen. Schlüssel gehören auf Ihren Server, der Auftragsdatensatz ebenso.

Belege

Was Sie selbst prüfen können

Jede Antwort trägt eine request_id

Der Umschlag lautet auf allen /api/v1-Operationen {code, msg, data, request_id}. In Payload-Version 2 bleibt die request_id einer Zustellung über Wiederholungen stabil und ist damit der natürliche Deduplizierungsschlüssel.

Reservierungen sind im Datensatz sichtbar

cost mit settled: false ist der reservierte Schätzwert, settled: true die Endabrechnung. Ein Erfolg übersteigt die Reservierung nie, Fehler und Ablauf geben sie vollständig frei.

Fehler nutzen ein geschlossenes Vokabular

errorCode ist einer von neun stabilen Werten: invalid_request, unsupported_combination, content_rejected, rate_limited, upstream_unavailable, generation_failed, timeout, invalid_asset, upstream_failed. Alles andere behandeln Sie als upstream_failed.

Vor dem Start

Plattformverhalten zum Bestätigen

  • Idempotenzschlüssel beim Auftrag speichern, nicht im Prozessspeicher.
  • Callback-Verarbeitung idempotent machen; Zustellungen werden planmäßig wiederholt.
  • Eine Abfragefrist setzen und bei Überschreitung alarmieren.
  • Ergebnisse vor expiresAt kopieren und die URL neu anfordern, statt eine signierte zu cachen.

Häufige Fragen

Was auf dieser Seite gefragt wird

Dieselbe Anfrage mit demselben Idempotency-Key wiederholen. Innerhalb von 24 Stunden und mit demselben API-Schlüssel erhalten Sie den ursprünglichen Auftrag ohne zweite Reservierung. Nach einem Timeout niemals einen neuen Körper senden – das ist ein neuer, separat berechneter Auftrag.

Weiter

Einen Auftragsablauf bauen, der ein Deployment übersteht

Lange Medienaufträge serverseitig senden und zuverlässig abschließen: Idempotenzschlüssel, signierte Callbacks, begrenzte Abfragen, fünf Zustände.

Weitere Leitfäden