LIVE · AUDIT-KJEDE · EU-VERTET
SYSTEM · 99,99 % OPPETID
v 1.0 ↗ LAGET I EU

Webhooks

Webhooks er hvordan backenden din får vite om ting som skjer asynkront — økter som avsluttes, opptak som fullfører etterbehandling, audit-kjeder som forankres hos tidsstemplingsmyndigheten. Registrer en URL, verifiser signaturen på hver POST, dispatch på event-type.

Event-typer

EventNår
session.createdNy økt via SPA eller offentlig API
session.completedØkt avsluttet (manuelt eller via API)
participant.joinedFeltbruker (eller observatør) ble med i en økt
participant.leftDeltaker koblet fra
evidence.addedNytt øyeblikksbilde / annotering / tavle / klipp / dokument fanget
recording.readyEtterbehandlede opptaksartefakter tilgjengelige
audit.anchoredKjedehode forankret hos én av de konfigurerte tidsstemplingsmyndighetene
signature.completedEn signert PDF (SES/AES/QES) er klar for nedlasting
webhook.testUtløst av "Test fire"-knappen i SPA-administrasjonen, med en liten syntetisk 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 */
  }
}

id er stabil på tvers av gjenforsøk — bruk den som din idempotensnøkkel på mottakersiden.

Signatur-header

Hver POST bærer en NB-Signature-header i Stripe-stil-format:

NB-Signature: t=1716461235,v1=5257a8...3e2c1f

Verdien v1 er HMAC-SHA256(secret, "{timestamp}.{body}") i hex. Verdien t er et Unix-tidsstempel på signeringstidspunktet. Et 5-minutters skjevhetsvindu avviser replays av eldre payloads.

Verifisering i kode

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)

Gjenforsøk-oppførsel

En levering anses som vellykket når endepunktet ditt returnerer en 2xx innen 30s. Alt annet utløser eksponentiell backoff:

30s 5m 1h 6h 24h DROPPED

Etter 50 påfølgende feil på tvers av alle events, deaktiveres endepunktet automatisk. Org-administratoren kan reaktivere fra SPA-administrasjonen når mottakeren er tilbake.

Idempotens på din side

Webhook-leveranser kan gjentas. Behandle event.id som dedupliseringsnøkkelen:

-- 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.

Signeringshemmeligheter

Hvert registrerte webhook-endepunkt har sin egen whsec_*-signeringshemmelighet. Klarteksten vises nøyaktig én gang når du registrerer endepunktet (eller roterer det); deretter lagrer vi en Fernet-kryptert kopi og viser bare de første 6 tegnene til identifikasjon.

Roter fra SPA → Admin → Webhooks → Rotate secret. Eksisterende mottakere vil avvise signerte hendelser til de er oppdatert med den nye hemmeligheten — planlegg roteringen sammen med et deploy-vindu.

Testutsending

Hvert registrerte endepunkt har en «Test fire»-knapp i SPA-administrasjonen som sender en webhook.test-konvolutt slik at du kan verifisere mottakeren din før du går live. Testkonvolutten har samme form som en ekte hendelse, men med en syntetisk payload merket "test": true i data.

Leveringslogg

SPA → Admin → Webhooks viser de siste 100 leveransene per endepunkt med HTTP-status, forsøk, siste responstekst (avkortet) og tidsstempler. Filtrer etter status / endepunkt for å feilsøke mottakerproblemer.