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

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

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


Reading this as an agent? The raw Markdown is at /docs/webhooks.md.