Skip to main content

Webhook events

Understand webhook event types and payload structure​

Webhook payloads are minimal, machine-readable JSON messages that deliver metadata about an event. They will never include personally identifiable information (PII). You can fetch full details from the API when needed by using the respective session_id.

info

All events use thin payloads. No personally identifiable information (PII) is included by default. To learn more, see the Configure webhooks →


Payload structure​

All webhook events include these fields:

FieldTypeDescription
eventIdstringSame ID across retries for the same event
eventVersionstringCurrent event version
eventNameenumFormat: resource.action. One of session.created, session.completed, session.aborted, session.expired, session.error (see Session events), or step.started, step.progress, step.ended (see Step events).
eventDeliverIdnumberUnique per retry attempt (currently defaulted to a max. 10 times)
eventSequencenumberIndex of the specific event within a session (sequence: 1, 2, 3)
createdAtISO 8601When the event was created
environmentenumEnvironment on which endpoint URL was configured. One of live, staging.
payload.flowIdstringThe identifier of the flow that was triggered
payload.sessionIdUUIDThe identifier of the specific session
payload.sessionStatusenumCurrent status of the session. One of CREATED, RUNNING, COMPLETED, ABORTED, EXPIRED, ERROR.
payload.lastStepobjectInformation about the last executed step. Always present for terminal session events (session.completed, session.aborted, session.expired, session.error). Always absent for session.created. Always present for step events (step.started, step.progress, step.ended).
payload.lastStep.stepIdstringUnique identifier of the last step. This corresponds to the step name defined in the flow definition.
payload.lastStep.stepTypestringType of the last step (e.g. DOC_ID:v2, END, CHOICE)
payload.lastStep.stepDescriptionstringHuman-readable description of the step (as configured in the flow). Empty string if not set.
payload.lastStep.stepStatusstringStatus of the last step. One of STARTED, COMPLETED, ERROR, ABORTED, WORKFLOW_EXPIRED, or ROLLED_BACK.
payload.lastStep.stepProgressenumWhat a running step is waiting for. One of IN_PROGRESS, ENDUSER_INPUT_NEEDED, IN_MANUAL_REVIEW. Present while stepStatus is STARTED, absent otherwise. See Track step progress.
payload.lastStep.stepStatusDetailsstringDiagnostic detail when stepStatus is ERROR (optional). See Technical errors for more.
info

The eventId remains the same across all retry attempts, while eventDeliverId increments.


JWT-encoded payload​

Webhook messages are delivered as a JSON Web Token (JWT) rather than as a plain JSON object. The HTTP request body therefore contains a JWT string, which must be decoded to access the underlying payload.

The JWT must be verified before use, including validation of the signature and standard claims such as iss, aud, sub, exp, and iat. Once successfully decoded and verified, the JWT payload exposes the event metadata and business data under the data field.

  • aud — equals the destination endpoint URL you configured for the webhook. Validate that this matches your endpoint to prevent cross-endpoint replay attacks.
  • sub — equals the eventId of the delivered event.

Payload example​

The decoded JWT payload has the following structure:

{
"data": {
"eventId": "61a51c5b-480d-4f47-8334-34b0ba7ae0be",
"eventName": "session.completed",
"eventVersion": "1.0",
"eventSequence": 2,
"eventDeliverId": 1,
"createdAt": "2026-01-08T08:35:37.581Z",
"environment": "staging",
"payload": {
"flowId": "bf8e2e27-2340-426f-a0bb-f1081e4a07ac",
"sessionId": "fe1941c2-bc45-4142-b516-fa0fc9fd7754",
"sessionStatus": "COMPLETED",
"lastStep": {
"stepId": "END-ACCEPT",
"stepType": "END",
"stepDescription": "Final step",
"stepStatus": "COMPLETED"
}
}
},
"iss": "https://localhost:3002/oidc",
"iat": 1767861339,
"exp": 1767864939,
"sub": "61a51c5b-480d-4f47-8334-34b0ba7ae0be",
"aud": "https://webhook.site/d076d490-8424-4c85-8904-5d1801c7909e"
}

Session events​

IDnow sends the following event types when a session changes state:

Event TypeDescription
session.createdThe session has been created and is ready to start
session.completedThe session reached an End step with a final outcome
session.expiredThe session expired before it finished and can no longer be used
session.abortedThe user left or cancelled the session before it reached a final outcome
session.errorThe session stopped because of an error

session.completed means the flow finished, not that the user passed. For what to do with each event, see Interpret session results.


Step events​

Session events tell you how a session starts and ends. Step events tell you what happens in between. You select them next to the session events when you configure a webhook, and they follow the same delivery, retry and security rules, including the JWT-encoded payload described above.

IDnow sends the following event types while a step runs:

Event TypeDescription
step.startedA step begins. Its progress is IN_PROGRESS
step.progressThe progress of a running step changes, for example to IN_MANUAL_REVIEW when it enters a manual review
step.endedA step finishes. The flow either moved on to the next step, or sent the user back (rolled back)

step.ended means the step finished, not that the user passed. Only the session's outcome holds that decision. A step that is aborted or fails has no step event: use session.aborted and session.error.

info

step.progress comes with a progress value that says what the running step is waiting for. IN_MANUAL_REVIEW is one example: listen for it to know when a user moves to a manual review. For all progress values, what each one means and a worked example, see Track step progress.