---
title: "Get session detail by ID"
method: GET
path: "/api/v1/sessions/{id}"
tags: ["Sessions"]
---

# Get session detail by ID

`GET /api/v1/sessions/{id}`

## Request

- Base URL: `https://api.korala.ai`
- URL: `https://api.korala.ai/api/v1/sessions/{id}`
- Auth: one of:
  - API key in header `X-API-Key`
  - `bearer` (a scheme the document does not define)

## Path parameters

- `id` string, required

## Headers

- `X-Korala-Mode` 'live' | 'test'

## Response `200`

- SessionDetailDto
  - `originContextId` string, nullable: Registered originating risk context; null when none was linked. This association does not determine evidence applicability.
  - `subjectId` string, nullable: Explicitly linked Korala risk subject ID; null for unlinked sessions.
  - `sandbox` boolean, required: Persisted execution mode: true for test data
  - `id` string, required
  - `organizationId` string, required
  - `externalUserId` string, required
  - `subjectKind` 'individual' | 'business', required
  - `finalManualReviewRequired` boolean, required
  - `accessToken` string, required: Access token for end-user access
  - `status` 'created' | 'in_progress' | 'pending_review' | 'completed' | 'expired' | 'failed', required
  - `resolution` 'approved' | 'rejected'
  - `resolutionReason` string, nullable
  - `resolvedAt` string, date-time, nullable
  - `resolvedBy` string, nullable
  - `riskScore` number, nullable
  - `riskLevel` 'low' | 'medium' | 'high'
  - `riskSummary` RiskAssessmentDto
    - `kind` 'sybil' | 'velocity' | 'duplicate_document' | 'device_cluster' | 'location_cluster' | 'network_mismatch', required
    - `score` number, required
    - `level` 'low' | 'medium' | 'high', required
    - `reasons` string[], required
    - `findingCount` number, required
    - `findings` RiskFindingDto[], required
      - `code` string, required
      - `severity` 'low' | 'medium' | 'high', required
      - `entityType` string, required
      - `observedAt` string, required: ISO 8601 timestamp
      - `entityId` string, nullable
      - `metadata` object, required
    - `metrics` object, required
    - `manualReviewRecommended` boolean, required
  - `eventVersion` number, required: Grows with each change announced by a session webhook; compare it with the webhook's `data.version`. The higher number is the newer state; numbers may skip.
  - `decision` SessionDecisionDto
    - `outcome` 'approved' | 'rejected' | 'review' | 'resubmit', required
    - `decidedBy` 'auto' | 'reviewer' | 'partner', required: auto: Korala decided; reviewer: someone in the dashboard; partner: your integration through the API
    - `decidedAt` string, required
    - `rulesVersion` string, required: The rules that made the decision. v2 adds the identity switch between attempts and the unnumbered-attempt rule; records made under v1 keep it.
    - `reasonCodesVersion` string, required
    - `codes` string[], required: Why: the decline codes of a rejection, or the codes holding a session in review
    - `decidingCheckIds` string[], required
    - `findings` SessionDecisionFindingDto[], required
      - `code` string, required: Korala reason code, family.name (for example screening.sanctions_match)
      - `effect` 'decline' | 'review' | 'resubmit', required
      - `checkId` string, nullable, required: The check that produced this finding; null for a session-level finding (missing evidence, duplicate identity, validation, a required manual decision).
    - `attempts` SessionDecisionAttemptDto[], required
      - `sessionWorkflowId` string, required
      - `workflowRunId` string, required
      - `attempt` number, nullable, required: The run's stored attempt number. Null only if the run was never numbered (a broken invariant). When Korala decides automatically it then records data.attempt_unnumbered: an approval or resubmission goes to review with the code in codes, a review gains it in codes, and beside a definite decline it sits in findings (not codes) while the decline stands. With no automatic decision there is no record. A reviewer's or partner's decision stands and simply cites null. A decision an older version of Korala made cites that version's attempt counter.
    - `resubmission` SessionDecisionResubmissionDto
      - `sessionWorkflowId` string, required: The earliest workflow the person is asked to redo
      - `attemptsRemaining` number, required: The fewest attempts the person has left on any workflow asked for again
      - `workflows` SessionDecisionResubmissionWorkflowDto[]: Every workflow asked for again, earliest first
        - `sessionWorkflowId` string, required: A workflow the person is asked to redo
        - `attemptsRemaining` number, required: Attempts the person has left on it
    - `identityAcrossAttempts` SessionDecisionIdentityAcrossAttemptsDto
      - `status` 'same' | 'changed' | 'unknown', required: changed: a different person (code duplicate.identity_changed_between_attempts; the switch itself never declines, while a definite decline from a check set to block still declines, with the switch among decision.codes); unknown: a field either attempt left unread, so not compared; same: name and date of birth agree
      - `signals` string[], required: What showed a change: name_and_date_of_birth, both differ; document_number, another document (number and issuing country) whose name differs while the date of birth is not shown to agree (unread on either); document_and_date_of_birth, another document with another date of birth, whatever the name (two people of one name)
  - `metadata` object, nullable
  - `context` object, nullable
  - `accumulatedData` object, nullable
  - `expiresAt` string, date-time, nullable
  - `redirectUrl` string, nullable
  - `startedAt` string, date-time, nullable
  - `completedAt` string, date-time, nullable
  - `createdAt` string, date-time, required
  - `updatedAt` string, date-time, required
  - `participants` SessionParticipantDto[], required
    - `id` string, required
    - `role` 'subject' | 'beneficial_owner' | 'controller' | 'director' | 'representative', required
    - `displayName` string, nullable
    - `externalParticipantId` string, nullable
    - `data` object, nullable
    - `metadata` object, nullable
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
  - `workflows` SessionWorkflowDto[], required
    - `id` string, required
    - `workflowDefinitionId` string, required
    - `workflowName` string, nullable
    - `workflowSlug` string, nullable
    - `workflowRunId` string, nullable
    - `outputKey` string, required
    - `participantId` string, nullable
    - `participantRole` 'subject' | 'beneficial_owner' | 'controller' | 'director' | 'representative'
    - `participantDisplayName` string, nullable
    - `order` number, required
    - `status` 'pending' | 'in_progress' | 'completed' | 'failed' | 'resubmit_required', required
    - `context` object, nullable
    - `attemptCount` number, required
    - `maxAttempts` number, required
    - `resubmissionReasons` string[], nullable: Why Korala asked for this workflow again: capture reason codes the person can act on (capture.document_expired, capture.document_unsupported, capture.image_unreadable, capture.side_missing, capture.file_too_large, capture.document_no_face, capture.selfie_no_face, capture.selfie_multiple_faces, capture.selfie_too_dark, capture.selfie_blurry). Kept while the redo runs and cleared when the workflow next completes. Null when nobody asked, or when the partner did.
    - `documentChoice` SessionDocumentChoiceDto
      - `country` string, required: ISO 3166-1 alpha-2
      - `type` 'passport' | 'national_id' | 'driving_license', required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
    - `attempts` SessionWorkflowAttemptDto[]: Every attempt at this workflow, ordered by attemptNumber, then any not yet numbered by startedAt, the current one included. On the organisation's session responses (GET, create, resolve, resubmit), never on the person's session link. An earlier attempt is one a resubmission replaced: its checks are the session's checks with supersededAt set.
      - `workflowRunId` string, required
      - `attemptNumber` number, nullable, required: Which attempt this run is, from 1, in the order the runs were claimed, never rewritten. A run an older version of Korala started during an upgrade is numbered when the next run of this workflow starts or the session is next decided, so it can be numbered after a newer run and numbers need not follow startedAt. Until then it is null and listed after the numbered ones, by startedAt: never a number that changes later. If an older version of Korala made the last decision on the session, earlier runs can stay unnumbered (nothing later claims or decides on them), and that decision cites the attempt counter of that version. A decision this version makes cites the stored number, or null where an invariant broke (see decision.attempts[].attempt). A workflow redone because an earlier one changed keeps counting here, while its attemptCount (the cap) starts again.
      - `status` 'pending' | 'running' | 'paused' | 'completed' | 'failed', required
      - `startedAt` string, date-time, nullable
      - `completedAt` string, date-time, nullable
      - `resubmissionReasons` string[], nullable: The capture reason codes Korala asked for this attempt again with. Null for the current attempt, for one the partner asked for again, and for attempts from before this was recorded.
      - `documentChoice` SessionDocumentChoiceDto
        - `country` string, required: ISO 3166-1 alpha-2
        - `type` 'passport' | 'national_id' | 'driving_license', required
      - `checkIds` string[], required: Ids of this attempt's checks in the session's checks, current and superseded alike
  - `checks` SessionCheckDto[], required
    - `id` string, required
    - `sessionId` string, required
    - `sessionWorkflowId` string, nullable
    - `participantId` string, nullable
    - `checkKind` 'document_authenticity' | 'face_match' | 'passive_liveness' | 'active_liveness' | 'database_identity' | 'aml_screening' | 'business_registry' | 'tax_id' | 'individual_identity' | 'pep_sanctions' | 'adverse_media' | 'ubo_lookup', required
    - `provider` string, required
    - `status` 'clear' | 'match' | 'review_required' | 'error', required
    - `score` number, nullable
    - `blockingMode` 'none' | 'manual_review' | 'block', required
    - `reviewThreshold` 'low' | 'medium' | 'high', required
    - `reviewRecommended` boolean, required
    - `providerRef` string, nullable
    - `matches` SessionCheckMatchDto[], required
      - `id` string, nullable
      - `label` string, required
      - `score` number, nullable
      - `category` string, nullable
      - `metadata` object, nullable
    - `reasons` string[], required
    - `rawResultRedacted` object, nullable
    - `metadata` object, nullable
    - `supersededAt` string, date-time, nullable: When a resubmission replaced the attempt this check judged. A superseded check is an earlier attempt, kept as evidence: it no longer decides the session. Integrations must ignore checks with supersededAt set when judging the session.
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required

## Other responses

- `400`: Malformed UUID in path parameter (`id`).

---

[API](https://skmtc.dev/korala/apis/korala-public-api.md) · [All operations](https://skmtc.dev/korala/apis/korala-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/korala/apis/korala-public-api/revisions/5c4d7810c507?raw)
