Sessions
curl --request GET \
--url https://api.example.com/kyc/sessionsimport requests
url = "https://api.example.com/kyc/sessions"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/kyc/sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/kyc/sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/kyc/sessions"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/kyc/sessions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/kyc/sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyKYC Workflows & Sessions
Sessions
GET
/
kyc
/
sessions
Sessions
curl --request GET \
--url https://api.example.com/kyc/sessionsimport requests
url = "https://api.example.com/kyc/sessions"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/kyc/sessions', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/kyc/sessions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/kyc/sessions"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/kyc/sessions")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/kyc/sessions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyManage KYC onboarding sessions for end users. Sessions track progress through workflows, store document uploads, and manage the onboarding process from creation to approval.
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
Example — create a session when you already know the subject is Federico Gil:
After the session completes and is processed, check
Unlike website URLs, declaring a person name in
Values are normalized before being stored:
The stored attributes are echoed in
Retrieve results with:
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
Requireskyc: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
Subject data
Usesubject_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:
"website": "https://merchant.example"
"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 |
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) |
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).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.Individual KYC (pre-declared person)
For individual identity workflows (IDV / KYC), pass attributes you already know about the person insubject_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 |
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.{
"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"
}
}
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:
{
"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"]
}
subject_data does not consume extra quota at creation. Sanctions screening only runs when the workflow has run_lists: true (or equivalent automation configuration).
Session attributes
attributes carries facts your integration already knows about this session that the workflow itself is designed to react to — the merchant’s industry, a product line, a customer segment. Unlike subject_data, which feeds processing, session attributes are a typed contract with the workflow: the workflow declares a session_attributes catalog (see Workflows → Session attributes) and every value you send is validated against it.
| Situation | Result |
|---|---|
| Key not declared in the catalog | 400 Unknown session attribute(s): <key> |
Value outside a select attribute’s options | 400 (the submitted value is never echoed back) |
Catalog marks the attribute required and it is missing or blank | 400 Missing required session attribute: <key> |
Workflow declares no catalog but attributes is sent | 400 This workflow does not declare session attributes |
select values are matched case-insensitively and stored as the configured option, country values are uppercased ISO 3166-1 alpha-2 codes, boolean accepts true/false (also as strings) and text is trimmed (max 256 characters).
Each attribute resolves, in order, to the value you sent, then to the value the end user entered in the attribute’s fallback_field_id form field (when the catalog defines one), then to the catalog default. When you send the value, the fallback field is neither shown nor required in the public flow.
{
"workflow_id": "wf_merchant_onboarding",
"client_id": "merchant-456",
"account_country": "UY",
"attributes": {
"industry": "restaurants"
}
}
GET /kyc/sessions/{session_id} as attributes, and the public session API exposes them (catalog keys only) so the end-user flow evaluates the same conditions the backend does.
Sessions created from the dashboard send no
attributes. A workflow whose catalog has required attributes can therefore only be started through the API.Request Example
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
{
"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"
}
}
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.List Sessions
Retrieve all sessions for your tenant with pagination, filtering, and optional summary statistics.Endpoint
GET /kyc/sessions
Query Parameters
Request Example
# 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
{
"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
Wheninclude_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 |
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.
Get Session Details
Retrieve detailed information about a specific session.Endpoint
GET /kyc/sessions/{session_id}
Request Example
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001 \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/process \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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 inprocessing_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) |
error | Generic error code on failure (invalid_url, validation_failed). No URL or internal details are returned |
GET /kyc/sessions/{session_id}— after status isprocessed,approved,rejected, ormanual_reviewPOST /kyc/sessions/{session_id}/process— triggers processing manually and returns the sameprocessing_resultsobject
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.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
Request Example
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
{
"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 toawaiting_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
Each item incorrections 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
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
{
"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"
}
]
}
]
}
}
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.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
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/generate-link \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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
Request Example
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
curl -X POST https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/validate \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/documents/doc_abc123/url \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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
curl -X DELETE https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001 \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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 includecompliance_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
Request Example
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
{
"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
curl https://kyc.legaltalent.ai/kyc/sessions/660e8400-e29b-41d4-a716-446655440001/subsessions \
-H "Authorization: Bearer YOUR_TOKEN"
Response Format
{
"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
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
{
"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
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
{
"status": "success",
"data": {
"subsession_id": "770e8400-e29b-41d4-a716-446655440003",
"deleted": true
}
}
Typical Workflow
- Create Session: Create a session linked to a workflow. Optionally pass
subject_data(e.g.websitefor merchants, orfull_name/nationalityfor individual KYC) with data you already know - Share Link: Send the
access_linkto the end user - User Completes Steps: User uploads documents and fills forms via public API
- Subsessions (if applicable): User creates subsessions for UBOs/submerchants via the public API
- Process Session: Processing runs automatically when the session completes if the workflow has
auto_processenabled; otherwise callPOST /process - Review Results: Read
processing_resultsviaGET /kyc/sessions/{session_id}(full detail) or act onkyc.session.processedwebhooks (automation summary) - Request Corrections (optional): Move the session to
awaiting_client_correctionwithPOST /corrections - User Resolves Corrections: The public link shows only the affected steps and open correction guidance
- Final Decision: Update status to
approvedorrejectedif manual review is needed