Webhooks sturen quizactiviteit naar je eigen endpoint op het moment dat die plaatsvindt. Deze naslag noemt de topics, de velden in elke payload en hoe de aflevering werkt. Een webhook maak je aan via Integrations → Developer area → Webhooks. Zie ook webhooks instellen.
Topics
| Topic | Verstuurd wanneer | Te beperken tot |
|---|---|---|
question.answered | Een klant beantwoordt een quizvraag. Eén aanroep per gekozen antwoord. | Een quiz, een vraag of één antwoord |
result.viewed | Een klant ziet zijn quizresultaten. | Een quiz |
profile.updated | Een profiel wordt aangemaakt of bijgewerkt door quizactiviteit. | Een quiz |
email.submitted | Een klant vult een e-mailvraag in. | Een quiz |
phone.submitted | Een klant vult een vraag naar zijn telefoonnummer in. | Een quiz |
Kies je bij het aanmaken van de webhook een quiz, vraag of antwoord, dan gaat hij alleen daarvoor af. Het veld topic in de payload bevat het volledige topic, bijvoorbeeld question.answered.<quizId>.<questionId>.<answerId>.
Velden in de payload
Alle payloads zijn JSON met veldnamen in camelCase. Elke payload heeft topic, advisorId (de quiz), sessionId en userId (de bezoeker), behalve profile.updated, dat profileId heeft in plaats van advisorId.
| Topic | Overige velden |
|---|---|
question.answered | questionId, questionName, selectedAnswerId, selectedAnswerLabel, selectedAnswerValue, selectedAnswerTextValue, selectedAnswerFormattedValue, isEmail, isPhone, consentAccepted |
result.viewed | email en phoneNumber als die bekend zijn; questions[] met de antwoorden per vraag (dezelfde antwoordvelden als hierboven plus selectedAnswerTopic); results[] met productId, productName, productUrl, productImageUrl en elke producteigenschap |
profile.updated | email, phoneNumber, firstName, lastName, consentAccepted, consentDate, properties[] (name en value), recommendations[] (position, title, url, imageUrl, quizName en de eigenschappen van het product), createdDate, updatedDate, triggerEvent |
email.submitted | questionId, questionName, email, selectedAnswerId, selectedAnswerLabel, consentAccepted |
phone.submitted | questionId, questionName, phoneNumber, selectedAnswerId, selectedAnswerLabel, consentAccepted |
Producteigenschappen gebruiken jouw eigenschapnamen met een kleine eerste letter, zoals brand of skinType. Telefoonnummers staan in internationaal formaat, bijvoorbeeld +31612345678.
{
"topic": "question.answered.3f2c….9a1e….c07b…",
"advisorId": "3f2c…",
"sessionId": "d41a…",
"userId": "7b90…",
"questionId": "9a1e…",
"questionName": "skin_type",
"selectedAnswerId": "c07b…",
"selectedAnswerLabel": "dry",
"selectedAnswerValue": null,
"selectedAnswerTextValue": null,
"selectedAnswerFormattedValue": "dry",
"isEmail": false,
"isPhone": false,
"consentAccepted": null
}In Studio zie je de voorbeeldpayload van elk topic met één klik in het onderdeel Webhooks.

Aflevering
- bluebarry stuurt een
POSTmetContent-Type: application/jsonen de eigen headers die je aan de webhook hebt toegevoegd. - Elk event heeft een
Idempotency-Key-header. Een nieuwe poging gebruikt dezelfde sleutel, dus sla hem op en sla sleutels over die je al hebt verwerkt. - Elk request heeft een header
bluebarry-signature, waarmee je kunt controleren of het van bluebarry komt. Zie Handtekeningen controleren hieronder. - Elke 2xx-response telt als afgeleverd. Elke poging staat onder Delivery Attempts, waar je de payload kunt bekijken en opnieuw kunt versturen.
- Antwoord met
410 Goneom een webhook uit te zetten. Een webhook die langer dan twee dagen blijft falen, wordt automatisch uitgezet.
Handtekeningen controleren
Elke webhook heeft een eigen signing secret dat begint met whsec_. Studio toont het één keer, direct nadat je de webhook hebt aangemaakt. Ben je het kwijt, open dan het bewerkvenster van de webhook en klik op Rotate secret voor een nieuw secret. Het oude werkt meteen niet meer, dus werk je endpoint direct daarna bij.
De header bluebarry-signature ziet er zo uit: t=1700000000,v1=5257a869…. t is het moment van verzenden in Unix-seconden. v1 is een HMAC-SHA256 van de timestamp, een punt en de onbewerkte request-body, met je signing secret als sleutel, in hex met kleine letters. Zo controleer je een request:
- Lees de onbewerkte request-body voordat je hem parset. Als je de JSON parset en opnieuw schrijft, veranderen de bytes en klopt de handtekening niet meer.
- Splits de header op de komma's en neem de waarden van
tenv1. - Bereken HMAC-SHA256 van
{t}.{body}met het volledige signing secret, inclusiefwhsec_, als sleutel. - Vergelijk de uitkomst met
v1in constante tijd. - Weiger het request als
tmeer dan vijf minuten afwijkt van de klok van je server. Zo kan niemand een oud request opnieuw afspelen.
Een nieuwe poging wordt opnieuw ondertekend met een nieuwe timestamp en houdt zijn Idempotency-Key.
import crypto from "node:crypto";
import express from "express";
const app = express();
const secret = process.env.BLUEBARRY_WEBHOOK_SECRET; // whsec_…
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("bluebarry-signature") ?? "";
const { t, v1 } = Object.fromEntries(header.split(",").map((part) => part.split("=")));
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${req.body}`)
.digest("hex");
const valid =
typeof v1 === "string" &&
v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
if (!valid || !fresh) return res.sendStatus(401);
const event = JSON.parse(req.body);
// Verwerk hier het event.
res.sendStatus(200);
});