Webhooks

Ontvang de gebeurtenissen van uw sessies in uw backend: elke bezorging is ondertekend met HMAC-SHA256, wordt opnieuw geprobeerd met exponentiële backoff en draagt een uniek id, zodat uw ontvanger idempotent kan zijn.

Wanneer u webhooks gebruikt

Om te reageren op wat er in de ruimte gebeurt zonder te pollen: het platform roept uw endpoint aan wanneer een sessie start of eindigt, wanneer een vraag sluit of wanneer de resultaten definitief zijn. De bezorging is at-least-once – die kan zich herhalen, maar mislukt nooit stilletjes – en juist daarom moet uw ontvanger idempotent zijn.

Catalogus van gebeurtenissen

Geleverd door de API via /public/v1/limits – deze pagina bewaart er geen kopie van.

  • presentation.import.completed
  • presentation.import.failed
  • question.activated
  • question.closed
  • question.results.finalized
  • report.ready
  • session.ended
  • session.paused
  • session.resumed
  • session.started

Headers bij elke bezorging

  • X-Votinova-EventHet type gebeurtenis, precies zoals het in de catalogus staat.
  • X-Votinova-Delivery-IdUniek per bezorging – uw deduplicatiesleutel.
  • X-Votinova-TimestampSeconden sinds epoch; onderdeel van wat ondertekend wordt, zodat een herhaalde bezorging geen nieuwe datum kan krijgen.
  • X-Votinova-SignatureHMAC-SHA256 in hex, zonder prefix.

De body is compacte JSON met de gebeurtenis en elk betrokken id – dit is, byte voor byte, de ondertekende voorbeeldbezorging:

{"event":"session.ended","session_id":"68b2e3d4c5f607182930a5bc"}

De handtekening verifiëren

Elke bezorging wordt ondertekend met HMAC-SHA256 over de timestamp, een punt en de body, met het geheim van het endpoint als sleutel. Vergelijk het resultaat met de header X-Votinova-Signature.

  • Onderteken de RUWE body. Die parseren en opnieuw serialiseren verandert de witruimte, en dan klopt de handtekening niet meer.
  • Vergelijk in constante tijd, niet met ==.
Geverifieerd tegen een echte bezorging
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)
= 10a86171bd92f5fcf8c28b873978e0214302cc2291c54cc016d18347f3ee7c38

Opnieuw proberen

Webhook-bezorgingen: maximaal 8 pogingen, met oplopende wachttijden van 21, 45, 95, 171, 369, 732, 1480 seconden. Daarna belandt de bezorging in de dead-letterwachtrij en kunt u die handmatig opnieuw versturen.

Idempotentie

Gebruik X-Votinova-Delivery-Id als uw deduplicatiesleutel: een bezorging kan meer dan eens aankomen, en uw effect mag maar één keer worden toegepast.

X-Votinova-Delivery-Id

Aanbevolen werkwijzen

  • Antwoord met 200 zodra de bezorging veilig is en verwerk hem in uw eigen wachtrij – een trage ontvanger stapelt herhalingen op.
  • Verifieer ALTIJD de handtekening voordat u parseert: zonder die controle kan iedereen die uw URL kent gebeurtenissen verzinnen.
  • Dedupliceer op X-Votinova-Delivery-Id: at-least-once betekent dat dezelfde bezorging twee keer kan binnenkomen.
  • Na 10 mislukkingen op rij pauzeert het endpoint zichzelf; schakel het weer in vanuit het paneel of via de API zodra uw ontvanger terug is.