List Check
curl --request POST \
--url https://api.example.com/kycimport requests
url = "https://api.example.com/kyc"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/kyc', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$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"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/kyc")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/kyc")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyCompliance Screening
List Check
POST
/
kyc
List Check
curl --request POST \
--url https://api.example.com/kycimport requests
url = "https://api.example.com/kyc"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/kyc', 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",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$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"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/kyc")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/kyc")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_bodyCheck entities against KYC watchlists (OFAC, UN, EU, UK, and many more) to identify sanctions, PEPs (Politically Exposed Persons), crypto-related risks, and other risk entities.
The match works whether the number is stored on the list entry as
or in the JSON body:
Per-request ephemeral must be enabled for your account first: the endpoint identifier (
Endpoint
POST /kyc
Authentication
Requireskyc:create permission. Include your Bearer token in the Authorization header.
Request Body Parameters
Subject Parameter Details
Required Fields
At least one of the following must be provided:| Field | Required If | Description |
|---|---|---|
full_name | No identifiers provided | Full name of the entity |
document_id | No full_name provided | Government-issued ID |
wallet_address | No full_name provided | Cryptocurrency wallet |
identifiers | No full_name provided | Array of identifier objects |
imo_number | No full_name provided | IMO number for vessels |
Entity Types
| Type | Description |
|---|---|
individual | Natural person |
company | Business or corporation |
organization | Non-profit, government agency, etc. |
vessel | Ships, boats (use with imo_number) |
aircraft | Airplanes, helicopters (use with call_sign) |
Identifiers Array Format
When using theidentifiers field, provide an array of objects:
{
"identifiers": [
{
"type": "Ethereum Wallet",
"value": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
},
{
"type": "Bitcoin Address",
"value": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
},
{
"type": "Passport",
"value": "AB1234567"
}
]
}
Identifier Matching
Identifier and document matching is value-first. An exact ID or document number matches a list entry regardless of how the document-type label is named on either side (CI, DNI, National ID, document_id, a numeric id, etc.). Values are normalized
before comparison (non-alphanumeric characters stripped, case-insensitive).
This means you do not need to send document_type to get an exact identifier hit —
document_id alone is enough:
{
"subject": {
"full_name": "Jane Roe",
"document_id": "30708422459"
},
"list_name": "senaclaft_uy"
}
ci, document_id,
a numeric id, or inside an identifiers[] array. Sending document_type (or the
identifiers array) is still supported and never blocks a match. An exact identifier
match always returns confidence_score: 1.0.
nationality and birth_date refine name-based matches only (and may lower
confidence on a mismatch). They never affect an exact identifier match.Ephemeral List Check
For synchronousPOST /kyc list checks, you can request ephemeral processing with either:
X-Data-Retention: ephemeral
{
"data_retention": "ephemeral"
}
kyc.single for single-list checks, kyc.multi for multi-list checks, kyc.batch for direct multi-entity batches — or the wildcard *) has to appear in your tenant’s data_processing_config.allowed_ephemeral_endpoints, otherwise the request is rejected with a 400.
Tenants can also opt in account-wide: when your tenant’s data_processing_config.mode is set to ephemeral, every synchronous list check runs in ephemeral mode regardless of per-request headers or body flags (the tenant-level setting always wins and does not require the allowlist). Contact support to enable either option on your account.
When ephemeral mode is active, the API returns the normal match response but does not save validation records, audit DynamoDB records, or detailed audit events, even if save_validation is true.
The platform still retains aggregate billing metrics, such as one counted list check, and operational logs without subject PII for the configured CloudWatch retention period. Tenants with retain_billing_metrics: false in their data_processing_config also suppress the aggregate usage event.
Ephemeral processing applies to synchronous list checks (single, multi-list, and direct multi-entity batches), 1:1 face verification (see Face Match), adverse media analysis (see Adverse Media), and crypto wallet checks (see Crypto Wallet Check). Asynchronous batch jobs (POST /kyc/jobs) reject ephemeral mode with ZDR_UNSUPPORTED_FOR_BATCH because they rely on SQS queues, job records, and dead-letter queues. Screening and sessions are not covered yet.
Available Watchlists
If you send neither
list_name nor lists (or send an empty lists array),
the check runs against every list enabled for your environment. To pin a
specific set — for example the core sanctions set — pass them explicitly:
"lists": ["ofac", "un", "senaclaft_uy"].Government Sanctions Lists
| List Name | Description | Entity Types Supported |
|---|---|---|
ofac | OFAC SDN List (US Treasury) | Persons, Organizations, Vessels |
un | UN Security Council Consolidated List | Persons, Organizations |
eu | EU Financial Sanctions List | Persons, Organizations |
uk | UK Sanctions List (OFSI) | Persons, Organizations |
canada | Canada Consolidated Autonomous Sanctions | Persons, Organizations |
australia | Australia DFAT Consolidated List | Persons, Organizations |
switzerland | Switzerland SECO Sanctions | Persons, Organizations |
US Export Control Lists
| List Name | Description | Entity Types Supported |
|---|---|---|
us_csl | US Consolidated Screening List (CSL) | Persons, Organizations |
bis_denied_persons | BIS Denied Persons List | Persons |
bis_entity_list | BIS Entity List | Organizations |
Regional & Specialized Lists
| List Name | Description | Entity Types Supported |
|---|---|---|
senaclaft_uy | SENACLAFT Uruguay PEP List | Persons |
world_bank | World Bank Debarred Firms & Individuals | Persons, Organizations |
Cryptocurrency Lists
| List Name | Description | Identifier Types |
|---|---|---|
ransomwhere | Ransomwhe.re Ransomware Addresses | Bitcoin, Ethereum wallets |
nbctf | NBCTF Israel Sanctioned Crypto Wallets | Crypto wallets |
Search Types
| Type | Description | Use Case |
|---|---|---|
exact | Exact name matching | High precision, strict matching |
fuzzy | Approximate string matching | Handle typos and variations |
token | Word-based matching | Find partial name matches |
composite | Combined exact + fuzzy + token strategy | Balanced precision and recall |
fast_precise_cascade | Cascaded fast→precise matching (default) | Best precision/latency balance |
When
search_type is omitted, the default is fast_precise_cascade. The
llm_enhanced value is deprecated and rejected. If you need the previous
default behavior, send "search_type": "composite" explicitly.Request Examples
Check Person Against Single List
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "John Doe",
"nationality": "US",
"birth_date": "1985-03-15"
},
"list_name": "ofac",
"search_type": "composite"
}'
Check Person with Document ID
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "Juan Pérez",
"document_id": "12345678",
"document_type": "CI",
"nationality": "UY"
},
"list_name": "senaclaft_uy"
}'
Check Cryptocurrency Wallet
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
},
"lists": ["ofac", "ransomwhere", "nbctf"]
}'
Check Company
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "Acme Corporation",
"entity_type": "company",
"tax_id": "12-3456789",
"incorporation_country": "US"
},
"lists": ["ofac", "bis_entity_list", "world_bank"]
}'
Check Vessel by IMO Number
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "MV Oceanstar",
"entity_type": "vessel",
"imo_number": "9123456",
"call_sign": "V7AB3"
},
"list_name": "ofac"
}'
Check Multiple Lists
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "John Doe",
"nationality": "US"
},
"lists": ["ofac", "un", "eu", "uk", "canada"],
"search_type": "composite"
}'
Check with Multiple Identifiers
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "John Doe",
"identifiers": [
{
"type": "Ethereum Wallet",
"value": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
},
{
"type": "Bitcoin Address",
"value": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
}
]
},
"lists": ["ofac", "ransomwhere"]
}'
Save Validation for Dashboard
Usesave_validation: true to store the validation result and view it later in the dashboard:
curl -X POST https://kyc.legaltalent.ai/kyc \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": {
"full_name": "John Doe",
"nationality": "US",
"document_id": "AB1234567",
"document_type": "Passport"
},
"lists": ["ofac", "un", "eu"],
"search_type": "composite",
"save_validation": true
}'
Response Format
OFAC Metadata Fields
When an OFAC entry includes public identity metadata, the API returns it insidematches[*].match_data:
nationalitybirth_dateidentifiers(array with document/wallet/tax identifiers depending on list entry data)
{
"match_data": {
"match_type": "composite",
"name": "Allan Estuardo RODRIGUEZ REYES",
"nationality": "Guatemala",
"birth_date": "19 Oct 1981",
"identifiers": [
{ "type": "national id no.", "value": "2754422680101" },
{ "type": "passport", "value": "F5573390" }
]
}
}
Note: Metadata availability depends on source list data. If a source entry does not publish nationality/identifiers, those fields may be absent.The response envelope depends on whether you check a single list (via
list_name) or multiple lists (via lists, or by omitting both — which
checks every enabled list).
- Single-list responses wrap the check under a top-level
resultobject. - Multi-list responses expose
results(keyed by list name) plus asummaryaggregate. - Both include an
execution_contextobject (the request id lives there asexecution_context.request_id— there is nometaobject).
Match Object
Each entry in a list’smatches array has this shape:
| Field | Type | Description |
|---|---|---|
confidence_score | number | Match confidence, 0.0–1.0 (1.0 for exact identifier matches). |
match_type | string | exact, fuzzy, token, or composite. |
match_timestamp | string | ISO timestamp of when the match was computed. |
match_data | object | Raw match payload from the source list (name, identifiers, sanction programs, etc.). For convenience it also repeats confidence_score and match_type; use the top-level fields as canonical. |
Success Response (Single List)
Returned when the request useslist_name.
{
"status": "success",
"result": {
"list_name": "ofac",
"subject": {
"full_name": "John Doe",
"nationality": "US"
},
"is_match": true,
"matches": [
{
"confidence_score": 0.95,
"match_type": "composite",
"match_timestamp": "2026-06-29T10:30:00Z",
"match_data": {
"name": "JOHN DOE",
"entity_type": "individual",
"source": "ofac",
"sanction_programs": ["SDGT"],
"nationality": "US",
"identifiers": [
{ "type": "passport", "value": "AB1234567" }
],
"confidence_score": 0.95,
"match_type": "composite"
}
}
],
"match_count": 1,
"check_timestamp": "2026-06-29T10:30:00Z",
"processing_time_ms": 1250,
"metadata": {
"search_type": "fast_precise_cascade"
},
"execution_time_ms": 1250
},
"execution_context": {
"request_id": "abc-123-def",
"function_name": "kyc-lists-check",
"function_version": "$LATEST",
"processing_time_ms": 1250,
"timestamp": "2026-06-29T10:30:00Z",
"tenant_id": "tnt-123"
}
}
Success Response (Multiple Lists)
Returned when the request useslists (or omits both list_name and lists,
which checks every enabled list). Each entry in results has the same shape as
the single-list result object.
{
"status": "success",
"results": {
"ofac": {
"list_name": "ofac",
"subject": {
"full_name": "John Doe",
"nationality": "US"
},
"is_match": true,
"matches": [
{
"confidence_score": 0.95,
"match_type": "composite",
"match_timestamp": "2026-06-29T10:30:00Z",
"match_data": {
"name": "JOHN DOE",
"entity_type": "individual",
"source": "ofac",
"sanction_programs": ["SDGT"]
}
}
],
"match_count": 1,
"check_timestamp": "2026-06-29T10:30:00Z",
"processing_time_ms": 800,
"metadata": {
"search_type": "fast_precise_cascade"
},
"execution_time_ms": 805
},
"un": {
"list_name": "un",
"subject": {
"full_name": "John Doe",
"nationality": "US"
},
"is_match": false,
"matches": [],
"match_count": 0,
"check_timestamp": "2026-06-29T10:30:00Z",
"processing_time_ms": 600,
"metadata": {
"search_type": "fast_precise_cascade"
},
"execution_time_ms": 602
}
},
"summary": {
"is_match": true,
"match_count": 1,
"lists_checked": ["ofac", "un"],
"lists_with_matches": ["ofac"],
"has_errors": false,
"error_count": 0,
"execution_time_ms": 3200,
"timestamp": "2026-06-29T10:30:00Z"
},
"execution_context": {
"request_id": "abc-123-def",
"processing_time_ms": 3200,
"timestamp": "2026-06-29T10:30:00Z",
"tenant_id": "tnt-123"
}
}
If an individual list fails to evaluate, its entry in
results is replaced
with { "is_match": false, "error": "Validation failed for this list", "matches": [] }
and summary.has_errors is set to true. A failure in one list does not fail
the whole request.Summary Fields (Multi-list)
| Field | Type | Description |
|---|---|---|
is_match | boolean | true if any list returned at least one match. |
match_count | number | Total matches across all checked lists. |
lists_checked | array | List names that were evaluated. |
lists_with_matches | array | Subset of lists_checked that returned matches. |
has_errors | boolean | true if any list failed to evaluate. |
error_count | number | Number of lists that failed. |
execution_time_ms | number | Total evaluation time. |
timestamp | string | ISO timestamp. |
No Match Response (Single List)
{
"status": "success",
"result": {
"list_name": "ofac",
"subject": {
"full_name": "Jane Smith",
"nationality": "CA"
},
"is_match": false,
"matches": [],
"match_count": 0,
"check_timestamp": "2026-06-29T10:30:00Z",
"processing_time_ms": 850,
"metadata": {
"search_type": "fast_precise_cascade"
},
"execution_time_ms": 850
},
"execution_context": {
"request_id": "abc-123-def",
"function_name": "kyc-lists-check",
"function_version": "$LATEST",
"processing_time_ms": 850,
"timestamp": "2026-06-29T10:30:00Z",
"tenant_id": "tnt-123"
}
}
Error Responses
Error responses share the same envelope as success responses: a top-levelstatus: "error", an error object, and an execution_context (the request id
is execution_context.request_id — there is no meta object).
400 Bad Request - Missing Subject
{
"status": "error",
"error": {
"type": "ValidationError",
"message": "Subject must have at least one of: full_name, document_id, wallet_address, identifiers, or imo_number",
"code": "VALIDATION_ERROR"
},
"execution_context": {
"request_id": "abc-123-def",
"processing_time_ms": 5,
"timestamp": "2026-06-29T10:30:00Z"
}
}
400 Bad Request - Unknown List
Sending a list name that is not enabled fails the request (it is not silently skipped):{
"status": "error",
"error": {
"type": "ValidationError",
"message": "Unknown list names: invalid_list. Remove or correct them and retry.",
"code": "VALIDATION_ERROR"
},
"execution_context": {
"request_id": "abc-123-def",
"processing_time_ms": 5,
"timestamp": "2026-06-29T10:30:00Z"
}
}
400 Bad Request - Invalid Birth Date
{
"status": "error",
"error": {
"type": "ValidationError",
"message": "Invalid value for birth_date",
"code": "VALIDATION_ERROR"
},
"execution_context": {
"request_id": "abc-123-def",
"processing_time_ms": 5,
"timestamp": "2026-06-29T10:30:00Z"
}
}
403 Forbidden - Missing Permission
{
"message": "User is not authorized to perform this action"
}
Status Codes
| Code | Description |
|---|---|
| 200 | Success - Check completed |
| 400 | Bad Request - Invalid parameters |
| 401 | Unauthorized - Missing or invalid token |
| 403 | Forbidden - Insufficient permissions |
| 500 | Internal Server Error |