API
Baue auf Qwizbee
Lass deine App sofort wissen, wenn ein Quiz startet oder endet. Nutzer verbinden sich mit einem Klick, du empfängst signierte Webhooks, und niemand teilt jemals ein Passwort oder Konto-Token.
https://qwizbee-api-production.up.railway.app
So funktioniert die Verbindung
Drei Schritte, ohne Entwicklerportal und ohne Vorab-Registrierung. Deine App erzeugt einen PKCE-Verifier, der Nutzer stimmt einmal zu, und du speicherst den zurückkommenden API-Schlüssel.
Connect-Button einbauen
Schicke den Nutzer zu qwizbee.com/connect mit deinem App-Namen, einer https-Redirect-URI, einer PKCE-Challenge und einem zufälligen state-Wert.
Der Nutzer stimmt zu
Qwizbee zeigt eine Zustimmungsseite in der Sprache des Nutzers. Nach Erlauben kehrt der Browser zu deiner Redirect-URI zurück — mit einem einmaligen Code (2 Minuten gültig) und deinem state.
Code eintauschen
Dein Server tauscht Code plus PKCE-Verifier an POST /api/integrations/token gegen einen qbw_… API-Schlüssel. Der Schlüssel verwaltet nur Webhooks — sonst nichts im Konto.
Der Connect-Link
Erzeuge Verifier und Challenge auf deinem Server und bewahre den Verifier in der Session des Nutzers auf:
// 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}Der state-Wert kommt unverändert zurück (CSRF-Schutz), und die Redirect-URI muss https sein (http://localhost ist zum Testen erlaubt).
// 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 safelyDie Events
Registriere nach dem Verbinden einen Webhook mit dem API-Schlüssel. Qwizbee POSTet danach eine signierte JSON-Nachricht an deine URL, sobald ein Quiz des Nutzers startet oder endet.
quiz.started
Feuert, sobald der Host auf Start drückt.
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
Feuert, wenn die Endstände erscheinen. Ergänzt den Gewinner.
{
"event": "quiz.completed",
"timestamp": "2026-10-08T13:12:40.911Z",
"data": {
...same fields as quiz.started,
"winner": { "nickname": "BeeMercia", "score": 8420 }
}
}Payload-Felder
- event
- quiz.started oder quiz.completed
- timestamp
- ISO-8601-Zeitpunkt des Events
- data.sessionId
- interne Session-ID, stabil pro Spiel
- data.roomCode
- der 6-stellige Raumcode, mit dem Spieler beitreten
- data.quizId / quizTitle
- welches Quiz es war
- data.playerCount / questionCount
- wie viele Spieler und Fragen
- data.winner
- nur bei quiz.completed: Nickname und Punktzahl von Platz 1, oder null
Signatur prüfen
Jede Zustellung ist mit dem eigenen Secret des Webhooks signiert (einmalig bei der Registrierung angezeigt). Prüfe den rohen Request-Body — nicht ein neu serialisiertes Objekt — bevor du einer Zustellung vertraust:
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-Referenz
Base-URL der Produktions-API. JWT bedeutet das Login-Token des Nutzers; API-Schlüssel bedeutet einen qbw_…-Schlüssel aus dem Connect-Flow. Webhook-Routen akzeptieren beides.
Connect-Flow
- GET
/api/connect/authorizeJWTConnect-Parameter validieren; liefert den App-Namen für die Zustimmungsseite.
- POST
/api/connect/approveJWTZustimmen und die Redirect-URL mit einmaligem Code und state erhalten.
- POST
/api/integrations/tokenpublicCode + code_verifier gegen den abgetrennten API-Schlüssel (qbw_…) tauschen.
- GET
/api/integrationsJWTVerbundene Apps des Nutzers mit Zeitstempeln der letzten Nutzung.
- DELETE
/api/integrations/:idJWTVerbindung trennen. Ihre Webhooks werden sofort gelöscht, der Schlüssel stoppt.
Webhooks
- POST
/api/webhooksJWT oder API-SchlüsselWebhook registrieren: { url, events }. Die Antwort enthält das Signing-Secret — nur einmal sichtbar.
- GET
/api/webhooksJWT oder API-SchlüsselRegistrierte Webhooks auflisten.
- DELETE
/api/webhooks/:idJWT oder API-SchlüsselWebhook entfernen.
- GET
/api/webhooks/:id/deliveriesJWT oder API-SchlüsselDie letzten 50 Zustellversuche mit Statuscodes, zum Debuggen.
Zustellverhalten
- Fehlgeschlagene Zustellungen werden nach 1, 5 und 25 Sekunden wiederholt (insgesamt 4 Versuche).
- Dein Endpunkt muss innerhalb von 5 Sekunden mit einem 2xx-Status antworten.
- Client-Fehler (4xx) werden nicht wiederholt — du hast abgelehnt, also hören wir auf.
- Jeder Versuch wird protokolliert und über den Deliveries-Endpunkt sichtbar.
- Wird die Verbindung auf der Kontoseite des Nutzers getrennt, stoppen alle Zustellungen sofort.
Integration testen
- Registriere einen Webhook auf eine https://webhook.site-URL, um echte Zustellungen zu inspizieren.
- http://localhost und http://127.0.0.1 sind als Webhook- und Redirect-Ziele erlaubt, du kannst also lokal entwickeln.
- Das Zustellprotokoll (GET /api/webhooks/:id/deliveries) zeigt die exakten Statuscodes, die wir von dir erhalten haben.
Fragen oder fehlt ein Event?
contact@kylevanraaij.com Schreib eine Mail und erzähl uns, was du baust — Events auf Spieler-Ebene stehen auf der Roadmap.