> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# List Session Events

> Read the event timeline of a verification session: device-reported steps, status changes and workflow routing, newest first and paginated.

List Session Events API Prompt
Copy prompt to clipboard

<pre>
  \`Read the event timeline of one Didit verification session through the API.

  Endpoint:
  GET [https://verification.didit.me/v3/session/\{session\_id}/events/](https://verification.didit.me/v3/session/\{session_id}/events/)

  Authentication:
  Send my Didit API key in the x-api-key header. A scoped key needs sessions: read and decisions: read.

  Goal:

  * See what happened during a session, step by step: which screens the user saw, where they stopped, which attempts failed, when the status changed and how the workflow routed the session.

  Behavior:

  * Works for user (KYC) and business (KYB) session IDs.
  * Ordered by sent\_at, newest first. sent\_at is a Unix timestamp in milliseconds.
  * Paginated with limit (default 50) and offset. The response is { count, next, previous, results }. Follow next until it is null.
  * Device-reported event types: LINK\_OPENED, STEP\_RENDERED, BUTTON\_CLICKED, FORM\_SUBMITTED, FILE\_UPLOADED, ATTEMPT\_FAILED, LOG. Server-recorded types include SESSION\_CREATED, SESSION\_STATUS\_CHANGED (details.old\_status, details.current\_status), FEATURE\_STEP\_CHANGED, WORKFLOW\_BRANCH\_EVALUATED and WORKFLOW\_STATUS\_NODE\_REACHED.
  * Events are stored asynchronously, so a new event can take a few seconds to appear.
  * file\_url is a short-lived presigned link; a scoped key without media: read receives it as null.

  Example call:
  curl -X GET "[https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/events/?limit=50](https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/events/?limit=50)" \
  -H "x-api-key: YOUR\_API\_KEY"

  What to read from the response:

  * results\[].event\_type, feature\_step (OCR, LIVENESS, FACE\_MATCH, ...) and step (the screen, for example DOCUMENT\_CAPTURE\_FRONT).
  * results\[].details: event-specific data; the keys vary by event\_type.
  * results\[].ip\_address, user\_agent and device\_info for device-reported events.
  * count, next and previous for pagination.

  Failure modes:

  * 400: limit or offset above 1,000,000.
  * 401: the API key has expired.
  * 403: missing or invalid key, a key of another application, a scoped key without the permissions above, or a request from outside the key's IP allowlist.
  * 404: the session does not exist, was deleted, or is outside a scoped key's workflow or status limits.

  Side effects: none. This is a pure read.

  For the full integration shape, see /integration/integration-prompt.\`
</pre>

Paste into

The workflow routing events (`WORKFLOW_BRANCH_EVALUATED`, `WORKFLOW_STATUS_NODE_REACHED`) and their `details` are described in [Retrieve session](/sessions-api/retrieve-session.md), which can also return the timeline of a User Verification (KYC) session inside its decision with `?include=events`.


## OpenAPI

````yaml GET /v3/session/{sessionId}/events/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/session/{sessionId}/events/:
    get:
      tags:
        - Sessions
      summary: List session events
      description: >-
        Read the event timeline of one verification session, newest first by
        `sent_at`: the screens the user saw, buttons and uploads, failed
        attempts, status and feature-step changes, and the workflow routing
        trace. Works for User Verification (KYC) and Business Verification (KYB)
        session IDs. Events are stored asynchronously, so a new event can take a
        few seconds to appear. Results are paginated with `limit` and `offset`;
        follow `next` until it is `null`. A scoped API key needs `sessions:
        read` and `decisions: read`, and without `media: read` it receives
        `file_url` as `null`. The routing events are described in [Retrieve
        session](https://docs.didit.me/sessions-api/retrieve-session).
      operationId: get_v3_session_events
      parameters:
        - name: sessionId
          in: path
          required: true
          description: >-
            UUID of the verification session (the `session_id` returned by `POST
            /v3/session/`). Accepts both User Verification (KYC) and Business
            Verification (KYB) session IDs: the server resolves the ID across
            both session types. Must be a well-formed UUID; a malformed value
            does not match the route and returns an HTML `404`.
          schema:
            type: string
            format: uuid
            example: 11111111-2222-3333-4444-555555555555
        - name: limit
          in: query
          required: false
          description: >-
            Maximum number of events per page. Defaults to 50. A value below 1
            or a non-numeric value falls back to 50; a value above 1,000,000
            returns `400`.
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 1000000
            example: 50
        - name: offset
          in: query
          required: false
          description: >-
            Number of results to skip before the first returned one. Defaults to
            0; a negative or non-numeric value falls back to 0, a value above
            1,000,000 returns `400`. Prefer following the `next` and `previous`
            URLs.
          schema:
            type: integer
            default: 0
            minimum: 0
            maximum: 1000000
            example: 0
        - name: ordering
          in: query
          required: false
          description: >-
            Optional sort override. The default order is `-sent_at`. Pass a
            result field name (for example `sent_at`, `created_at`,
            `event_type`, `feature_step` or `step`) to sort ascending, prefix it
            with `-` to sort descending, and separate several fields with
            commas. Unknown fields are ignored.
          schema:
            type: string
            example: sent_at
      responses:
        '200':
          description: One page of the session's events, newest first.
          content:
            application/json:
              schema:
                type: object
                required:
                  - count
                  - next
                  - previous
                  - results
                properties:
                  count:
                    type: integer
                    description: Total number of events of the session.
                  next:
                    type: string
                    format: uri
                    nullable: true
                    description: URL of the next page, or `null` on the last page.
                  previous:
                    type: string
                    format: uri
                    nullable: true
                    description: URL of the previous page, or `null` on the first page.
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/SessionEvent'
              examples:
                Completed session:
                  value:
                    count: 3
                    next: null
                    previous: null
                    results:
                      - uuid: aaaaaaaa-1111-2222-3333-444444444444
                        event_type: SESSION_STATUS_CHANGED
                        created_at: '2026-09-14T10:02:13.904512Z'
                        component: null
                        feature_step: null
                        step: null
                        details:
                          old_status: In Progress
                          current_status: Approved
                        ip_address: null
                        user_agent: null
                        device_info: null
                        file_url: null
                        sent_at: 1789380131482
                      - uuid: bbbbbbbb-1111-2222-3333-444444444444
                        event_type: FEATURE_STEP_CHANGED
                        created_at: '2026-09-14T10:01:49.210377Z'
                        component: null
                        feature_step: null
                        step: null
                        details:
                          old_feature_step: OCR
                          current_feature_step: LIVENESS
                        ip_address: null
                        user_agent: null
                        device_info: null
                        file_url: null
                        sent_at: 1789380107103
                      - uuid: cccccccc-1111-2222-3333-444444444444
                        event_type: STEP_RENDERED
                        created_at: '2026-09-14T10:01:00.581930Z'
                        component: DocumentCapture
                        feature_step: OCR
                        step: DOCUMENT_CAPTURE_FRONT
                        details: {}
                        ip_address: 203.0.113.24
                        user_agent: >-
                          Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X)
                          AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5
                          Mobile/15E148 Safari/604.1
                        device_info:
                          device_model: iPhone
                        file_url: null
                        sent_at: 1789380058776
        '400':
          description: >-
            `limit` or `offset` is above 1,000,000. The body is a JSON array
            with one message.
          content:
            application/json:
              examples:
                Limit too large:
                  summary: limit=2000000
                  value:
                    - limit must not exceed 1000000.
                Offset too large:
                  summary: offset=2000000
                  value:
                    - offset must not exceed 1000000.
              schema:
                type: array
                items:
                  type: string
        '401':
          description: >-
            The scoped API key has expired. This is the only case that returns
            `401`: a missing, invalid or revoked key returns `403`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    description: Human-readable error message.
              examples:
                Expired key:
                  summary: The key's expiry date has passed
                  value:
                    detail: This API key has expired.
        '403':
          description: >-
            Authentication or authorization failure. Missing, invalid and
            revoked keys return `403` (not `401`); so do a key of another
            application, a scoped key without the permission this endpoint
            needs, and a request from outside the key's IP allowlist.
            Distinguish them by `detail`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    description: Human-readable error message.
              examples:
                Missing or invalid credentials:
                  summary: No x-api-key header, or the key failed validation
                  value:
                    detail: >-
                      Authentication credentials were not provided or are
                      invalid.
                Other application:
                  summary: >-
                    A valid key that belongs to a different application than the
                    session
                  value:
                    detail: You do not have permission to perform this action.
                Scoped key without sessions read:
                  summary: 'Scoped key lacks sessions: read'
                  value:
                    detail: This API key has no read access to sessions.
                Scoped key without decisions read:
                  summary: 'Scoped key lacks decisions: read'
                  value:
                    detail: This API key has no read access to decisions.
                IP not allowed:
                  summary: Request from outside the key's IP allowlist
                  value:
                    detail: This API key can't be used from this IP address.
        '404':
          description: >-
            The session does not exist, was deleted, or is outside a scoped
            key's workflow or approved-only limits. The session lookup runs
            before the credential check, so an unknown `sessionId` returns `404`
            even without a valid key.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    description: Human-readable error message.
              examples:
                Unknown session:
                  summary: No session with this ID exists, or it was deleted
                  value:
                    detail: Not found.
                Outside key limits:
                  summary: >-
                    The session is outside a scoped key's workflow or
                    approved-only limits
                  value:
                    detail: Session not found.
        '429':
          description: >-
            Rate limit exceeded: 600 GET requests per minute per API key. Wait
            `Retry-After` seconds before retrying; the `X-RateLimit-*` headers
            show the budget.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    description: Human-readable error message.
              examples:
                Rate limited:
                  summary: Budget for the current minute exhausted
                  value:
                    detail: >-
                      GET request rate limit exceeded. You can make up to 600
                      requests per minute.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
                minimum: 1
                example: 30
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: >-
            curl -X GET
            'https://verification.didit.me/v3/session/11111111-2222-3333-4444-555555555555/events/?limit=50'
            \
              -H 'x-api-key: YOUR_API_KEY'
        - lang: python
          label: Python
          source: |-
            import os

            import requests

            session_id = '11111111-2222-3333-4444-555555555555'
            resp = requests.get(
                f'https://verification.didit.me/v3/session/{session_id}/events/',
                headers={'x-api-key': os.environ['DIDIT_API_KEY']},
                params={'limit': 50},
                timeout=10,
            )
            resp.raise_for_status()
            for event in resp.json()['results']:
                print(event['sent_at'], event['event_type'], event['step'])
        - lang: javascript
          label: JavaScript
          source: >-
            const sessionId = '11111111-2222-3333-4444-555555555555';

            const resp = await
            fetch(`https://verification.didit.me/v3/session/${sessionId}/events/?limit=50`,
            {
              headers: { 'x-api-key': process.env.DIDIT_API_KEY },
            });

            if (!resp.ok) throw new Error(`Request failed: ${resp.status}`);

            const page = await resp.json();

            for (const event of page.results) console.log(event.sent_at,
            event.event_type, event.step);
components:
  schemas:
    SessionEvent:
      type: object
      description: One entry of a verification session's event timeline.
      required:
        - uuid
        - event_type
        - created_at
        - component
        - feature_step
        - step
        - details
        - ip_address
        - user_agent
        - device_info
        - file_url
        - sent_at
      properties:
        uuid:
          type: string
          format: uuid
          description: Event identifier.
        event_type:
          type: string
          enum:
            - SESSION_CREATED
            - SESSION_COMPLETED
            - SESSION_STATUS_CHANGED
            - LINK_OPENED
            - FORM_SUBMITTED
            - BUTTON_CLICKED
            - FILE_UPLOADED
            - ATTEMPT_FAILED
            - FEATURE_STEP_CHANGED
            - STEP_RENDERED
            - NOTE_ADDED
            - MANUAL_REVIEW_STARTED
            - WORKFLOW_BRANCH_EVALUATED
            - WORKFLOW_STATUS_NODE_REACHED
            - LOG
          description: >-
            What happened. Reported by the device during the hosted flow or SDK:
            `LINK_OPENED`, `STEP_RENDERED`, `BUTTON_CLICKED`, `FORM_SUBMITTED`,
            `FILE_UPLOADED`, `ATTEMPT_FAILED` and `LOG` (debugging). Recorded by
            the server: `SESSION_CREATED`, `SESSION_STATUS_CHANGED`
            (`details.old_status`, `details.current_status`),
            `FEATURE_STEP_CHANGED` (`details.old_feature_step`,
            `details.current_feature_step`), `WORKFLOW_BRANCH_EVALUATED` and
            `WORKFLOW_STATUS_NODE_REACHED` (the workflow routing trace).
            `SESSION_COMPLETED`, `NOTE_ADDED` and `MANUAL_REVIEW_STARTED` can
            appear on older sessions.
        created_at:
          type: string
          format: date-time
          description: >-
            When Didit stored the event. Events are stored asynchronously, a few
            seconds after `sent_at`.
        component:
          type: string
          nullable: true
          description: UI component that reported the event (device events only).
        feature_step:
          type: string
          nullable: true
          enum:
            - OCR
            - OCR_BACK
            - NFC
            - AML
            - FACE
            - LIVENESS
            - FACE_MATCH
            - IP_ANALYSIS
            - AGE_ESTIMATION
            - PROOF_OF_ADDRESS
            - PHONE_VERIFICATION
            - EMAIL_VERIFICATION
            - FACE_SEARCH
            - DATABASE_VALIDATION
            - QUESTIONNAIRE
            - KYB_REGISTRY
            - KYB_DOCUMENTS
            - KYB_KEY_PEOPLE
            - DOCUMENT_AI
            - GEOLOCATION
            - null
          description: Verification feature the session was on when the event happened.
        step:
          type: string
          nullable: true
          description: >-
            Screen within the feature, for example `DOCUMENT_CAPTURE_FRONT` or
            `FACE_PASSIVE_LIVENESS`.
        details:
          type: object
          nullable: true
          additionalProperties: true
          description: Event-specific data. The keys depend on `event_type`.
        ip_address:
          type: string
          nullable: true
          description: >-
            IP address the device reported the event from. `null` for
            server-recorded events.
        user_agent:
          type: string
          nullable: true
          description: User agent of the device. `null` for server-recorded events.
        device_info:
          type: object
          nullable: true
          additionalProperties: true
          description: Device details the SDK or browser reported.
        file_url:
          type: string
          format: uri
          nullable: true
          description: >-
            Short-lived presigned link to a file attached to the event (for
            example a captured image). `null` when there is none, and always
            `null` for a scoped API key without `media: read`.
        sent_at:
          type: integer
          format: int64
          description: >-
            When the event happened, as a Unix timestamp in milliseconds.
            Results are ordered by it.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Your application's API key, from Developers -> API keys in the Business
        Console. The primary key has full access. A named key can be scoped:
        none, read or write per resource, limited to some workflows or to
        approved sessions, to a list of IP addresses, and to an expiry date. 401
        means the key is missing, wrong, revoked or expired; 403 means the key
        has no access to this resource or action, or the request came from an
        address outside its IP list; 404 on a session route means the session is
        outside the key's workflows or statuses. A key without media access
        receives image, video and PDF URLs as null, and a key without sessions
        write receives session links and tokens as null. See
        https://docs.didit.me/console/api-keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.