Webhooks
Ta imot hendelsene fra øktene dine i din egen backend: hver levering er signert med HMAC-SHA256, prøves på nytt med eksponentielt økende ventetid og bærer en unik id, slik at mottakeren din kan være idempotent.
Når du bør bruke webhooks
For å reagere på det som skjer i rommet uten å spørre om og om igjen: plattformen ringer deg når en økt starter eller slutter, når et spørsmål lukkes, eller når resultatene blir endelige. Leveringen skjer minst én gang – den kan gjenta seg, men den svikter aldri i stillhet – og nettopp derfor må mottakeren din være idempotent.
Hendelseskatalog
Leveres av API-et på /public/v1/limits – denne siden har ingen egen kopi.
- presentation.import.completed
- presentation.import.failed
- question.activated
- question.closed
- question.results.finalized
- report.ready
- session.ended
- session.paused
- session.resumed
- session.started
Headere på hver levering
X-Votinova-EventHendelsestypen, nøyaktig slik den står i katalogen.X-Votinova-Delivery-IdUnik per levering – nøkkelen din for duplikatfjerning.X-Votinova-TimestampSekunder siden epoken; den er en del av det som signeres, så en levering som spilles av på nytt, kan ikke få ny dato.X-Votinova-SignatureHMAC-SHA256 i heks, uten prefiks.
Kroppen er kompakt JSON med hendelsen og alle id-ene som er involvert – dette er, byte for byte, den signerte eksempelleveringen:
{"event":"session.ended","session_id":"68b2e3d4c5f607182930a5bc"}Slik verifiserer du signaturen
Hver levering signeres med HMAC-SHA256 over tidsstempelet, et punktum og kroppen, med hemmeligheten til endepunktet som nøkkel. Sammenlign resultatet med X-Votinova-Signature-headeren.
- Signer den RÅ kroppen. Tolker du den og serialiserer den på nytt, endres blanktegnene, og signaturen stemmer ikke lenger.
- Sammenlign i konstant tid, ikke med ==.
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)
= 10a86171bd92f5fcf8c28b873978e0214302cc2291c54cc016d18347f3ee7c38Nye forsøk
Webhook-leveringer: opptil 8 forsøk, med økende ventetid på 21, 45, 95, 171, 369, 732, 1480 sekunder. Når de er brukt opp, blir leveringen oppgitt og kan sendes på nytt for hånd.
Idempotens
Bruk X-Votinova-Delivery-Id som nøkkel for duplikatfjerning: en levering kan komme mer enn én gang, og effekten din skal bare skje én gang.
X-Votinova-Delivery-Id
Beste praksis
- Svar 200 så snart leveringen er trygt lagret, og behandle den i din egen kø – en treg mottaker hoper opp nye forsøk.
- Verifiser ALLTID signaturen før du tolker innholdet: uten den kan hvem som helst som kjenner URL-en din, finne på hendelser.
- Fjern duplikater etter X-Votinova-Delivery-Id: minst én gang betyr at den samme leveringen kan ringe to ganger.
- Etter 10 mislykkede forsøk på rad setter endepunktet seg selv på pause; slå det på igjen fra panelet eller via API-et når mottakeren din er tilbake.