Webhooks
Stand: 18. August 2026
Statt den Status abzufragen, kannst du dich benachrichtigen lassen. URL und Secret hinterlegst du im Dashboard unter Einstellungen.
Nutzlast
{
"event": "verification.completed",
"verification_id": "3f7c…",
"status": "SUCCESS",
"satisfied": true,
"profile": "age-over-18",
"channel": "eid",
"assurance": "high",
"client_reference": "bestellung-4711",
"completed_at": "2026-07-30T12:31:02.000Z"
}
status ist SUCCESS, FAILED oder EXPIRED – PENDING löst nichts aus.
Freigeben nur bei SUCCESS und satisfied: true.
channel sagt, womit geprüft wurde: eid für die staatliche E-ID, external
für dein eigenes Verfahren (siehe
Eigenes Verfahren bestätigen). assurance ist daraus abgeleitet
und lässt sich nicht setzen. Beides gehört in deinen Bestellnachweis: „geprüft"
allein ist keine Auskunft mehr, sobald es zwei Wege gibt.
Signatur
Jede Zustellung trägt:
valyda-signature: t=<zeitstempel>,v1=<hmac>
Signiert wird die Zeichenkette <zeitstempel>.<körper> per HMAC-SHA256 mit
deinem Secret, hexadezimal ausgegeben. Das Schema entspricht dem von Stripe,
weil Shop-Entwickler es kennen.
Prüfe die Signatur, bevor du den Inhalt verwendest, und vergleiche zeitkonstant. Prüfe ausserdem den Zeitstempel: liegt er mehr als fünf Minuten zurück, weise die Zustellung ab. Der Zeitstempel steckt im signierten Material, eine abgefangene Zustellung lässt sich also nicht mit frischer Zeit erneut einspielen.
import crypto from 'node:crypto'
function verify(secret, body, header) {
const parts = Object.fromEntries(
header.split(',').map(p => p.split('=').map(s => s.trim()))
)
const t = Number(parts.t)
if (!Number.isFinite(t)) return false
if (Math.abs(Date.now() / 1000 - t) > 300) return false
const expected = crypto.createHmac('sha256', secret)
.update(`${t}.${body}`).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(parts.v1 ?? '')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}
Signiert wird der rohe Körper. Wer erst nach JSON parst und dann wieder serialisiert, bekommt eine andere Zeichenkette und eine Signatur, die nie passt.
Zustellung
Eine Zustellung, ein Versuch, Zeitlimit acht Sekunden. Es gibt heute keine automatische Wiederholung. Antwortet dein Endpunkt mit einem Fehler oder ist er kurz nicht erreichbar, ist die Benachrichtigung verloren – der Ausgang der Prüfung bleibt in unserer Datenbank korrekt, nur weiss dein System nichts davon.
Daraus folgt: Verlass dich nicht allein auf Webhooks. Halte einen Abgleich bereit, der offene Vorgänge nach einer Weile per Statusabfrage nachzieht. Das ist auch ohne diese Einschränkung guter Stil, hier ist es notwendig.
Antworte schnell mit 2xx und erledige die Arbeit danach. Was du in der
Antwortzeit tust, läuft gegen das Zeitlimit.
Mehrfache Zustellung
Behandle den Empfang idempotent – die verification_id ist der natürliche
Schlüssel dafür. Auch wenn heute nur einmal zugestellt wird: eine Verarbeitung,
die eine Wiederholung nicht verträgt, ist eine Verarbeitung, die dir bei der
ersten Änderung dieser Zusage um die Ohren fliegt.