Webhooks
Webhooks är hur din backend får reda på saker som händer asynkront — sessioner som avslutas, inspelningar som blir klara med efterbearbetning, granskningskedjor som förankras hos TSA:n. Registrera en URL, verifiera signaturen på varje POST, dirigera på händelsetyp.
Händelsetyper
| Händelse | När |
|---|---|
session.created | Ny session via SPA eller publikt API |
session.completed | Session avslutad (manuellt eller via API) |
participant.joined | Fältanvändare (eller observatör) anslöt till en session |
participant.left | Deltagare kopplades från |
evidence.added | Ny skärmdump / anteckning / whiteboard / klipp / dokument fångad |
recording.ready | Efterbearbetade inspelningsartefakter tillgängliga |
audit.anchored | Kedjehuvud förankrat hos en av de konfigurerade TSA:erna |
signature.completed | En signerad PDF (SES/AES/QES) är klar för nedladdning |
webhook.test | Avfyrad av knappen "Test fire" i SPA-adminen, med en liten syntetisk payload |
Kuvertets form
{
"id": "evt_01HGB9...",
"type": "session.completed",
"created_at": "2026-05-23T11:42:15Z",
"org_id": 42,
"data": {
/* event-specific payload — full resource shape */
}
} id är stabilt över omförsök — använd det som din idempotensnyckel på mottagarsidan.
Signaturheader
Varje POST bär en NB-Signature-header i Stripe-liknande format:
NB-Signature: t=1716461235,v1=5257a8...3e2c1f Värdet v1 är HMAC-SHA256(secret, "{timestamp}.{body}") i hex. Värdet t är en Unix-tidsstämpel vid signeringstillfället. Ett skevningsfönster på 5 minuter avvisar återuppspelningar av äldre payloads.
Verifiera i kod
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) Omförsöksbeteende
En leverans anses lyckad när din endpoint returnerar en 2xx inom 30s. Allt annat utlöser exponentiell backoff:
30s → 5m → 1h → 6h → 24h → DROPPED Efter 50 misslyckanden i följd över alla händelser avaktiveras endpointen automatiskt. Org-adminen kan återaktivera från SPA-adminen när mottagaren är tillbaka.
Idempotens på din sida
Webhook-leveranser kan upprepas. Behandla event.id som deduplikationsnyckel:
-- 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. Signeringshemligheter
Varje registrerad webhook-endpoint har sin egen whsec_*-signeringshemlighet. Klartexten visas exakt en gång när du registrerar endpointen (eller roterar den); därefter lagrar vi en Fernet-krypterad kopia och visar bara de första 6 tecknen för identifiering.
Rotera från SPA → Admin → Webhooks → Rotera hemlighet. Befintliga mottagare kommer att avvisa signerade händelser tills de uppdaterats med den nya hemligheten — schemalägg rotationen med ett deploy-fönster.
Test fire
Varje registrerad endpoint har en "Test fire"-knapp i SPA-adminen som skickar ett webhook.test-kuvert så att du kan verifiera din mottagare innan du går live. Testkuvertet har samma form som en riktig händelse men med en syntetisk payload taggad "test": true i data.
Leveranslogg
SPA → Admin → Webhooks visar de senaste 100 leveranserna per endpoint med HTTP-status, försök, senaste svarskropp (avkortad) och tidsstämplar. Filtrera på status / endpoint för att felsöka mottagarproblem.