Webhooks
Empfange die Events deiner Sessions in deinem Backend: Jede Zustellung ist HMAC-SHA256-signiert, wird mit exponentiellem Backoff wiederholt und trägt eine eindeutige ID, damit dein Empfänger idempotent sein kann.
Wann Webhooks
Um auf den Raum zu reagieren, ohne zu pollen: Die Plattform ruft dich, wenn eine Session startet oder endet, eine Frage schließt oder ihre Ergebnisse konsolidiert sind. Die Zustellung ist at-least-once — sie kann sich wiederholen, geht nie still verloren — deshalb muss dein Empfänger idempotent sein.
Event-Katalog
Von der API unter /public/v1/limits ausgeliefert — diese Seite hält keine Kopie.
- presentation.import.completed
- presentation.import.failed
- question.activated
- question.closed
- question.results.finalized
- report.ready
- session.ended
- session.paused
- session.resumed
- session.started
Header jeder Zustellung
X-Votinova-EventDer Event-Typ, exakt wie im Katalog.X-Votinova-Delivery-IdEindeutig pro Zustellung — dein Deduplizierungsschlüssel.X-Votinova-TimestampEpoche in Sekunden; Teil des Signierten — eine wiederholte Zustellung kann nicht umdatiert werden.X-Votinova-SignatureHMAC-SHA256 in Hex, ohne Präfix.
Der Body ist kompaktes JSON mit dem Event und allen beteiligten IDs — dies ist, Byte für Byte, die signierte Beispielzustellung:
{"event":"session.ended","session_id":"68b2e3d4c5f607182930a5bc"}Signatur prüfen
Jede Zustellung ist mit HMAC-SHA256 über Zeitstempel, Punkt und Body signiert, mit dem Secret des Endpunkts. Vergleichen Sie das Ergebnis mit dem Header X-Votinova-Signature.
- Signieren Sie den ROHEN Body. Parsen und neu serialisieren ändert Leerzeichen, und die Signatur passt nicht mehr.
- Vergleichen Sie in konstanter Zeit, nicht mit ==.
const crypto = require("node:crypto");
function verify(headers, rawBody, secret) {
const timestamp = headers["x-votinova-timestamp"];
const signature = headers["x-votinova-signature"];
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}secret whsec_3f8a1c92d4e5b6a7
timestamp 1785321600
body {"event":"session.ended","session_id":"68b2e3d4c5f607182930a5bc"}
HMAC-SHA256(secret, timestamp + "." + body)
= 10a86171bd92f5fcf8c28b873978e0214302cc2291c54cc016d18347f3ee7c38Wiederholungen
Webhook-Zustellungen: bis zu 8 Versuche mit wachsenden Wartezeiten von 20, 41, 80, 185, 333, 669, 1413 Sekunden. Danach landet die Zustellung in der Dead-Letter-Liste und kann manuell erneut gesendet werden.
Idempotenz
Nutze X-Votinova-Delivery-Id als Deduplizierungsschlüssel: Eine Zustellung kann mehr als einmal ankommen, dein Effekt darf nur einmal wirken.
X-Votinova-Delivery-Id
Best Practices
- Antworte 200, sobald die Zustellung sicher ist, und verarbeite in deiner Queue — ein langsamer Empfänger stapelt Wiederholungen.
- Verifiziere IMMER die Signatur vor dem Parsen: Ohne sie kann jeder mit deiner URL Events erfinden.
- Dedupliziere über X-Votinova-Delivery-Id: At-least-once heißt, dieselbe Zustellung kann zweimal anrufen.
- Nach 10 Fehlern in Folge pausiert sich der Endpoint selbst; reaktiviere ihn im Workspace oder per API, sobald dein Empfänger zurück ist.