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": [],
"riskClasses": [],
"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.
riskClasses
riskFactors names the individual reasons behind a liveness result. The codes
are detailed and can change as the check improves, so rather than matching on
them, route on riskClasses: the kinds of reason present, deduplicated. It is
an empty array when there are none, and it can hold more than one class.
| Class | What it means | What to do |
|---|---|---|
spoof |
Evidence about the medium: what was in front of the camera did not behave like a live person in a room. | Send a result that did not pass to a human review before you let the person try again. |
compliance |
The person did not do what they were asked, or not fully. | Offer another attempt with clearer guidance. |
capture |
Our own measurement failed: not enough usable frames, too little light, a poor connection. This is not evidence of fraud. | Offer another attempt, ideally with a hint about light and position. |
Only spoof adds anything to the result on its own account. The other two are
reported so you can tell a person who needs another go from a case that needs
a person. A result can still be not passed with only capture or compliance
present, because a check we could not measure, or a prompt that was not
performed, gives the score nothing to pass on. Such a check is a result like
any other and is billed as one.
A sandbox session whose result you forced with a test key ran no detection, so
it has no class: riskClasses is empty and riskFactors marks the result as
simulated. Pass or fail, route it on result alone.
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.