Consent-Webhooks: signierte Ereignisse an Ihren Server
Empfangen Sie consent.recorded und consent.withdrawn auf Ihrem Server, prüfen Sie die HMAC-Signatur mit dem SDK und testen Sie die signierte Zustellung.
Consent-Webhooks übermitteln jede Einwilligungsentscheidung als signierten HTTP-POST an Ihren Server: consent.recorded, wenn ein Besucher mindestens eine Kategorie erteilt, consent.withdrawn, wenn er ablehnt oder widerruft. Das macht das Widerrufsrecht serverseitig durchsetzbar — widerruft ein Besucher, erfährt es Ihr Backend und kann löschen oder die Verarbeitung stoppen.
Einen Webhook anlegen
Zwei Wege, derselbe Vertrag:
- In der App — der Einrichtungsassistent auf der Integrationsseite des Builders: Geben Sie Ihre Endpoint-URL ein, optional beschränkt auf ein einzelnes Banner (Standard: der ganze Workspace).
- Über MCP — das Tool
configure_consent_webhook, wenn Sie FlowConsent aus Claude oder einem anderen MCP-Client steuern.
In beiden Fällen erhalten Sie ein Signatur-Secret im Format whsec_….
Die Signatur
Jede Zustellung trägt einen X-FlowConsent-Signature-Header, im Stripe-Stil:
X-FlowConsent-Signature: t=1722326400,v1=5f8a1c…
Dabei ist t ein Unix-Zeitstempel und v1 = HMAC-SHA256(secret, "<t>.<roher Body>"). Der Zeitstempel begrenzt Replay-Angriffe: Weisen Sie Zustellungen mit zu altem t ab.
Mit dem Server-SDK prüfen
@flowconsent/server-sdk liefert verifyWebhookSignature — Vergleich in konstanter Zeit, standardmäßig 300 s Replay-Toleranz:
import { verifyWebhookSignature } from '@flowconsent/server-sdk'
export async function POST(request: Request) {
const rawBody = await request.text() // roher Body, vor jedem JSON.parse
const check = await verifyWebhookSignature(
rawBody,
request.headers.get('X-FlowConsent-Signature'),
process.env.FLOWCONSENT_WEBHOOK_SECRET!,
)
if (!check.valid) {
// check.reason: 'missing_header', 'malformed_header',
// 'timestamp_out_of_tolerance', 'signature_mismatch'
return new Response('invalid signature', { status: 400 })
}
const event = JSON.parse(rawBody)
if (event.test) return new Response('ok') // Test-Ereignis des Assistenten — nie eine echte Einwilligung
if (event.type === 'consent.withdrawn') {
// Verarbeitung für event.visitor_id stoppen, nachgelagerte Systeme bereinigen…
}
return new Response('ok')
}Die Ereignisse
{
"id": "5f0e0a1c-…",
"type": "consent.recorded",
"banner": "FC-A1B2C3",
"visitor_id": "v_8f3d…",
"action": "accept_all",
"categories": {
"functional": true,
"analytics": true,
"marketing": false,
"preferences": false
},
"services": { "google-analytics": true },
"policy_version": "3",
"occurred_at": "2026-07-30T09:41:22.000Z"
}typeistconsent.recorded, wenn mindestens eine der Kategorienanalytics,marketing,preferenceserteilt wurde; andernfallsconsent.withdrawn.bannerist der öffentliche Lizenzcode des Banners — interne IDs werden nie offengelegt.visitor_idist die pseudonyme Kennung, die auch in den Einwilligungsprotokollen und imdecision.visitorIddes Server-SDK erscheint.occurred_atist ISO 8601.
Die Zustellung testen
Der „Test senden" des Assistenten schickt ein consent.test-Ereignis an Ihren Endpoint, signiert mit Ihrem echten Secret und mit einem expliziten Marker "test": true — behandeln Sie es nie als echte Einwilligung. Es bestätigt Ende-zu-Ende, dass Ihr Endpoint empfängt, prüft und antwortet. Das Zustellergebnis (HTTP-Status, Dauer) wird in der App angezeigt.
Zustellung und Wiederholungen
- 3 Versuche pro Zustellung, exponentielles Backoff (250 ms, 500 ms, 1 s zwischen den Versuchen), je 5 s Timeout.
- Eine
4xx-Antwort (außer429) beendet die Wiederholungen — ein erneuter Versuch würde nichts ändern. - Antworten Sie schnell mit
2xxund verarbeiten Sie asynchron: Alles andere zählt als fehlgeschlagene Zustellung. - Status und Zeitpunkt der letzten Zustellung sind bei jedem Webhook in der App sichtbar.