Webhooks: Events, Payloads und Signaturen

Mit Webhooks können deine eigenen Systeme in dem Moment reagieren, in dem Inwista fertig ist: Wenn eine Transkription abgeschlossen oder ein Video-Export gerendert ist, POSTet Inwista ein signiertes JSON-Event an einen HTTPS-Endpunkt unter deiner Kontrolle. Nutze das, um Publishing-Pipelines, Archivsysteme, Projekt-Tracker zu füttern — alles, was nach getaner Inwista-Arbeit automatisch passieren soll.

Einrichtung und das Signing-Secret

Verbinde unter My workspaceIntegrations die Webhooks-Karte und gib deine Endpunkt-URL ein (HTTPS erforderlich). Inwista generiert ein Signing-Secret mit dem Präfix whsec_ und zeigt es genau einmal an — lege es sofort in deinem Secret-Manager ab. Du kannst das Secret jederzeit über die Integrationseinstellungen rotieren; das alte Secret verliert sofort seine Gültigkeit.

Nutze Send test event in den Einstellungen, um ein signiertes webhook.test-Event an deinen Endpunkt zu feuern und die Verkabelung vor echtem Traffic zu bestätigen. Änderst du später die Endpunkt-URL, bleibt das Secret dasselbe.

Events

  • transcript.completed Wird einmal pro Projekt ausgelöst, wenn die initiale Transkription abgeschlossen ist. Enthält Download-Links für die Transkript-Dateien in den auf der Integration konfigurierten Formaten.
  • export.completed Wird bei jedem abgeschlossenen Video-Rendering ausgelöst. Enthält das gerenderte Video plus frische Transkript-Dateien, die alle seit der Transkription vorgenommenen Untertitel-Änderungen widerspiegeln.
  • webhook.test Wird manuell aus den Integrationseinstellungen ausgelöst, zum Verifizieren deines Receivers.

Beide Event-Typen lassen sich in den Integrationseinstellungen unabhängig voneinander umschalten. Events feuern bei jedem abonnierten Vorkommnis, unabhängig von den Speicher-Auswahlen einzelner Exporte — Webhooks sind Benachrichtigungen, keine Zustellungsziele.

Payload

Jedes Event teilt dieselbe Hülle: einen event-Typ, eine eindeutige id zur Deduplizierung, einen Unix-timestamp, die workspaceId und einen project-Block. Events mit Dateien ergänzen ein files-Array; export.completed enthält zusätzlich ein video-Objekt.

{
  "event": "export.completed",
  "id": "evt_9c1b7e2a4f0d4b6e8a12",
  "timestamp": 1784034017,
  "workspaceId": "UK6naH1L1sMtzTVcVZih",
  "project": {
    "id": "abc123def456",
    "name": "Interview — Episode 12",
    "language": "no",
    "durationSeconds": 1834
  },
  "files": [
    {
      "format": "srt",
      "name": "Interview — Episode 12.srt",
      "mimeType": "application/x-subrip",
      "url": "https://storage.googleapis.com/...signed...",
      "expiresAt": 1784120417
    }
  ],
  "video": {
    "name": "Interview — Episode 12.mp4",
    "mimeType": "video/mp4",
    "sizeBytes": 812340221,
    "url": "https://storage.googleapis.com/...signed...",
    "expiresAt": 1784120417
  }
}

Die url-Werte sind signierte Download-Links mit 24 Stunden Gültigkeit (der expiresAt-Unix-Timestamp sagt exakt wann) — hole dir zeitnah, was du brauchst, statt die Links zu speichern. transcript.completed hat dieselbe Form, nur ohne das video-Objekt.

Signaturen verifizieren

Jeder Request trägt drei Header: X-Inwista-Event (der Event-Typ), X-Inwista-Delivery (die Event-ID) und X-Inwista-Signature — ein HMAC-SHA256 über den rohen Request-Body, berechnet mit deinem Signing-Secret. Berechne ihn nach und vergleiche, bevor du dem Payload vertraust; ohne diese Prüfung könnte jeder, der deine Endpunkt-URL entdeckt, dir gefälschte Events unterschieben.

const crypto = require("crypto");

function verifyInwistaSignature(rawBody, signatureHeader, secret) {
  const expected =
    "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return (
    signatureHeader.length === expected.length &&
    crypto.timingSafeEqual(
      Buffer.from(signatureHeader),
      Buffer.from(expected),
    )
  );
}

// Express-Beispiel — den Raw-Body für die Verifizierung erfassen:
// app.post("/inwista-hook", express.raw({ type: "application/json" }), (req, res) => {
//   if (!verifyInwistaSignature(req.body, req.get("X-Inwista-Signature"), process.env.INWISTA_WEBHOOK_SECRET)) {
//     return res.status(401).end();
//   }
//   const event = JSON.parse(req.body);
//   res.status(200).end(); // schnell bestätigen, asynchron verarbeiten
// });

Wichtig: Berechne den HMAC über den rohen Request-Body, nicht über eine neu serialisierte Version des geparsten JSON — Unterschiede in Schlüsselreihenfolge und Whitespace lassen den Vergleich scheitern.

Zustellung, Wiederholungen und Deduplizierung

  • Mit 2xx bestätigen Antworte innerhalb von 10 Sekunden. Erledige schwere Verarbeitung asynchron nach der Bestätigung — eine langsame Antwort zählt als Fehlschlag.
  • Wiederholungen Fehlgeschlagene Zustellungen werden bis zu zweimal wiederholt (ungefähr 10 und 30 Sekunden später). Antworten im 4xx-Bereich gelten als endgültig und werden nicht wiederholt, mit Ausnahme von 408 und 429.
  • Per ID deduplizieren Nimmt dein Server einen Request an, geht aber die Antwort verloren, kann eine Wiederholung dasselbe Event zweimal zustellen. Das id-Feld ist über Wiederholungen hinweg stabil — nutze es, um Duplikate zu ignorieren.
  • Automatische Pause Nach 10 aufeinanderfolgenden fehlgeschlagenen Zustellungen pausiert Inwista den Endpunkt und zeigt den Grund in den Integrationseinstellungen an, wo du ihn wieder aktivieren kannst, sobald dein Receiver repariert ist. Status und HTTP-Code der letzten Zustellung sind dort immer sichtbar.