Webhooks
Webhooks sind der Weg, wie Ihr Backend von Dingen erfährt, die asynchron passieren — Sitzungen enden, Aufzeichnungen schließen die Nachbearbeitung ab, Audit-Ketten verankern sich an der TSA. Registrieren Sie eine URL, verifizieren Sie die Signatur bei jedem POST, dispatchen Sie nach Event-Typ.
Event-Typen
| Event | Wann |
|---|---|
session.created | Neue Sitzung über SPA oder öffentliche API |
session.completed | Sitzung beendet (manuell oder über API) |
participant.joined | Feldbenutzer (oder Beobachter) ist einer Sitzung beigetreten |
participant.left | Teilnehmer getrennt |
evidence.added | Neuer Snapshot / Annotation / Whiteboard / Clip / Dokument erfasst |
recording.ready | Nachbearbeitete Aufzeichnungs-Artefakte verfügbar |
audit.anchored | Kettenkopf an einer der konfigurierten TSAs verankert |
signature.completed | Ein signiertes PDF (SES/AES/QES) steht zum Download bereit |
webhook.test | Ausgelöst durch den „Test fire“-Button in der SPA-Verwaltung, mit einem winzigen synthetischen Payload |
Envelope-Form
{
"id": "evt_01HGB9...",
"type": "session.completed",
"created_at": "2026-05-23T11:42:15Z",
"org_id": 42,
"data": {
/* event-specific payload — full resource shape */
}
} Die id ist über Retries hinweg stabil — verwenden Sie sie als Ihren Idempotenzschlüssel auf der Empfängerseite.
Signatur-Header
Jeder POST trägt einen NB-Signature-Header im Stripe-Stil-Format:
NB-Signature: t=1716461235,v1=5257a8...3e2c1f Der v1 -Wert ist HMAC-SHA256(secret, "{timestamp}.{body}") in Hex. Der t -Wert ist ein Unix-Zeitstempel zum Signierzeitpunkt. Ein 5-Minuten-Skew-Fenster weist Replays älterer Payloads ab.
Verifizierung im Code
Node
import { NexBasira, InvalidSignatureError } from "@nexbasira/node";
const nb = new NexBasira({ apiKey: "...", apiSecret: "..." });
// Express handler — important: use express.raw() so the body is the
// untouched bytes the signature was computed over.
app.post("/nb-webhook", express.raw({ type: "application/json" }), (req, res) => {
const sig = req.header("NB-Signature")!;
const secret = process.env.NB_WEBHOOK_SECRET!;
let event;
try {
event = nb.webhooks.constructEvent(req.body, sig, secret);
} catch (err) {
if (err instanceof InvalidSignatureError) {
return res.status(401).send("bad signature");
}
throw err;
}
// event is now type-narrowed by event.type
return handleEvent(event, res);
}); Python
from nexbasira import NexBasira, InvalidSignatureError
nb = NexBasira(api_key="...", api_secret="...")
# Flask handler — get the raw body, not request.get_json()
@app.post("/nb-webhook")
def webhook():
sig = request.headers["NB-Signature"]
secret = os.environ["NB_WEBHOOK_SECRET"]
try:
event = nb.webhooks.construct_event(request.data, sig, secret)
except InvalidSignatureError:
return ("bad signature", 401)
return handle_event(event) Retry-Verhalten
Eine Zustellung gilt als erfolgreich, wenn Ihr Endpoint innerhalb von 30 s einen 2xx zurückgibt. Alles andere löst exponentielles Backoff aus:
30s → 5m → 1h → 6h → 24h → DROPPED Nach 50 aufeinanderfolgenden Fehlern über alle Events hinweg deaktiviert sich der Endpoint automatisch. Der Org-Admin kann ihn aus der SPA-Verwaltung wieder aktivieren, sobald der Empfänger zurück ist.
Idempotenz auf Ihrer Seite
Webhook-Zustellungen können sich wiederholen. Behandeln Sie event.id als Deduplizierungsschlüssel:
-- Postgres example
INSERT INTO webhook_deliveries (event_id, processed_at)
VALUES ($1, NOW())
ON CONFLICT (event_id) DO NOTHING
RETURNING event_id;
-- If RETURNING is empty, this is a duplicate — skip the side-effect. Signier-Secrets
Jeder registrierte Webhook-Endpoint hat sein eigenes whsec_*-Signier-Secret. Der Klartext wird genau einmal angezeigt, wenn Sie den Endpoint registrieren (oder rotieren); danach speichern wir eine Fernet-verschlüsselte Kopie und zeigen nur die ersten 6 Zeichen zur Identifikation.
Rotieren Sie über SPA → Admin → Webhooks → Secret rotieren. Bestehende Empfänger weisen signierte Events ab, bis sie mit dem neuen Secret aktualisiert wurden — planen Sie die Rotation mit einem Deploy-Fenster.
Test fire
Jeder registrierte Endpoint hat in der SPA-Verwaltung einen „Test fire“-Button, der ein webhook.test-Envelope verschickt, damit Sie Ihren Empfänger vor dem Go-Live verifizieren können. Das Test-Envelope hat dieselbe Form wie ein echtes Event, aber mit einem synthetischen Payload, der in data mit "test": true getaggt ist.
Zustellungsprotokoll
SPA → Admin → Webhooks zeigt die letzten 100 Zustellungen pro Endpoint mit HTTP-Status, Versuchen, letztem Response-Body (gekürzt) und Zeitstempeln. Filtern Sie nach Status / Endpoint, um Empfängerprobleme zu debuggen.