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

# Sessions

Manage KYC onboarding sessions for end users. Sessions track progress through workflows, store document uploads, and manage the onboarding process from creation to approval.

## Overview

Sessions represent individual KYC onboarding processes for end users. Each session:

* **Links to a Workflow**: Defines the steps and requirements
* **Tracks Progress**: Monitors which steps are completed
* **Stores Documents**: Uploaded documents are stored securely
* **Runs Validations**: Automated checks (watchlists, crypto, adverse media, face match)
* **Public Access**: End users access sessions via public access tokens

## Endpoints

| Method   | Endpoint                                                          | Description                                   |
| -------- | ----------------------------------------------------------------- | --------------------------------------------- |
| `POST`   | `/kyc/sessions`                                                   | Create a new session                          |
| `GET`    | `/kyc/sessions`                                                   | List sessions (paginated)                     |
| `GET`    | `/kyc/sessions/{session_id}`                                      | Get session details                           |
| `PATCH`  | `/kyc/sessions/{session_id}`                                      | Update session status                         |
| `DELETE` | `/kyc/sessions/{session_id}`                                      | Delete session                                |
| `POST`   | `/kyc/sessions/{session_id}/generate-link`                        | Generate/regenerate access link               |
| `POST`   | `/kyc/sessions/{session_id}/extend`                               | Extend the public access link expiration      |
| `POST`   | `/kyc/sessions/{session_id}/corrections`                          | Request client corrections for selected steps |
| `POST`   | `/kyc/sessions/{session_id}/validate`                             | Run validation checks                         |
| `POST`   | `/kyc/sessions/{session_id}/process`                              | Process completed session                     |
| `GET`    | `/kyc/sessions/{session_id}/documents/{doc_id}/url`               | Get document download URL                     |
| `POST`   | `/kyc/sessions/{session_id}/subsessions`                          | Create a subsession                           |
| `GET`    | `/kyc/sessions/{session_id}/subsessions`                          | List subsessions                              |
| `POST`   | `/kyc/sessions/{session_id}/subsessions/{sub_id}/regenerate-link` | Regenerate subsession link                    |
| `DELETE` | `/kyc/sessions/{session_id}/subsessions/{sub_id}`                 | Delete subsession                             |

## Authentication

Requires `kyc:create` permission for creating sessions and `kyc:read` permission for retrieving sessions. Include your Bearer token in the Authorization header.

## Create Session

Create a new KYC onboarding session for an end user.

### Endpoint

```
POST /kyc/sessions
```

### Request Body Parameters

<ParamFields>
  <ParamField name="workflow_id" type="string" required description="ID of the workflow to use for this session" />

  <ParamField name="ttl_days" type="integer" description="Number of days until session expires (default: 7)" />

  <ParamField name="metadata" type="object" description="Optional metadata to store with the session">
    <ParamField name="user_email" type="string" description="Email of the end user" />

    <ParamField name="user_name" type="string" description="Name of the end user" />
  </ParamField>

  <ParamField name="subject_data" type="object" description="Tenant-declared attributes about the subject, supplied at creation time. Used for automation, cross-validation, and to pre-declare values such as a merchant website URL before the end user completes the public flow. See Subject data below." />

  <ParamField name="customer_id" type="string" description="Existing customer ID to link this session to" />

  <ParamField name="client_id" type="string" description="Your external customer identifier. Auto-creates a customer record when none exists for this ID" />

  <ParamField name="account_country" type="string" description="ISO 3166-1 alpha-2 country code where the account was opened with your organization (e.g. BR, UY, MX). Used by automation rules and document cross-validation" />

  <ParamField name="language" type="string" description="Fixed public session UI language (e.g. es, en, pt). Must be one of the locales enabled on the workflow" />
</ParamFields>

### Subject data

Use `subject_data` to declare facts your integration already knows about the subject **before** the end user opens the public link. Values are stored on the session, echoed in `GET /kyc/sessions/{session_id}`, and consumed during processing.

Each value may be a plain scalar or an envelope object:

```json theme={null}
"website": "https://merchant.example"
```

```json theme={null}
"website": {
  "value": "https://merchant.example",
  "validation_profile": "web_validator_default"
}
```

#### Website URL (web validation)

If any of the following keys holds a non-empty URL string, the platform runs **web validation** for that URL when the session is processed — even when the end user never fills a website field in the public form:

| Key       | Notes                                                                           |
| --------- | ------------------------------------------------------------------------------- |
| `website` | **Recommended.** Aligns with the `website` form field in KYB/merchant workflows |
| `web_url` | Alias                                                                           |
| `url`     | Alias                                                                           |
| `domain`  | Alias                                                                           |

Duplicate URLs are validated once. If the workflow also has an auto-validated URL form field and the user submits the same URL, you are not charged twice.

Optional companion keys improve the web validator context (same semantics as `POST /kyc/web-validation`):

| Key                                                                | Used for                                                                              |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| `legal_name`, `business_name`, `company_name`, `full_name`, `name` | `declared_name` passed to the web validator                                           |
| `industry`, `business_industry`, `sector`                          | `declared_industry`                                                                   |
| `merchant_id`, `client_id`, `customer_id`                          | Merchant/customer correlation (falls back to the session's `customer_id` when linked) |

<Info>
  Declaring a URL in `subject_data` consumes one `web_validation_checks` unit at session creation, the same as when the workflow defines an auto-validated URL field. Processing runs automatically when the session completes if the workflow has `auto_process` enabled (default for most templates).
</Info>

<Note>
  Web validation **summary** (triggered automation rules) is delivered in session webhooks. The **full** `web_validation_results` payload is available via the Sessions API after processing — see [Web validation results](#web-validation-results).
</Note>

#### Individual KYC (pre-declared person)

For individual identity workflows (IDV / KYC), pass attributes you already know about the person in `subject_data` at creation time. The platform stores them on the session and uses them during processing — **before** the end user completes the public form.

| Key                                         | Notes                                                                                                                                        |
| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `full_name`                                 | **Recommended** for natural persons. Drives sanctions screening and adverse media as a declared screening subject (`source: "subject_data"`) |
| `name`                                      | Alias for `full_name`                                                                                                                        |
| `nationality`                               | ISO alpha-2 (e.g. `UY`). Feeds automation country rules                                                                                      |
| `country_of_residence`, `residence_country` | Country of residence for automation                                                                                                          |
| `date_of_birth`                             | Stored on the session and included in reports; use form fields for cross-validation against documents                                        |
| `document_number`, `tax_id`, `email`        | Stored and available to automation rules and reports                                                                                         |

<Warning>
  `subject_data` is **tenant/backend data**. It is **not** returned by the public session API and **does not pre-fill** the end-user form. Cross-validation compares what the user declared in the public form against extracted document data — not your pre-declared `subject_data`.
</Warning>

Example — create a session when you already know the subject is Federico Gil:

```json theme={null}
{
  "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
  "client_id": "federico-gil-123",
  "metadata": {
    "user_email": "federico@example.com",
    "user_name": "Federico Gil"
  },
  "subject_data": {
    "full_name": "Federico Gil",
    "nationality": "UY",
    "date_of_birth": "1990-05-15"
  }
}
```

After the session completes and is processed, check `processing_results.external_validations.lists_check` — when the workflow has `validation_config.run_lists` enabled, screening includes a subject with `"source": "subject_data"` even if the user has not yet filled the public form:

```json theme={null}
{
  "screening_subjects": [
    {
      "name": "Federico Gil",
      "source": "workflow",
      "entity_type": "individual",
      "role": "primary"
    },
    {
      "name": "Federico Gil",
      "source": "subject_data",
      "entity_type": "individual",
      "role": "declared"
    }
  ],
  "entities_checked": ["Federico Gil"]
}
```

Unlike website URLs, declaring a person name in `subject_data` does **not** consume extra quota at creation. Sanctions screening only runs when the workflow has `run_lists: true` (or equivalent automation configuration).

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
    "ttl_days": 7,
    "client_id": "merchant-456",
    "metadata": {
      "user_email": "user@example.com",
      "user_name": "John Doe"
    },
    "subject_data": {
      "website": "https://landing.merchant.example",
      "legal_name": "Merchant Example SA",
      "industry": "E-commerce"
    }
  }'
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
    "workflow_version": 1,
    "status": "active",
    "access_token": "770e8400-e29b-41d4-a716-446655440002",
    "access_link": "https://compliance.legaltalent.ai/public/sessions/770e8400-e29b-41d4-a716-446655440002",
    "current_step_index": 0,
    "expires_at": 1732278600,
    "ttl_days": 7,
    "subject_data": {
      "website": "https://landing.merchant.example",
      "legal_name": "Merchant Example SA",
      "industry": "E-commerce"
    },
    "steps_data": [
      {
        "step_id": "step_1",
        "status": "pending"
      },
      {
        "step_id": "step_2",
        "status": "pending"
      }
    ],
    "metadata": {
      "user_email": "user@example.com",
      "user_name": "John Doe"
    },
    "custom_tags": {
      "department": "onboarding",
      "region": "latam"
    },
    "created_at": "2024-11-22T10:30:00Z",
    "updated_at": "2024-11-22T10:30:00Z"
  }
}
```

<Info>
  The `custom_tags` field is a snapshot of the workflow's `custom_tags` at the time the session was created. If you later update the workflow's tags, existing sessions retain their original tags. These tags are included in all session webhook payloads.
</Info>

## List Sessions

Retrieve all sessions for your tenant with pagination, filtering, and optional summary statistics.

### Endpoint

```
GET /kyc/sessions
```

### Query Parameters

<ParamFields>
  <ParamField query="status" type="string" description="Filter by single technical status: 'active', 'completed', 'processing', 'processed', 'expired', 'approved', 'rejected', 'manual_review', or 'awaiting_client_correction'" />

  <ParamField query="status_list" type="string" description="Filter by multiple statuses (comma-separated). Example: 'approved,rejected,manual_review'" />

  <ParamField query="inbox" type="string" description="Filter by operational inbox: 'all', 'pending', 'manual_review', 'approved', 'rejected', 'remediation', 'completed', or 'incomplete'. When provided, it takes precedence over status filters." />

  <ParamField query="workflow_id" type="string" description="Filter by workflow ID" />

  <ParamField query="search" type="string" description="Search by session ID, customer ID, user name, or user email" />

  <ParamField query="assigned_to" type="string" description="Filter by reviewer assignment. Use 'me' for the authenticated user or 'unassigned' for unassigned sessions." />

  <ParamField query="priority" type="string" description="Filter by manual priority: 'low', 'medium', 'high', 'critical', or 'high_or_higher'" />

  <ParamField query="requires_action" type="boolean" description="If 'true', restrict results to sessions that require reviewer action" />

  <ParamField query="sort" type="string" description="Sort field: 'created_at', 'progress_percent', or 'manual_review_at'" />

  <ParamField query="order" type="string" description="Sort order: 'asc' or 'desc' (default: 'desc')" />

  <ParamField query="created_from" type="string" description="Filter sessions created on or after this ISO date (e.g., '2024-01-01T00:00:00Z')" />

  <ParamField query="created_to" type="string" description="Filter sessions created on or before this ISO date (e.g., '2024-12-31T23:59:59Z')" />

  <ParamField query="include_summary" type="boolean" description="If 'true', include summary statistics with status counts, total sessions, and average risk score" />

  <ParamField query="limit" type="integer" description="Number of results per page (default: 50, max: 100)" />

  <ParamField query="next_key" type="string" description="Pagination token from previous response" />
</ParamFields>

### Request Example

```bash theme={null}
# Basic listing with status filter
curl "https://kyc.legaltalent.ai/kyc/sessions?status=active&limit=20" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Filter by date range and workflow
curl "https://kyc.legaltalent.ai/kyc/sessions?workflow_id=550e8400-e29b-41d4-a716-446655440000&created_from=2024-01-01T00:00:00Z&created_to=2024-12-31T23:59:59Z" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Get sessions with summary statistics
curl "https://kyc.legaltalent.ai/kyc/sessions?include_summary=true" \
  -H "Authorization: Bearer YOUR_TOKEN"

# Filter multiple statuses
curl "https://kyc.legaltalent.ai/kyc/sessions?status_list=approved,rejected,manual_review&include_summary=true" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "sessions": [
      {
        "session_id": "660e8400-e29b-41d4-a716-446655440001",
        "tenant_id": "tenant123",
        "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
        "workflow_name": "Basic KYC",
        "status": "approved",
        "compliance_status": "approved",
        "current_step_index": 3,
        "completed_steps": 3,
        "total_steps": 3,
        "progress_percent": 100,
        "expires_at": 1732278600,
        "metadata": {
          "user_email": "user@example.com",
          "user_name": "John Doe"
        },
        "customer_id": "cust_abc123",
        "priority": "medium",
        "assigned_to": "user_abc123",
        "risk_score": 25.5,
        "risk_level": "low",
        "created_at": "2024-11-22T10:30:00Z",
        "updated_at": "2024-11-22T10:35:00Z"
      }
    ],
    "next_key": "eyJzZXNzaW9uX2lkIjoiNjYwZTg0MDA...",
    "summary": {
      "status_counts": {
        "active": 5,
        "completed": 3,
        "approved": 42,
        "rejected": 8,
        "manual_review": 12,
        "expired": 2
      },
      "inbox_counts": {
        "all": 72,
        "pending": 8,
        "manual_review": 12,
        "approved": 42,
        "rejected": 8,
        "remediation": 0,
        "completed": 3,
        "incomplete": 2
      },
      "total": 72,
      "avg_risk_score": 35.2,
      "sessions_with_risk_score": 50,
      "validation_counts": {
        "lists": 50,
        "face_match": 31,
        "adverse_media": 18
      }
    }
  }
}
```

### Summary Statistics

When `include_summary=true`, the response includes aggregate statistics for all sessions matching the filters (not just the current page):

| Field                      | Description                                          |
| -------------------------- | ---------------------------------------------------- |
| `status_counts`            | Count of sessions per status                         |
| `inbox_counts`             | Count of sessions per operational inbox              |
| `total`                    | Total number of sessions matching filters            |
| `avg_risk_score`           | Average risk score across scored sessions            |
| `sessions_with_risk_score` | Number of sessions that have a risk score            |
| `validation_counts`        | Count of sessions that executed each validation type |

<Warning>
  The summary requires scanning all matching sessions, which may increase response time for tenants with many sessions. Use filters (workflow\_id, date range) to limit the scope when possible.
</Warning>

## Get Session Details

Retrieve detailed information about a specific session.

### Endpoint

```
GET /kyc/sessions/{session_id}
```

### Request Example

```bash theme={null}
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "tenant_id": "tenant123",
    "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
    "workflow_version": 1,
    "status": "completed",
    "access_token": "770e8400-e29b-41d4-a716-446655440002",
    "current_step_index": 3,
    "steps_data": [
      {
        "step_id": "step_1",
        "status": "completed",
        "started_at": "2024-11-22T10:31:00Z",
        "completed_at": "2024-11-22T10:32:00Z",
        "documents": [
          {
            "doc_id": "doc_abc123",
            "type": "id",
            "file_name": "passport.jpg",
            "mime_type": "image/jpeg",
            "uploaded_at": "2024-11-22T10:32:00Z"
          }
        ]
      },
      {
        "step_id": "step_2",
        "status": "completed",
        "started_at": "2024-11-22T10:33:00Z",
        "completed_at": "2024-11-22T10:34:00Z",
        "documents": [
          {
            "doc_id": "doc_def456",
            "type": "selfie",
            "file_name": "selfie.jpg",
            "mime_type": "image/jpeg",
            "uploaded_at": "2024-11-22T10:34:00Z"
          }
        ]
      },
      {
        "step_id": "step_3",
        "status": "completed",
        "started_at": "2024-11-22T10:35:00Z",
        "completed_at": "2024-11-22T10:36:00Z",
        "form_data": {
          "full_name": "John Doe",
          "date_of_birth": "1990-01-15",
          "email": "john@example.com"
        }
      }
    ],
    "form_data": {
      "full_name": {
        "field_id": "field_abc123",
        "name": "Full Name",
        "type": "name",
        "value": "John Doe"
      },
      "date_of_birth": {
        "field_id": "field_xyz789",
        "name": "Date of Birth",
        "type": "date",
        "value": "1990-01-15"
      },
      "email": {
        "field_id": "field_email456",
        "name": "Email",
        "type": "email",
        "value": "john@example.com"
      }
    },
    "metadata": {
      "user_email": "user@example.com",
      "user_name": "John Doe"
    },
    "subject_data": {
      "website": "https://landing.merchant.example",
      "legal_name": "Merchant Example SA"
    },
    "custom_tags": {
      "department": "onboarding",
      "region": "latam"
    },
    "processing_results": {
      "web_validation_results": [
        {
          "field_id": "subject_data.website",
          "step_id": "subject_data",
          "url": "https://landing.merchant.example",
          "status": "success",
          "result": {
            "reliability_score": 78.5,
            "validation_results": {
              "ssl_checker": { "has_ssl": true, "is_valid": true },
              "classifier": { "industry_name": "E-commerce", "allowed_industry": true }
            }
          }
        }
      ],
      "final_decision": "approved",
      "processed_at": "2024-11-22T10:45:00Z"
    },
    "expires_at": 1732278600,
    "created_at": "2024-11-22T10:30:00Z",
    "updated_at": "2024-11-22T10:36:00Z",
    "completed_at": "2024-11-22T10:36:00Z"
  }
}
```

| Field                | Description                                                                                                                              |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `subject_data`       | Tenant-declared attributes from session creation (including pre-declared website URLs)                                                   |
| `processing_results` | Present after the session has been processed. Includes `web_validation_results`, automation output, risk scoring, and extraction results |

## Process Session

Process a completed session - extract document data, run cross-validation, face matching, and external validations. This is the main endpoint to call after a session is completed to get final results.

### Endpoint

```
POST /kyc/sessions/{session_id}/process
```

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/process \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "status": "processed",
    "processing_results": {
      "extraction_results": {
        "doc_abc123": {
          "full_name": "JOHN DOE",
          "document_number": "AB1234567",
          "date_of_birth": "1990-01-15",
          "nationality": "US",
          "expiry_date": "2030-01-15"
        }
      },
      "cross_validation": {
        "status": "passed",
        "warnings": [],
        "errors": []
      },
      "face_match_result": {
        "status": "matched",
        "confidence": 0.95,
        "threshold": 0.8
      },
      "external_validations": {
        "lists_check": {
          "is_match": false,
          "match_count": 0,
          "lists_checked": ["ofac", "un", "eu"]
        },
        "crypto_check": null,
        "adverse_media_check": {
          "risk_score": 10,
          "decision": "CLEAR"
        }
      },
      "web_validation_results": [
        {
          "field_id": "subject_data.website",
          "step_id": "subject_data",
          "url": "https://landing.merchant.example",
          "status": "success",
          "result": {
            "reliability_score": 78.5,
            "validation_results": {
              "ssl_checker": { "has_ssl": true, "is_valid": true },
              "classifier": { "industry_name": "E-commerce", "allowed_industry": true },
              "kyc_matches": { "declared_name_match": true }
            }
          }
        }
      ],
      "final_decision": "approved",
      "processed_at": "2024-11-22T10:45:00Z",
      "processing_time_ms": 5200
    }
  }
}
```

### Processing Results Fields

| Field                    | Description                                                               |
| ------------------------ | ------------------------------------------------------------------------- |
| `extraction_results`     | Extracted data from each uploaded document                                |
| `cross_validation`       | Consistency check between documents and form data                         |
| `face_match_result`      | Face comparison between ID and selfie (if configured)                     |
| `external_validations`   | Results from watchlist, crypto, and adverse media checks                  |
| `web_validation_results` | URL validation results (if configured)                                    |
| `final_decision`         | Automatic decision: `approved`, `flagged`, `manual_review`, or `rejected` |

### Web validation results

Each entry in `processing_results.web_validation_results` corresponds to one URL that was validated — from a workflow form field with `auto_validate`, or from `subject_data` at creation time.

| Field      | Description                                                                                                        |
| ---------- | ------------------------------------------------------------------------------------------------------------------ |
| `field_id` | Workflow field ID, or `subject_data.{key}` when the URL was declared via `subject_data`                            |
| `step_id`  | Form step ID, or `subject_data` for pre-declared URLs                                                              |
| `url`      | Validated URL                                                                                                      |
| `status`   | `success` or `error`                                                                                               |
| `result`   | Full web validation payload on success (same shape as [`POST /kyc/web-validation`](/api-reference/web-validation)) |
| `error`    | Generic error code on failure (`invalid_url`, `validation_failed`). No URL or internal details are returned        |

Retrieve results with:

* `GET /kyc/sessions/{session_id}` — after status is `processed`, `approved`, `rejected`, or `manual_review`
* `POST /kyc/sessions/{session_id}/process` — triggers processing manually and returns the same `processing_results` object

<Info>
  Session webhooks include web validation **decisions** inside `automation_result.triggered_rules` (e.g. `web_ssl`, `web_industry`, `web_score`), not the full `web_validation_results` array. See [Session webhooks — web validation](/api-reference/webhooks/sessions#web-validation-in-webhooks).
</Info>

## Update Session Status

Manually update the status of a session. Use this endpoint for reviewer decisions and operational transitions such as reactivating a session.

### Endpoint

```
PATCH /kyc/sessions/{session_id}
```

### Request Body Parameters

<ParamFields>
  <ParamField name="status" type="string" required description="New status: 'approved', 'rejected', 'manual_review', 'active', or 'completed'" />

  <ParamField name="notes" type="string" description="Optional notes about the status change" />
</ParamFields>

### Request Example

```bash theme={null}
curl -X PATCH https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "approved",
    "notes": "All documents verified successfully"
  }'
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "status": "approved",
    "updated_at": "2024-11-22T10:50:00Z"
  }
}
```

## Request Client Corrections

Request remediation from the end user for specific workflow steps, fields, or document types. The session moves to `awaiting_client_correction`, affected steps move to `needs_correction`, and the existing public access link remains valid.

Use this when a reviewer needs the customer to fix submitted data or replace documents instead of approving or rejecting immediately.

### Endpoint

```
POST /kyc/sessions/{session_id}/corrections
```

### Request Body Parameters

<ParamFields>
  <ParamField name="corrections" type="array" required description="One or more correction targets. Each target must include a workflow step ID and user-visible guidance." />

  <ParamField name="comment" type="string" description="Optional internal audit comment for the reviewer action" />
</ParamFields>

Each item in `corrections` supports:

| Field            | Type   | Description                                           |
| ---------------- | ------ | ----------------------------------------------------- |
| `step_id`        | string | Workflow step that needs correction                   |
| `field_ids`      | array  | Optional form field IDs to correct                    |
| `document_types` | array  | Optional document types to replace or re-upload       |
| `message`        | string | User-visible instructions shown in the public session |

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/corrections \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "corrections": [
      {
        "step_id": "personal_info",
        "field_ids": ["full_name"],
        "message": "Please correct your legal name so it matches your ID."
      },
      {
        "step_id": "id_document",
        "document_types": ["id"],
        "message": "Please upload a clearer photo of your ID."
      }
    ],
    "comment": "Name mismatch and blurry ID image"
  }'
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "status": "awaiting_client_correction",
    "current_step_index": 0,
    "steps_data": [
      {
        "step_id": "id_document",
        "status": "needs_correction",
        "correction_requests": [
          {
            "id": "corr_abc123",
            "step_id": "id_document",
            "document_types": ["id"],
            "message": "Please upload a clearer photo of your ID.",
            "status": "open"
          }
        ]
      }
    ]
  }
}
```

<Info>
  When corrections are requested, any current terminal `final_decision` fields are cleared so the session is no longer displayed as currently approved or rejected while remediation is pending.
</Info>

## Generate Access Link

Generate or regenerate the public access link for a session. Use this to get a new link if the previous one was compromised or needs to be refreshed.

### Endpoint

```
POST /kyc/sessions/{session_id}/generate-link
```

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/generate-link \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "access_token": "880e8400-e29b-41d4-a716-446655440003",
    "link": "https://kyc.legaltalent.ai/public/sessions/880e8400-e29b-41d4-a716-446655440003",
    "expires_at": 1732278600
  }
}
```

## Extend Session Expiration

Extend a session's public access link. This is useful before requesting corrections if the original link has expired.

### Endpoint

```
POST /kyc/sessions/{session_id}/extend
```

### Request Body Parameters

<ParamFields>
  <ParamField name="extend_days" type="integer" required description="Number of days to extend from now (maximum 90)" />

  <ParamField name="comment" type="string" description="Optional audit comment for the extension" />
</ParamFields>

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/extend \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "extend_days": 7,
    "comment": "Allow customer to complete requested corrections"
  }'
```

## Run Validation Checks

Manually trigger validation checks for a session without full processing.

### Endpoint

```
POST /kyc/sessions/{session_id}/validate
```

### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/validate \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "validation_results": {
      "lists_check": {
        "is_match": false,
        "match_count": 0
      },
      "crypto_check": null,
      "adverse_media_check": {
        "risk_score": 15,
        "decision": "CLEAR"
      },
      "validated_at": "2024-11-22T10:45:00Z"
    }
  }
}
```

## Get Document URL

Get a presigned URL to download a document from a session.

### Endpoint

```
GET /kyc/sessions/{session_id}/documents/{doc_id}/url
```

### Request Example

```bash theme={null}
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/documents/doc_abc123/url \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "presigned_url": "https://s3.amazonaws.com/bucket/...",
    "file_name": "passport.jpg",
    "mime_type": "image/jpeg",
    "doc_id": "doc_abc123",
    "document_type": "id",
    "uploaded_at": "2024-11-22T10:32:00Z",
    "expires_at": 1732282200
  }
}
```

## Delete Session

Delete a session and all associated data.

### Endpoint

```
DELETE /kyc/sessions/{session_id}
```

### Request Example

```bash theme={null}
curl -X DELETE https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "session_id": "660e8400-e29b-41d4-a716-446655440001",
    "deleted": true
  }
}
```

## Session Statuses

| Status                       | Description                                                                                    |
| ---------------------------- | ---------------------------------------------------------------------------------------------- |
| `draft`                      | Session created but not yet started                                                            |
| `active`                     | Session is in progress                                                                         |
| `completed`                  | All steps completed, ready for processing                                                      |
| `processing`                 | Session is being processed                                                                     |
| `processed`                  | Processing complete, awaiting review                                                           |
| `expired`                    | Session expired (TTL exceeded)                                                                 |
| `approved`                   | Session approved                                                                               |
| `rejected`                   | Session rejected                                                                               |
| `manual_review`              | Session requires manual review                                                                 |
| `awaiting_client_correction` | Reviewer requested customer corrections; the public link remains usable for the affected steps |

## Canonical Compliance Statuses

List responses include `compliance_status`, a stable operational status for queues and dashboards. It groups low-level session statuses into reviewer-facing inbox states.

| Compliance Status | Technical `status` Values    | Description                                                                    |
| ----------------- | ---------------------------- | ------------------------------------------------------------------------------ |
| `incomplete`      | `draft`, `expired`           | Session was not completed or is no longer available                            |
| `pending`         | `active`, `processing`       | Session is in progress or being processed                                      |
| `manual_review`   | `manual_review`              | Reviewer action is required                                                    |
| `approved`        | `approved`                   | Session has an active approval decision                                        |
| `rejected`        | `rejected`                   | Session has an active rejection decision                                       |
| `remediation`     | `awaiting_client_correction` | Customer corrections are pending                                               |
| `completed`       | `completed`, `processed`     | Customer completed the flow or processing finished without a terminal decision |

## Step Statuses

| Status             | Description                                                |
| ------------------ | ---------------------------------------------------------- |
| `pending`          | Step not yet started                                       |
| `in_progress`      | Step in progress                                           |
| `completed`        | Step completed                                             |
| `skipped`          | Step was skipped                                           |
| `needs_correction` | Step was reopened because a reviewer requested remediation |

## Status Codes

| Code | Description                               |
| ---- | ----------------------------------------- |
| 200  | Success                                   |
| 201  | Created - Session created successfully    |
| 400  | Bad Request - Invalid parameters          |
| 401  | Unauthorized - Missing or invalid token   |
| 403  | Forbidden - Insufficient permissions      |
| 404  | Not Found - Session or workflow not found |
| 500  | Internal Server Error                     |

## Subsessions

Subsessions allow you to collect verification from related parties (UBOs, submerchants, directors) during the main onboarding process. Each subsession is a complete, independent session linked to a parent session.

### Create Subsession

Create a new subsession for verification of a related party.

#### Endpoint

```
POST /kyc/sessions/{session_id}/subsessions
```

#### Request Body Parameters

<ParamFields>
  <ParamField name="step_id" type="string" required description="ID of the subsession_collection step in the parent workflow" />

  <ParamField name="label" type="string" description="Human-readable label for this subsession (e.g., 'Juan Garcia - UBO')" />

  <ParamField name="metadata" type="object" description="Additional metadata for the subsession" />
</ParamFields>

#### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/subsessions \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "step_id": "step_ubos",
    "label": "Juan Garcia - UBO",
    "metadata": {
      "ownership_percentage": 25
    }
  }'
```

#### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "subsession_id": "770e8400-e29b-41d4-a716-446655440003",
    "access_token": "880e8400-e29b-41d4-a716-446655440004",
    "access_link": "https://kyc.legaltalent.ai/public/sessions/880e8400-e29b-41d4-a716-446655440004",
    "workflow_id": "ubo-verification-workflow",
    "status": "active",
    "label": "Juan Garcia - UBO",
    "expires_at": 1732278600,
    "created_at": "2024-11-22T10:30:00Z"
  }
}
```

### List Subsessions

Get all subsessions for a parent session with completion status.

#### Endpoint

```
GET /kyc/sessions/{session_id}/subsessions
```

#### Request Example

```bash theme={null}
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/subsessions \
  -H "Authorization: Bearer YOUR_TOKEN"
```

#### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "subsessions": [
      {
        "subsession_id": "770e8400-e29b-41d4-a716-446655440003",
        "access_token": "880e8400-e29b-41d4-a716-446655440004",
        "access_link": "https://kyc.legaltalent.ai/public/sessions/880e8400-...",
        "status": "completed",
        "workflow_id": "ubo-verification-workflow",
        "label": "Juan Garcia - UBO",
        "created_at": "2024-11-22T10:30:00Z",
        "expires_at": 1732278600,
        "completed_at": "2024-11-22T11:00:00Z"
      },
      {
        "subsession_id": "770e8400-e29b-41d4-a716-446655440005",
        "access_token": "880e8400-e29b-41d4-a716-446655440006",
        "access_link": "https://kyc.legaltalent.ai/public/sessions/880e8400-...",
        "status": "active",
        "workflow_id": "ubo-verification-workflow",
        "label": "Maria Lopez - UBO",
        "created_at": "2024-11-22T10:35:00Z",
        "expires_at": 1732278600
      }
    ],
    "total": 2,
    "completed": 1,
    "pending": 1
  }
}
```

### Regenerate Subsession Link

Generate a new access link for a subsession if the original was lost or compromised.

#### Endpoint

```
POST /kyc/sessions/{session_id}/subsessions/{subsession_id}/regenerate-link
```

#### Request Example

```bash theme={null}
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/subsessions/770e8400-e29b-41d4-a716-446655440003/regenerate-link \
  -H "Authorization: Bearer YOUR_TOKEN"
```

#### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "subsession_id": "770e8400-e29b-41d4-a716-446655440003",
    "access_token": "990e8400-e29b-41d4-a716-446655440007",
    "access_link": "https://kyc.legaltalent.ai/public/sessions/990e8400-e29b-41d4-a716-446655440007",
    "expires_at": 1732278600
  }
}
```

### Delete Subsession

Remove a subsession from a parent session.

#### Endpoint

```
DELETE /kyc/sessions/{session_id}/subsessions/{subsession_id}
```

#### Request Example

```bash theme={null}
curl -X DELETE https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/subsessions/770e8400-e29b-41d4-a716-446655440003 \
  -H "Authorization: Bearer YOUR_TOKEN"
```

#### Response Format

```json theme={null}
{
  "status": "success",
  "data": {
    "subsession_id": "770e8400-e29b-41d4-a716-446655440003",
    "deleted": true
  }
}
```

## Typical Workflow

1. **Create Session**: Create a session linked to a workflow. Optionally pass `subject_data` (e.g. `website` for merchants, or `full_name` / `nationality` for individual KYC) with data you already know
2. **Share Link**: Send the `access_link` to the end user
3. **User Completes Steps**: User uploads documents and fills forms via public API
4. **Subsessions (if applicable)**: User creates subsessions for UBOs/submerchants via the public API
5. **Process Session**: Processing runs automatically when the session completes if the workflow has `auto_process` enabled; otherwise call `POST /process`
6. **Review Results**: Read `processing_results` via `GET /kyc/sessions/{session_id}` (full detail) or act on `kyc.session.processed` webhooks (automation summary)
7. **Request Corrections (optional)**: Move the session to `awaiting_client_correction` with `POST /corrections`
8. **User Resolves Corrections**: The public link shows only the affected steps and open correction guidance
9. **Final Decision**: Update status to `approved` or `rejected` if manual review is needed
