NA ŻYWO · ŁAŃCUCH AUDYTU · UE
SYSTEM · 99,99% DOSTĘPNOŚĆ
v 1.0 ↗ WYPRODUKOWANO W UE

Webhooki

Webhooki to sposób, w jaki Twój backend dowiaduje się o rzeczach dziejących się asynchronicznie — kończących się sesjach, nagraniach kończących przetwarzanie, łańcuchach audytu kotwiczonych w TSA. Zarejestruj URL, weryfikuj podpis przy każdym POST, dyspozycjonuj według typu zdarzenia.

Typy zdarzeń

ZdarzenieKiedy
session.createdNowa sesja przez SPA lub publiczne API
session.completedSesja zakończona (ręcznie lub przez API)
participant.joinedUżytkownik terenowy (lub obserwator) dołączył do sesji
participant.leftUczestnik rozłączył się
evidence.addedPrzechwycono nowy zrzut / adnotację / tablicę / klip / dokument
recording.readyDostępne przetworzone artefakty nagrania
audit.anchoredGłowica łańcucha zakotwiczona w jednym ze skonfigurowanych TSA
signature.completedPodpisany PDF (SES/AES/QES) jest gotowy do pobrania
webhook.testWyzwalane przyciskiem "Test fire" w panelu administracyjnym SPA, z drobnym syntetycznym payloadem

Kształt koperty

{
  "id": "evt_01HGB9...",
  "type": "session.completed",
  "created_at": "2026-05-23T11:42:15Z",
  "org_id": 42,
  "data": {
    /* event-specific payload — full resource shape */
  }
}

Pole id jest stabilne przy ponowieniach — użyj go jako klucza idempotencji po stronie odbiorcy.

Nagłówek podpisu

Każdy POST niesie nagłówek NB-Signature w formacie w stylu Stripe:

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

Wartość v1 to HMAC-SHA256(secret, "{timestamp}.{body}") w hex. Wartość t to znacznik czasu Unix z momentu podpisania. 5-minutowe okno tolerancji odrzuca powtórki starszych payloadów.

Weryfikacja w kodzie

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)

Zachowanie przy ponowieniach

Dostarczenie jest uznawane za udane, gdy Twój endpoint zwróci 2xx w ciągu 30 s. Cokolwiek innego wyzwala wykładniczy backoff:

30s 5m 1h 6h 24h DROPPED

Po 50 kolejnych niepowodzeniach we wszystkich zdarzeniach endpoint automatycznie się wyłącza. Administrator organizacji może go ponownie włączyć z panelu administracyjnego SPA, gdy odbiorca wróci do działania.

Idempotencja po Twojej stronie

Dostarczenia webhooków mogą się powtarzać. Traktuj event.id jako klucz deduplikacji:

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

Sekrety podpisujące

Każdy zarejestrowany endpoint webhooka ma własny sekret podpisujący whsec_*. Tekst jawny jest pokazywany dokładnie raz, gdy rejestrujesz endpoint (lub go rotujesz); potem przechowujemy kopię zaszyfrowaną Fernet i udostępniamy tylko pierwsze 6 znaków do identyfikacji.

Rotuj z SPA → Admin → Webhooki → Rotuj sekret. Istniejący odbiorcy będą odrzucać podpisane zdarzenia, dopóki nie zostaną zaktualizowani nowym sekretem — zaplanuj rotację wraz z oknem wdrożenia.

Test fire

Każdy zarejestrowany endpoint ma w panelu administracyjnym SPA przycisk "Test fire", który wysyła kopertę webhook.test, abyś mógł zweryfikować odbiorcę przed uruchomieniem produkcyjnym. Koperta testowa ma taki sam kształt jak prawdziwe zdarzenie, ale z syntetycznym payloadem oznaczonym "test": true w data.

Dziennik dostarczeń

SPA → Admin → Webhooki pokazuje ostatnie 100 dostarczeń per endpoint ze statusem HTTP, próbami, ostatnim ciałem odpowiedzi (skróconym) i znacznikami czasu. Filtruj według statusu / endpointu, aby debugować problemy odbiorcy.