# Webhooks The browser sees a verdict, but it reaches you through the end user's device. Webhooks are signed and server-to-server, so this is where decisions belong. ## Register an endpoint ```bash curl -X POST https://machine.cognau.com/api/v1/cockpit/webhooks \ -H "Authorization: Bearer $COGNAU_SECRET_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://acme.com/hooks/cognau", "enabledEvents": ["verification.completed"] }' ``` The signing secret is returned **once**. Endpoints are scoped to the environment of the key that created them, so test traffic never reaches your production receiver. ## `verification.completed` ```json { "sessionId": "6a7de599a5244ea6a3e65109", "clientReference": "user_4821", "result": "passed", "confidence": 0.91, "riskFactors": [], "personKey": null, "personSeenBefore": null, "completedAt": "2026-08-13T12:04:20.000Z" } ``` `clientReference` is whatever you set at session or link creation. It is the field that lets you join this event to your own record without having stored our `sessionId`. ## Verify the signature Every delivery carries `x-cognau-signature`. Compute HMAC-SHA256 over the raw body with your endpoint secret and compare in constant time. Reject anything that does not match, and do it **before** parsing the body. ## Delivery Deliveries are retried with backoff and claimed atomically, so exactly one of your instances handles each one even when several are running. Respond `2xx` quickly; do the work afterwards. A persistently failing endpoint is disabled and can be re-enabled from the dashboard, where you can also inspect the event log and redeliver. Handle duplicates. Retries mean the same event can arrive more than once, so key on `sessionId`.