API
Bouw op Qwizbee
Laat je app op het moment zelf weten dat een quiz start of klaar is. Gebruikers verbinden met één klik, jij ontvangt ondertekende webhooks, en niemand deelt ooit een wachtwoord of account-token.
https://qwizbee-api-production.up.railway.app
Zo werkt de verbinding
Drie stappen, zonder developer-portaal en zonder vooraf registreren. Je app genereert een PKCE-verifier, de gebruiker geeft één keer toestemming, en jij bewaart de API-sleutel die terugkomt.
Zet er een Verbinden-knop op
Stuur de gebruiker naar qwizbee.com/connect met je app-naam, een https-redirect-URI, een PKCE-challenge en een willekeurige state-waarde.
De gebruiker geeft toestemming
Qwizbee toont een toestemmingspagina in de taal van de gebruiker. Na Toestaan keert de browser terug naar jouw redirect-URI met een eenmalige code (2 minuten geldig) en jouw state.
Wissel de code in
Je server wisselt de code plus PKCE-verifier via POST /api/integrations/token in voor een qbw_… API-sleutel. Die sleutel beheert uitsluitend webhooks, verder niets in het account.
De verbindlink
Genereer verifier en challenge op je server en bewaar de verifier in de sessie van de gebruiker:
// on your server
const verifier = base64url(crypto.randomBytes(32));
const challenge = base64url(sha256(verifier));
// your "Connect to Qwizbee" button points at:
https://www.qwizbee.com/connect
?name=Supergood Mail
&redirect_uri=https://www.supergood-mail.com/callback
&code_challenge=${challenge}
&state=${randomState}
// after the user approves you are called back at:
https://www.supergood-mail.com/callback?code=${code}&state=${randomState}De state-waarde komt ongewijzigd terug zodat je jezelf tegen CSRF kunt beschermen, en de redirect-URI moet https zijn (http://localhost mag voor het testen).
// exchange the code for the scoped API key
const res = await fetch('https://qwizbee-api-production.up.railway.app/api/integrations/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, code_verifier: verifier }),
});
const { access_token } = await res.json(); // qbw_… — store it safelyDe events
Registreer na het verbinden een webhook met de API-sleutel. Vanaf dat moment POST Qwizbee een ondertekend JSON-bericht naar jouw URL zodra een quiz van de gebruiker start of klaar is.
quiz.started
Vuurt zodra de host op Start drukt.
POST https://your-app.com/webhooks/qwizbee
X-Qwizbee-Event: quiz.started
X-Qwizbee-Signature: <hmac-sha256>
{
"event": "quiz.started",
"timestamp": "2026-10-08T13:05:22.410Z",
"data": {
"sessionId": "s_ab12cd",
"roomCode": "KGMZ34",
"quizId": "qz_9x8y",
"quizTitle": "Friday afternoon quiz",
"playerCount": 14,
"questionCount": 10
}
}quiz.completed
Vuurt wanneer de eindstanden verschijnen. Voegt de winnaar toe.
{
"event": "quiz.completed",
"timestamp": "2026-10-08T13:12:40.911Z",
"data": {
...same fields as quiz.started,
"winner": { "nickname": "BeeMercia", "score": 8420 }
}
}Payload-velden
- event
- quiz.started of quiz.completed
- timestamp
- ISO 8601-tijdstip van het event
- data.sessionId
- interne sessie-id, stabiel per quiz
- data.roomCode
- de 6-tekens roomcode waarmee spelers meedoen
- data.quizId / quizTitle
- welke quiz het was
- data.playerCount / questionCount
- hoeveel spelers en vragen
- data.winner
- alleen bij quiz.completed: nickname en score van nummer 1, of null
De handtekening verifiëren
Elke levering is ondertekend met het eigen secret van de webhook (één keer zichtbaar bij registratie). Verifieer de rauwe request-body, dus niet een opnieuw geserialiseerd object, voordat je een levering vertrouwt:
import { createHmac, timingSafeEqual } from 'node:crypto';
app.post('/webhooks/qwizbee', express.raw({ type: 'application/json' }), (req, res) => {
const expected = createHmac('sha256', WEBHOOK_SECRET).update(req.body).digest('hex');
const got = req.headers['x-qwizbee-signature'] || '';
const valid = expected.length === got.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(got));
if (!valid) return res.status(401).end();
const event = JSON.parse(req.body);
if (event.event === 'quiz.started') { /* … */ }
res.status(200).end();
});API-referentie
Base-URL van de productie-API. JWT betekent het login-token van de gebruiker; API-sleutel betekent een qbw_…-sleutel uit de connect-flow. Webhook-routes accepteren beide.
Connect-flow
- GET
/api/connect/authorizeJWTDe verbindparameters valideren; geeft de app-naam terug voor de toestemmingspagina.
- POST
/api/connect/approveJWTToestemmen en de redirect-URL met eenmalige code en state terugkrijgen.
- POST
/api/integrations/tokenpublicCode + code_verifier inwisselen voor de afgeschermde API-sleutel (qbw_…).
- GET
/api/integrationsJWTDe verbonden apps van de gebruiker met tijdstempels van laatste gebruik.
- DELETE
/api/integrations/:idJWTVerbinding verbreken. De webhooks worden direct verwijderd en de sleutel werkt niet meer.
Webhooks
- POST
/api/webhooksJWT of API-sleutelWebhook registreren: { url, events }. Het antwoord bevat het signing-secret, dat maar één keer zichtbaar is.
- GET
/api/webhooksJWT of API-sleutelGeregistreerde webhooks tonen.
- DELETE
/api/webhooks/:idJWT of API-sleutelWebhook verwijderen.
- GET
/api/webhooks/:id/deliveriesJWT of API-sleutelDe laatste 50 leverpogingen met statuscodes, voor het debuggen.
Levergedrag
- Mislukte leveringen worden herhaald na 1, 5 en 25 seconden (in totaal 4 pogingen).
- Je endpoint moet binnen 5 seconden antwoorden met een 2xx-status.
- Client-fouten (4xx) worden niet herhaald: jij weigerde duidelijk, dus wij stoppen.
- Elke poging wordt gelogd en zichtbaar via het deliveries-endpoint.
- Verbinding verbreken op de Account-pagina van de gebruiker stopt alle leveringen direct.
Je integratie testen
- Registreer een webhook op een https://webhook.site-URL om echte leveringen te inspecteren.
- http://localhost en http://127.0.0.1 zijn toegestaan als webhook- en redirect-doel, dus je kunt lokaal ontwikkelen.
- Het leverlogboek (GET /api/webhooks/:id/deliveries) toont de exacte statuscodes die we van jou ontvingen.
Vragen of mis je een event?
contact@kylevanraaij.com Mail ons en vertel wat je bouwt: events op quizniveau staan op de roadmap.