cancelled state. The payload carries an outcome, a granular reason, and the per-check retry counters so you can tell whether the user gave up after a failed check, withdrew consent after the session had already terminalized, or cancelled cleanly before attempting anything.
When it fires
There are two paths that lead to a cancelled event, plus a privacy-driven replacement path:- Authenticated cancel.
POST /v1/sessions/:id/cancelwith an API key that holdssessions:write. Idempotent. - Public cancel.
POST /v1/verify/session/:id/cancelwith the one-shotcancel_token. The verify web app and mobile apps use this to abort from the user’s side. - Privacy withdrawal replacement. When the user redeems their
cancel_tokenafter the session has already terminalized assucceededorfailed, Kayle scrubs the previously queued terminal payload. If that prior delivery had not yet been delivered, averification.session.cancelledevent is emitted in its place so every session still produces exactly one terminal webhook. If the prior delivery had already been delivered, no replacement is emitted.
failed with failure_code: session_cancelled.
Payload
Fields
Always
verification.session.cancelled.The share-contract version the session was created against.
Unique event ID. Idempotency-key candidate — the same event reuses this ID on retries and replays.
The session that was cancelled.
Always
not_verified. Cancelled sessions never produce a verified user.Why this cancelled event was emitted. One of:
cancelled— the session was cancelled before any retry budget was consumed.cancelled_after_failed_check— the session was cancelled while at least one of the NFC or liveness retry budgets was already partially consumed. Inspectnfc_tries_used/liveness_tries_usedto see which.privacy_cancelled_after_terminal_failure— the session had already terminalized asfailedand the user then withdrew consent before the failed webhook delivered. The originalverification.session.failedpayload was scrubbed; this event replaces it.privacy_cancelled_after_terminal_success— the session had already terminalized assucceededand the user then withdrew consent before the success webhook delivered. The originalverification.session.succeededpayload (with its claims) was scrubbed; this event replaces it. You will not receive the claims for this session — privacy withdrawal is final.
How many NFC chip-read retries (0..3) the session consumed before cancellation.
How many liveness retries (0..3) the session consumed before cancellation.
Terminal-webhook invariant
Every verification session produces exactly one terminal webhook from the set{succeeded, failed, expired, cancelled} — provided you have at least one endpoint subscribed to that event type. The privacy-withdrawal replacement path exists to preserve this invariant: if a succeeded or failed webhook is scrubbed by a privacy request before it lands, you receive a cancelled event in its place rather than nothing at all.