Overview
Every per-feature report follows the V3 serializer shape defined inservice-didit-verification. The same object appears in three places, so the schema you see here is the single source of truth across them:
GET /v3/session/{sessionId}/decision/— each feature is returned as a plural array (id_verifications[],nfc_verifications[],liveness_checks[],face_matches[],poa_verifications[],phone_verifications[],email_verifications[],aml_screenings[],ip_analyses[],database_validations[],questionnaire_responses[], and the KYB equivalentsregistry_checks[],document_verifications[],key_people_checks[]).- Webhook payloads (
status.updated,data.updated) — same shape inside thedecisionenvelope. - Standalone APIs — single-object responses (Face Search, Age Estimation, Biometric Authentication) reuse the same field set.
V3 introduced multi-instance workflows: every feature object carries a
node_id that pins the report to the workflow graph node that produced it. V2 endpoints (singular kyc, face, aml, etc.) remain backwards-compatible but only return the first instance.Common fields
Every report object exposes the following:| Field | Type | Description |
|---|---|---|
status | string | Feature-level lifecycle status — one of the values in Status enum. Source: common/config/choices.py:FeatureStatusChoices (lines 343-348). The parent session’s top-level status uses the wider session enum (StatusChoices, lines 106-117). |
node_id | string | null | Workflow graph node identifier. Populated for V3 multi-instance workflows; null for legacy single-feature sessions. |
warnings | array of warning objects | Risk signals filtered to this feature and node_id. Returned by Session.get_logs(...) (sessions/models/session.py:1611). |
portrait_image, front_image, document_file, …) are presigned URLs with a limited validity window — download them promptly rather than persisting the URL. Examples show them as https://<media-host>/....
Warning object
Returned in everywarnings[] array. Schema from logs/serializers/log.py:8-65 (LogV3Serializer).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
feature | string (enum) | No | Which feature emitted the warning. Values from LogWarningChoices (common/config/choices.py:190-204): ID_VERIFICATION, NFC, LIVENESS, FACEMATCH, PROOF_OF_ADDRESS, PHONE, EMAIL, AML, LOCATION, DATABASE_VALIDATION, QUESTIONNAIRE, KYB_REGISTRY, KYB_DOCUMENTS, KYB_KEY_PEOPLE. | "ID_VERIFICATION" |
risk | string | No | Stable risk code (e.g. DOCUMENT_EXPIRED, LOW_LIVENESS_SCORE). Values from logs/choices.py:RiskChoices. Used as the key into description tables. | "DOCUMENT_EXPIRED" |
additional_data | object | null | Yes | Risk-specific context (e.g. score thresholds, matched fields). Shape varies by risk code. | { "score": 42.1, "threshold": 70 } |
log_type | string (enum) | No | One of error, warning, information. From LogTypeChoices (common/config/choices.py:207-210). | "error" |
short_description | string | No | Human-readable label for the risk. From logs/choices.py:RISK_SHORT_DESCRIPTIONS. | "Document expired" |
long_description | string | No | Longer human-readable explanation suitable for end-user-facing surfaces. From logs/choices.py:RISK_LONG_DESCRIPTIONS. | "The document's expiration date has passed, rendering it no longer valid for use." |
node_id | string | null | Yes | Workflow graph node the warning was raised against. null for legacy V2 logs without node_id. | "first_id_verification" |
Report objects
The remaining sections cover each per-feature report object. The H3 heading text is intentionally stable so other docs can deep-link to it.ID verification
Returned from each KYC/ID document a user submits. Appears asid_verifications[] in GET /v3/session/{sessionId}/decision/ and inside the kyc field of V2 responses. Source: kyc/serializers/kyc.py:383-414 (IDVerificationV3Serializer, extends IDVerificationV2Serializer at kyc/serializers/kyc.py:320-380).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
document_type | string | Yes | Human-readable document class (Passport, Identity Card, Driver's License, Residence Permit, Health Insurance Card, Tax Card). Source: DOC_TYPE_MAPPING (common/config/choices.py:1132-1139). | "Passport" |
document_subtype | string | Yes | Accepted document subtype code from the workflow document settings. Region-specific documents include the region. | "QUEENSLAND_DRIVER_LICENSE_GENERIC" |
document_number | string | Yes | OCR-extracted document number. | "AB1234567" |
personal_number | string | Yes | OCR-extracted personal/national identifier. | "99999999R" |
portrait_image | string (URL) | Yes | Presigned URL to the face crop. | "https://<media-host>/.../portrait.jpg?..." |
front_image | string (URL) | Yes | Presigned URL to the cleaned document front. | "https://<media-host>/.../front.jpg?..." |
front_video | string (URL) | Yes | Presigned URL to the front capture video (when available). | "https://<media-host>/.../front.mp4?..." |
back_image | string (URL) | Yes | Presigned URL to the cleaned document back. | "https://<media-host>/.../back.jpg?..." |
back_video | string (URL) | Yes | Presigned URL to the back capture video. | null |
full_front_image | string (URL) | Yes | Unclipped (full-frame) front capture. | "https://<media-host>/.../full_front.jpg?..." |
full_back_image | string (URL) | Yes | Unclipped (full-frame) back capture. | null |
front_image_camera_front | string (URL) | Yes | Front-camera image taken at the same time as the document front. | null |
back_image_camera_front | string (URL) | Yes | Front-camera image taken at the same time as the document back. | null |
front_image_camera_front_face_match_score | float (0-100) | Yes | Similarity between the document portrait and the front-camera capture. | null |
back_image_camera_front_face_match_score | float (0-100) | Yes | Same as above but for the back capture. | null |
front_image_quality_score | object | Yes | Quality metrics for the front image: scores 0-100 (focus_score, brightness_score, resolution_score, overall_score), plus brightness_issue (ok, too_dark, too_bright) and is_document_fully_visible (boolean). | { "focus_score": 91.0, "overall_score": 88.5 } |
back_image_quality_score | object | Yes | Same shape as front_image_quality_score. | null |
date_of_birth | string (YYYY-MM-DD) | Yes | OCR-extracted DOB. | "1990-05-12" |
age | integer | Yes | Computed age in years at extraction time. | 35 |
expiration_date | string (YYYY-MM-DD) | Yes | Document expiration. | "2032-05-11" |
date_of_issue | string (YYYY-MM-DD) | Yes | Document issue date. | "2022-05-11" |
issuing_state | string (ISO 3166-1 alpha-3) | Yes | Issuing country code. | "ESP" |
issuing_state_name | string | Yes | Localized issuing country name. | "Spain" |
first_name | string | Yes | OCR-extracted given name(s). | "María" |
last_name | string | Yes | OCR-extracted surname(s). | "García López" |
full_name | string | Yes | Full normalized name (vendor-supplied). | "María García López" |
gender | string | Yes | M, F, or other vendor-supplied value. | "F" |
address | string | Yes | Raw OCR-extracted address line. | "Calle Mayor 1, 28001 Madrid" |
formatted_address | string | Yes | Geocoded/formatted address (when parseable). | "Calle Mayor 1, 28001 Madrid, Spain" |
parsed_address | object | Yes | Structured, geocoded address: street_1, street_2, city, region, country, postal_code, address_type, formatted_address, document_location ({latitude, longitude}), raw_results, is_best_match. Source: kyc/utils/address.py:147-197. | { "street_1": "Calle Mayor 1", "city": "Madrid", "postal_code": "28001", "country": "ES" } |
place_of_birth | string | Yes | OCR-extracted place of birth. | "Madrid" |
marital_status | string | Yes | When extractable. | null |
nationality | string (ISO 3166-1 alpha-3) | Yes | OCR-extracted nationality. | "ESP" |
extra_fields | object | Yes | Document-type-specific fields not covered by the canonical schema (e.g. driver license categories). | { "DL Class": "B" } |
mrz | object | Yes | Parsed MRZ fields when present (document_number, birth_date, expiry_date, surname, given_names, …). | { "document_number": "AB1234567", "surname": "GARCIA", "given_names": "MARIA" } |
extra_files | array of strings (URL) | No | Presigned URLs to any additional uploaded files. | [] |
matches | array of objects | No | Cross-session document matches. Each item: { session_id, session_number, vendor_data, verification_date, user_details: { name, document_type, document_number }, status, is_blocklisted, api_service, front_image_url }. front_image_url is presigned. | [] |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_id_verification" |
warnings | array | No | See Warning object. | [] |
NFC verification
Returned for each ePassport chip read against an ID document. Appears asnfc_verifications[] in GET /v3/session/{sessionId}/decision/ (one per parent KYC record). Source: kyc/serializers/epassport.py:121-139 (NFCV3Serializer, extends NFCV2Serializer at kyc/serializers/epassport.py:83-118).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
portrait_image | string (URL) | Yes | Presigned URL to the chip-extracted face image. | "https://<media-host>/.../nfc_portrait.jpg?..." |
signature_image | string (URL) | Yes | Presigned URL to the chip-extracted signature image (when stored on the chip). | null |
chip_data | object | Yes | Personal data parsed from the chip’s Data Groups, flattened (kyc/utils/epassport.py:165-212): dgs (Data Groups read), surname, name, country, nationality, birth_date (YYYY-MM-DD), expiry_date (YYYY-MM-DD), sex (M/F), document_type (MRZ document code), document_number, optional_data, MRZ check digits (birth_date_hash, expiry_date_hash, document_number_hash, optional_data_hash, final_hash), mrz_string, mrz_type (TD1/TD2/TD3); plus place_of_birth and address (and full_name / full_name_non_latin for non-Latin names) when the chip carries DG11 — those keys are absent otherwise. null when the NFC step was skipped. | { "document_number": "AB1234567", "name": "MARIA" } |
authenticity | object | No | { sod_integrity, dg_integrity }. sod_integrity validates that the Document Security Object (SOD) signature chains to a valid issuing-country CSCA (and the DSC is neither revoked nor expired); dg_integrity validates that each Data Group hashes match the SOD. Both true means the chip is genuine and untampered. | { "sod_integrity": true, "dg_integrity": true } |
certificate_summary | object | Yes | Summary of the document-signer certificate (kyc/utils/epassport.py:338-348): issuer, subject, serial_number (integer), not_valid_before, not_valid_after (YYYY-MM-DD HH:MM:SS), plus a validation object { csca_verified, dsc_revoked, dsc_expired, csca_expired } (kyc/views/epassport.py:86). | { "issuer": "Common Name: CSCA SPAIN, Country: ES", "not_valid_after": "2031-02-18 10:21:11" } |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_nfc" |
warnings | array | No | See Warning object. | [] |
Liveness check
Returned per liveness session. Appears asliveness_checks[] in GET /v3/session/{sessionId}/decision/. Source: face/serializers/face.py:301-320 (LivenessV3Serializer, extends LivenessV2Serializer at face/serializers/face.py:216-298).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
method | string (enum) | Yes | ACTIVE_3D, FLASHING, or PASSIVE (LivenessMethodChoices, common/config/choices.py:514-517). Passive runs when desktop sessions are allowed and the user is on a desktop. | "PASSIVE" |
score | float (0-100) | Yes | Liveness confidence, rounded to 2 decimals. | 92.41 |
reference_image | string (URL) | Yes | Presigned URL to the user’s reference face crop. | "https://<media-host>/.../reference.jpg?..." |
video_url | string (URL) | Yes | Presigned URL to the liveness video (active mode only). | "https://<media-host>/.../liveness.webm?..." |
age_estimation | float | Yes | Estimated age (in years) of the largest face in the reference image. | 34.2 |
matches | array of objects | No | Cross-session face matches. Each item: { session_id, session_number, similarity_percentage, vendor_data, verification_date, user_details: { full_name, document_type, document_number }, match_image_url, status, is_blocklisted, is_allowlisted, api_service, source }. source is session, imported, or list_entry; match_image_url is presigned. | [] |
face_quality | float (0-100) | Yes | Passive-liveness face-quality score (normalized to a percentage). | 87.50 |
face_luminance | float (0-100) | Yes | Passive-liveness face-luminance score (normalized from 0-255 to a percentage). | 54.12 |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_liveness" |
warnings | array | No | See Warning object. | [] |
Face match
Returned per face-match comparison (typically the user’s liveness face against the document portrait). Appears asface_matches[] in GET /v3/session/{sessionId}/decision/. Source: face/serializers/face.py:367-389 (FaceMatchV3Serializer, extends FaceMatchV2Serializer at face/serializers/face.py:323-364).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
score | float (0-100) | Yes | Similarity, rounded to 2 decimals. When the provider returns only an unmatched_faces[].Confidence, it’s converted to 100 - confidence. | 97.83 |
source_image_session_id | string (UUID) | Yes | The session whose stored portrait supplied the source (reference) image — set in portrait-based flows (biometric authentication, or a portrait supplied at session creation). null when the reference is the document portrait from the same session. | null |
source_image | string (URL) | Yes | Presigned URL to the source (reference) image — usually the document portrait, or the stored portrait in biometric-authentication flows. | "https://<media-host>/.../source.jpg?..." |
target_image | string (URL) | Yes | Presigned URL to the target (live face) image captured during liveness. | "https://<media-host>/.../target.jpg?..." |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_face_match" |
warnings | array | No | See Warning object. | [] |
Face search
Returned by the standalone Face Search API (POST /v3/face-search/). Face Search never appears as a plural array in /v3/session/{sessionId}/decision/ — when persisted with save_api_request=true the session surfaces there as a FACE_SEARCH entry in features[] plus a liveness_checks[] item carrying the stored matches. Sources: apis/serializers/face_search.py:8-79 (FaceSearchResponseSerializer wrapping FaceSearchDetailsSerializer); match dicts built in face/utils/utils.py:869-884.
Top-level response:
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
request_id | string (UUID) | No | The persisted session id when save_api_request=true (usable with GET /v3/session/{sessionId}/decision/); otherwise a transient correlation UUID. | "4a1c2c4e-8b1b-4d6a-91b5-ee9a1f3a2c7f" |
face_search | object | No | The search-details payload — see fields below. | — |
vendor_data | string | Yes | Echoed vendor_data from the request. | null |
metadata | object | Yes | Echoed metadata from the request. | null |
created_at | string (ISO 8601) | No | Server-side request timestamp. | "2026-06-12T01:04:42.763237+00:00" |
face_search object:
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | Declined only when a FACE_IN_BLOCKLIST or POSSIBLE_FACE_IN_BLOCKLIST warning fired; Approved otherwise — duplicate matches alone never decline (apis/views/face_search.py:242-248). | "Approved" |
total_matches | integer | No | Number of returned matches in matches[] (0–5). | 1 |
matches | array of face-search match objects | No | Up to 5 matches above the similarity floor, sorted by descending similarity (blocklisted entries first with search_type=blocklisted_or_approved). | […] |
user_image | object | No | Detection result for the submitted image: { entities: [{ bbox, confidence }], best_angle } — one entity per detected face. | { "entities": [{ "bbox": [40, 40, 120, 120], "confidence": 0.73 }], "best_angle": 0 } |
warnings | array of objects | No | Reduced warning shape for this standalone API — no node_id. The serializer contract declares { risk, additional_data, log_type, short_description, long_description } (apis/serializers/face_search.py:49-54); the runtime payload also carries feature, always "LIVENESS" (apis/views/face_search.py:332-341). | [] |
Face-search match object
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
session_id | string (UUID) | Yes | The matched verification session. null when source is imported or list_entry. | "a3f2a6f1-…" |
session_number | integer | Yes | Console-friendly number of the matched session; null for non-session matches. | 1024 |
similarity_percentage | float (0-100) | No | Similarity between the submitted face and the matched face. | 96.42 |
source | string (enum) | No | Where the matched face was enrolled from: session (verification session or saved standalone call), imported (direct user-profile face upload), list_entry (face attached to a list). | "session" |
vendor_data | string | Yes | The matched session’s vendor_data (or the imported profile’s). | "user-12345" |
verification_date | string (ISO 8601) | Yes | When the matched face was captured; null for list_entry matches. | "2024-11-04T09:14:02Z" |
user_details | object | Yes | { full_name, document_type, document_number } from the matched session’s document verification; for imported matches only full_name is set; null when no identity data exists. | { "full_name": "María García López", "document_type": "Passport", "document_number": "AB1234567" } |
match_image_url | string (URL) | No | Matched user’s reference face — presigned URL when save_api_request=true, raw storage path otherwise. | "https://<media-host>/.../matched.jpg?..." |
status | string | Yes | The matched session’s verification status (see Status enum); null for non-session matches. | "Approved" |
is_blocklisted | boolean | No | Whether the matched face is in your face blocklist. | false |
is_allowlisted | boolean | No | Whether the matched face is in one of your allowlists. | false |
api_service | string (enum) | Yes | Uppercase standalone API type of the matched session (e.g. PASSIVE_LIVENESS, FACE_MATCH); null for workflow sessions and non-session matches. | null |
AML screening
Returned per screened entity. Appears asaml_screenings[] in GET /v3/session/{sessionId}/decision/ for both KYC and KYB sessions. Source: aml/serializers/aml.py:63-85 (AMLV3Serializer, extends AMLV2Serializer at aml/serializers/aml.py:28-60).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
total_hits | integer | No | Number of screening hits (always present, defaults to 0). | 2 |
entity_type | string (enum) | Yes | person or company (EntityTypeChoices, common/config/choices.py:675-677). | "person" |
hits | array of objects | No | One entry per hit. Key fields: id, caption, match (bool), target (bool | null — whether the entity is the direct target of the listing), match_score (float 0-100 identity confidence), risk_score (float 0-100 entity risk), score (deprecated 0-1 float), datasets[] (e.g. PEP, PEP Level 1-4, Sanctions, Adverse Media, Warnings and Regulatory Enforcement, Fitness and Probity), properties (names, aliases, dates of birth, …), features, url, first_seen, last_seen, rca_name, risk_view, score_breakdown, pep_matches, sanction_matches, warning_matches, adverse_media_matches, adverse_media_details, linked_entities, additional_information, and review_status (Unreviewed, Confirmed Match, False Positive, Inconclusive — editable via the update-AML-hit-status endpoint, AMLHitStatusChoices). | […] |
score | float (0-100) | Yes | Overall screening score — the highest risk_score among hits not marked False Positive (aml/services/aml.py:832-842); 0 when every hit is a false positive. null until computed. | 42.7 |
screened_data | object | Yes | Snapshot of the data sent to screening: full_name, nationality, date_of_birth, document_number. | { "full_name": "María García López", "date_of_birth": "1990-05-12" } |
is_ongoing_monitoring_enabled | boolean | No | Whether the entity is subscribed to ongoing-monitoring re-screens. | false |
next_ongoing_monitoring_bill_date | string (YYYY-MM-DD) | Yes | Computed as last_aml_bill_date + 365 days when ongoing monitoring is enabled. | null |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_aml" |
warnings | array | No | See Warning object. | [] |
IP analysis
Returned per captured network location. Appears asip_analyses[] in GET /v3/session/{sessionId}/decision/ for both KYC and KYB sessions. Source: kyc/serializers/location.py:196-243 (IPAnalysisSerializerV3).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_ip_analysis" |
device_brand | string | Yes | User-agent-derived device brand. | "Apple" |
device_model | string | Yes | Device model. | "iPhone" |
browser_family | string | Yes | Browser family. | "Mobile Safari" |
os_family | string | Yes | OS family. | "iOS" |
platform | string | Yes | High-level platform (mobile, desktop, tablet). | "mobile" |
device_fingerprint | string | Yes | Stable per-device fingerprint hash. | "f2a3…" |
ip_country | string | Yes | Country name resolved from the IP. | "Spain" |
ip_country_code | string (ISO 3166-1 alpha-2) | Yes | Country code resolved from the IP. | "ES" |
ip_state | string | Yes | Region / state resolved from the IP. | "Comunidad de Madrid" |
ip_city | string | Yes | City resolved from the IP. | "Madrid" |
latitude | float | Yes | IP-derived latitude. | 40.4168 |
longitude | float | Yes | IP-derived longitude. | -3.7038 |
ip_address | string | Yes | The captured IP address. | "203.0.113.42" |
isp | string | Yes | ISP name. | "Telefonica de Espana" |
organization | string | Yes | Organization name (often equal to ISP). | "Telefonica de Espana" |
is_vpn_or_tor | boolean | Yes | true when the IP belongs to a VPN, proxy, or Tor exit node. | false |
is_data_center | boolean | Yes | true when the IP belongs to a known hosting / data-center ASN. | false |
time_zone | string | Yes | IANA time-zone name. | "Europe/Madrid" |
time_zone_offset | string | Yes | UTC offset. | "+02:00" |
ip | object | No | { location, distance_from_id_document, distance_from_poa_document }. location = { latitude, longitude }. Distances in km, null when either side is missing. | { "location": { "latitude": 40.4168, "longitude": -3.7038 }, "distance_from_id_document": 3.4, "distance_from_poa_document": 1.1 } |
id_document | object | No | { location, distance_from_ip, distance_from_poa_document }. ID document location resolved from issuing_state and parsed address. | { "location": { "latitude": 40.4165, "longitude": -3.7026 }, "distance_from_ip": 3.4, "distance_from_poa_document": 4.0 } |
poa_document | object | No | { location, distance_from_ip, distance_from_id_document }. POA address geocoded. | { "location": { "latitude": 40.4170, "longitude": -3.7040 }, "distance_from_ip": 1.1, "distance_from_id_document": 4.0 } |
matches | array of objects | No | Cross-session IP/device matches. Each item: { session_id, session_number, vendor_data, verification_date, match_type, match_source, matched_value, status, is_blocklisted, api_service, source, device_info, location_info, confidence, match_mode }. match_type is ip_address or device_fingerprint; match_source is ip_address, persistent_id, legacy_fp, or recovered_high (recovered matches also carry recovery_similarity, tls_ja4_corroborated, recovery_gate_reason). Capped at 5 IP + 5 device matches. | [] |
warnings | array | No | See Warning object. | [] |
Proof of address
Returned per submitted address document. Appears aspoa_verifications[] in GET /v3/session/{sessionId}/decision/. Source: poa/serializers/poa.py:212-227 (POAV3Serializer, extends POAV2Serializer at poa/serializers/poa.py:173-209).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
issuing_state | string (ISO 3166-1 alpha-3) | Yes | Country code of the document issuer. | "ESP" |
document_type | string | No | High-level type from PoaDocumentTypeChoices (common/config/choices.py:868-873): UTILITY_BILL, BANK_STATEMENT, GOVERNMENT_ISSUED_DOCUMENT, OTHER_POA_DOCUMENT. Falls back to UNKNOWN — never null. | "UTILITY_BILL" |
document_subtype | string | No | Subtype code from PoaDocumentSubtypeChoices (e.g. ELECTRICITY_BILL, WATER_BILL, ACCOUNT_STATEMENT). Falls back to UNKNOWN — never null. | "ELECTRICITY_BILL" |
issuer | string | Yes | Name of the issuing entity. | "Iberdrola" |
issue_date | string (YYYY-MM-DD) | Yes | Document issue date. | "2026-04-15" |
expiration_date | string (YYYY-MM-DD) | Yes | Expiration date printed on the document, when present. | null |
poa_address | string | Yes | Raw OCR-extracted address. | "Calle Mayor 1, 28001 Madrid" |
poa_formatted_address | string | Yes | Geocoded/formatted address. | "Calle Mayor 1, 28001 Madrid, Spain" |
poa_parsed_address | object | Yes | Structured address (street_1, street_2, city, region, postal_code, country (alpha-2), address_type, document_location, …). | { "street_1": "Calle Mayor 1", "city": "Madrid", "postal_code": "28001" } |
document_file | string (URL) | Yes | Presigned URL to the uploaded document. | "https://<media-host>/.../poa.pdf?..." |
document_language | string | Yes | Detected document language (ISO 639-1). | "es" |
document_metadata | object | Yes | Filtered metadata: file_size, content_type, creation_date, modified_date, creator, producer, software, encryption, is_signed, is_tampered, signature_info, exif_original_date, exif_digitized_date, processed_by_known_editor, has_different_creation_mod_date, overlay_manipulation. | { "file_size": 184221, "content_type": "application/pdf", "is_tampered": false } |
extra_fields | object | No | Bank-account fields (bank_account_number, bank_iban, bank_sort_code, bank_routing_number, bank_swift_bic, bank_branch_name, bank_branch_address), document_phone_number, additional_names, plus any custom keys persisted on the record. | { "bank_iban": null, "additional_names": [] } |
name_on_document | string | Yes | Name as it appears on the POA. | "María García López" |
expected_details_address | string | Yes | Address the customer typed during signup (verbatim). | "Calle Mayor 1, Madrid" |
expected_details_formatted_address | string | Yes | Geocoded expected address. | "Calle Mayor 1, 28001 Madrid, Spain" |
expected_details_parsed_address | object | Yes | Structured expected address. | { "city": "Madrid", "postal_code": "28001" } |
name_match_score_expected_details | float (0-100) | Yes | Fuzzy match between name_on_document and the name supplied at session creation. | 94.0 |
name_match_score_id_verification | float (0-100) | Yes | Fuzzy match between name_on_document and the verified ID’s full_name. | 100.0 |
extra_files | array of strings (URL) | No | Presigned URLs to additional uploaded files. | [] |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_poa" |
warnings | array | No | See Warning object. | [] |
Phone verification
Returned per phone-verification attempt. Appears asphone_verifications[] in GET /v3/session/{sessionId}/decision/ for both KYC and KYB sessions. Source: phone/serializers/phone.py:251-266 (PhoneV3Serializer, extends PhoneV2Serializer at phone/serializers/phone.py:103-248).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
phone_number_prefix | string | No | E.164 country prefix (with +). | "+34" |
phone_number | string | No | Subscriber number without the prefix. | "612345678" |
full_number | string | No | The full E.164 number (phone_number_prefix + phone_number). | "+34612345678" |
country_code | string (ISO 3166-1 alpha-2) | Yes | Country of the number. | "ES" |
country_name | string | Yes | Localized country name. | "Spain" |
carrier | object | No | { name, type } where type is a LineTypeChoices value (common/config/choices.py:648-667): mobile, fixed_line, voip, isp, vpn, toll_free, premium_rate, satellite, pager, payphone, voice_mail, unknown, and other line classes. | { "name": "Movistar", "type": "mobile" } |
is_disposable | boolean | No | true when the carrier marks the number as temporary/disposable. | false |
is_virtual | boolean | No | true when carrier.type is one of voip, isp, vpn. | false |
verification_method | string | No | Channel used to deliver the OTP (whatsapp, sms, …). Reads from the last send attempt’s actual_channel (falls back to the requested channel, then sms). | "whatsapp" |
verification_attempts | integer | No | Total OTP send attempts (initial send plus resends). | 1 |
verified_at | string (ISO 8601) | Yes | Timestamp the OTP was successfully entered. | "2026-05-17T10:14:02Z" |
lifecycle | array of objects | No | Chronological events: send attempts, delivery callbacks, code checks, and the final status event. Each event is { type, timestamp, details, fee }. Event types come from PhoneEventChoices. | […] |
matches | array of objects | No | Cross-session phone-number matches. Each item: { session_id, session_number, vendor_data, verification_date, phone_number, status, is_blocklisted, api_service, source }. source is session or list_entry. | [] |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_phone" |
warnings | array | No | See Warning object. | [] |
Email verification
Returned per email-verification attempt. Appears asemail_verifications[] in GET /v3/session/{sessionId}/decision/ for both KYC and KYB sessions. Source: email_verification/serializers/email.py:149-164 (EmailV3Serializer, extends EmailV2Serializer at email_verification/serializers/email.py:38-146).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
email | string | No | The submitted email address. | "maria.garcia@example.com" |
is_breached | boolean | No | true when the email appears in a known data breach. | false |
breaches | array of objects | No | Per-breach detail when is_breached is true: { name, domain, logo_path, breach_date, description, is_verified, data_classes, breach_emails_count }. | [] |
is_disposable | boolean | No | true when the email belongs to a disposable-mail provider. | false |
is_undeliverable | boolean | No | true when SMTP delivery probing shows the inbox doesn’t accept mail. | false |
verification_attempts | integer | No | Total OTP check attempts. | 1 |
verified_at | string (ISO 8601) | Yes | Timestamp the OTP was successfully entered. | "2026-05-17T10:15:22Z" |
lifecycle | array of objects | No | Chronological events: send attempts, code checks, and the final status event. Each event is { type, timestamp, details, fee }. Event types come from EmailEventChoices. | […] |
matches | array of objects | No | Cross-session email matches. Each item: { session_id, session_number, vendor_data, verification_date, email, status, is_blocklisted, api_service, source }. source is session or list_entry. | [] |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_email" |
warnings | array | No | See Warning object. | [] |
Database validation
Returned per database lookup run against the user’s submitted data. Appears asdatabase_validations[] in GET /v3/session/{sessionId}/decision/. Source: database_validation/serializers/database_validation.py:21-142 (DatabaseValidationV3Serializer, extends DatabaseValidationV2Serializer).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
issuing_state | string (ISO 3166-1 alpha-3) | Yes | Country whose registry was queried. | "ESP" |
validation_type | string (enum) | No | How the result was corroborated: one_by_one (single-service outcome), two_by_two (two or more distinct services independently full-matched the identification number), or not_enabled (the validator was skipped or no provider responded — a definitive no_match still yields one_by_one). Never null. Source: DatabaseValidationChoices (common/config/choices.py:1097-1100). | "one_by_one" |
screened_data | object | No | The data submitted to the registry. File fields (selfie, cnh_qr_code_image, document_image) are presigned at read time. | { "document_number": "99999999R", "date_of_birth": "1990-05-12" } |
validations | array of objects | No | One entry per catalog service that produced a match. Each entry can include service_id, service_name, validation (provider verdict object), outcome_code, outcome_detail, and source_data (cleaned citizen profile: full_name, gender, date_of_birth, photo (presigned URL), signature (presigned URL), …). | […] |
errors | array of objects | Yes | Per-service errors when a lookup failed; the key is omitted entirely when empty. Each entry is the upstream service’s error object plus the service_id that produced it. | [] |
match_type | string (enum) | Yes | Aggregate match verdict across queried services: full_match, partial_match, or no_match (DatabaseValidationMatchTypeChoices, common/config/choices.py:1103-1106). null until evaluated. | "full_match" |
status | string | No | See Status enum. | "Approved" |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_db_validation" |
warnings | array | No | See Warning object. | [] |
Questionnaire response
Returned per questionnaire submission. Appears asquestionnaire_responses[] in GET /v3/session/{sessionId}/decision/ for both KYC and KYB sessions. Source: questionnaires/serializers/questionnaire.py:591-597 (QuestionnaireResponseV3Serializer, extends QuestionnaireResponseSerializer at questionnaires/serializers/questionnaire.py:520-588).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
questionnaire_id | string (UUID) | No | Identifier of the questionnaire version that was answered. | "6a0f1c2c-…" |
title | string | No | Questionnaire name, as set in the Console. | "Customer risk profile" |
description | string | Yes | Questionnaire description. | "Short risk-profile questions." |
languages | array of strings | No | Language codes the questionnaire is published in. | ["en", "es"] |
default_language | string | No | Fallback language code. | "en" |
is_active | boolean | No | Whether this questionnaire version is the active one. | true |
is_simple_questionnaire | boolean | No | true when the questionnaire has no branching (flat list). | true |
questionnaire_group_id | string (UUID) | No | Identifier shared across versions of the same questionnaire. | "a7c2c2c2-…" |
version | integer | No | Version number of the active template. | 3 |
status | string | No | One of Approved, In Review, Not Finished (a questionnaire-level decline maps to In Review). | "Approved" |
published_at | string (ISO 8601) | Yes | When the template was published. | "2026-01-12T11:00:00Z" |
sections | array of objects | No | Ordered sections after applying graph traversal and visibility filtering. Each section is { title, description, items[] } (title/description come from the opening SECTION_HEADER, pre-translated). Each item is a form element (uuid, value (node id), element_type, is_required, title, description, placeholder, choices, max_files, required_if, repeatable_config, plus an answer field — null when unanswered, omitted on HEADING/PARAGRAPH/SEPARATOR layout items). File answers contain { files: [<presigned URL>, …] }. | […] |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_questionnaire" |
Age estimation
Returned by the standalone Age Estimation API (POST /v3/age-estimation/). The response carries a subset of Liveness check’s shape under an age_estimation envelope — status, method, score, age_estimation, warnings — plus a standalone-only user_image face-detection block; it does not include reference_image, video_url, matches, face_quality, or face_luminance. In workflow sessions there is no separate array — the estimated age surfaces as liveness_checks[].age_estimation in GET /v3/session/{sessionId}/decision/. Source: apis/serializers/age_estimation.py:50-55 (AgeEstimationResponseSerializer), envelope assembled in apis/views/age_estimation.py:138-174.
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
request_id | string (UUID) | No | Persisted session id when save_api_request=true (the default); otherwise a transient correlation UUID. | "3b1f1e2c-…" |
age_estimation | object | No | Result envelope: status (Approved / Declined), method (always PASSIVE), score (liveness 0-100, nullable), age_estimation (predicted age in years of the largest face, nullable), user_image (entities[] with per-face age, bbox [x_min, y_min, x_max, y_max], confidence, gender; plus best_angle), warnings[]. | { … } |
vendor_data | string | Yes | Echoed vendor_data from the request. | null |
metadata | object | Yes | Echoed metadata from the request. | null |
created_at | string (ISO 8601) | No | Server-side request timestamp. | "2026-05-17T10:22:13.512941+00:00" |
Biometric authentication
Biometric authentication runs the same Liveness + Face Match pipeline used in standard KYC, but configured to compare the captured face against an existing user’s reference image instead of a freshly-OCR’d document portrait. There is no dedicated serializer —GET /v3/session/{sessionId}/decision/ returns the standard Liveness check and Face match objects under liveness_checks[] and face_matches[]. The session’s workflow is configured with workflow_type = "biometric_authentication" (WorkflowTypeChoices, common/config/choices.py:636).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
liveness_checks | array of Liveness check | No | Liveness result for the authentication attempt. | [ { "status": "Approved", … } ] |
face_matches | array of Face match | No | Match result against the enrolled reference. source_image_session_id is set to the session’s own session_id — the supplied portrait_image is stored under the authentication session itself (face/views/face.py:656-659). | [ { "status": "Approved", "source_image_session_id": "…", … } ] |
status | string | No | Top-level session status (see Status enum). | "Approved" |
KYB registry
Returned per registry-confirmed company in a KYB workflow. Appears asregistry_checks[] in GET /v3/session/{sessionId}/decision/ for business sessions. Source: kyb/serializers/kyb.py:939-964 (RegistryCheckV3Serializer).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_registry" |
data_resolved | boolean | No | true when the registry fetch has completed (or is_from_registry is false, meaning the data was entered manually). | true |
company | object | No | Full company payload — see Company object below. | { … } |
ownership_structure | object | Yes | Provider-supplied ownership graph (nodes, edges, percentages). Free-form JSON. | { "nodes": [...], "edges": [...] } |
warnings | array | No | See Warning object. | [] |
Company object
Fromkyb/serializers/kyb.py:220-321 (KYBCompanyResponseSerializer).
| Field | Type | Nullable | Description |
|---|---|---|---|
uuid | string (UUID) | No | Internal company identifier. |
node_id | string | null | Yes | Workflow node identifier. |
status | string | No | Feature status (FeatureStatusChoices). |
registry_status | string | Yes | Company status from the registry (active, dissolved, …). |
data_resolved | boolean | No | Same definition as on the parent object. |
company_name | string | Yes | Registered company name. |
registration_number | string | Yes | Registry identifier. |
country_code | string (ISO 3166-1 alpha-2) | Yes | Country of incorporation. |
region | string | Yes | ISO 3166-2 subdivision when applicable (e.g. US-CA). |
company_type | string | Yes | Legal form (LLC, SL, …). |
incorporation_date | string (YYYY-MM-DD) | Yes | Date of incorporation. |
registered_address | string | Yes | Registered legal address. |
tax_number | string | Yes | Tax / VAT identifier. |
risk_level | string | Yes | Provider-supplied risk rating. |
verification_status | string | Yes | Internal verification status enum. |
is_from_registry | boolean | No | true when sourced from the registry (vs. manual entry). |
fetch_status | string | Yes | pending, resolved, failed. |
alternative_names | string | Yes | Comma-separated alternative trade names. |
nature_of_business | string | Yes | Free-text business activity description. |
registered_capital | string | Yes | Registered capital as a human-readable string. |
registered_capital_amount | string (decimal) | Yes | Parsed registered capital amount. |
registered_capital_currency | string (ISO 4217) | Yes | Currency code. |
website | string (URL) | Yes | Company website. |
email | string | Yes | Public contact email. |
phone | string | Yes | Public contact phone. |
legal_entity_identifier | string | Yes | LEI when available. |
location_of_registration | string | Yes | Registry office / region. |
financial_summary | object | Yes | Snapshot of latest financial highlights when supplied by the registry. |
officers | array of objects | No | B2C-safe officer list: { uuid, name, designation, role, nationality, is_active, kyc_status, kyc_session_url }. |
beneficial_owners | array of objects | No | B2C-safe UBO list: { uuid, name, first_name, last_name, entity_type, roles, ownership_min_shares, ownership_max_shares, is_active, kyc_status, kyc_session_url, effective_ownership_percent }. |
addresses | array of objects | Yes | Per-address detail from the registry. |
industries | array of objects | Yes | SIC/NAICS-style classifications. |
accounts | array of objects | Yes | Filed accounts metadata. |
registry_data | object | Yes | Raw registry payload (vendor-specific). |
user_provided_data | object | Yes | Snapshot of user-edited fields. |
confirmed_by_user_at | string (ISO 8601) | Yes | Timestamp the user confirmed the extracted data. |
last_console_edit_at | string (ISO 8601) | Yes | Timestamp of the last console edit. |
is_editable | boolean | No | true while registry-sourced data can still be edited by the end user. |
KYB document
Returned per node that collects KYB supporting documents. Appears asdocument_verifications[] in GET /v3/session/{sessionId}/decision/ for business sessions — one entry per node_id, with items[] listing each uploaded document. Source: kyb/serializers/kyb.py:1053-1068 (DocumentVerificationV3Serializer); each item follows kyb/serializers/kyb.py:811-851 (KYBDocumentResponseSerializer).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | Aggregate status across this node’s documents: Approved only when every pipeline document is approved; Declined if any is declined; In Review otherwise; Not Finished while pending. See Status enum. | "Approved" |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_kyb_documents" |
items | array of KYB document item objects | No | One entry per uploaded or requested document. | […] |
groups | object | No | Per-document-group counts: { <group_name>: { total, approved, pending, declined, in_review, other, missing } }. | { "incorporation_certificate": { "total": 1, "approved": 1, "pending": 0, "declined": 0, "in_review": 0, "other": 0, "missing": 0 } } |
required_groups | array of strings | No | Document groups required by the workflow configuration. | ["incorporation_certificate", "shareholder_register"] |
warnings | array | No | See Warning object. | [] |
KYB document item object
| Field | Type | Nullable | Description |
|---|---|---|---|
uuid | string (UUID) | No | Internal document identifier. |
document_type | string | Yes | High-level group (incorporation_certificate, shareholder_register, …). |
document_subtype | string | Yes | Provider-specific subtype. |
document_group | string | Yes | Mirror of document_type (alias kept for clarity). |
file_url | string (URL) | Yes | Presigned URL to the cleaned file. |
original_filename | string | Yes | Filename as uploaded. |
file_size | integer | Yes | File size in bytes. |
status | string | No | Per-document status (FeatureStatusChoices). |
created_at | string (ISO 8601) | No | Upload timestamp. |
cross_check_result | object | Yes | Cross-check verdict against registry / other docs. |
document_metadata | object | Yes | Same filtered metadata shape as POA’s document_metadata. |
description | string | Yes | Reviewer- or system-supplied description. |
is_requested | boolean | No | true when the workflow expected this document. |
ocr_data | object | Yes | OCR-extracted fields when available. |
is_console_upload | boolean | No | true when the document was uploaded by a console reviewer (excluded from the aggregate verdict). |
is_confirmed | boolean | No | true when the reviewer has explicitly confirmed the document. |
KYB key person
Returned per Key People node in a KYB workflow. Appears askey_people_checks[] in GET /v3/session/{sessionId}/decision/ for business sessions. Source: kyb/serializers/kyb.py:967-1050 (KeyPeopleCheckV3Serializer).
| Field | Type | Nullable | Description | Example |
|---|---|---|---|---|
status | string | No | See Status enum. | "Approved" |
node_id | string | null | Yes | Workflow node identifier (V3). | "first_key_people" |
registry | object | No | { officers[], beneficial_owners[] } extracted from the registry. Officers follow KYBPersonResponseSerializer (kyb/serializers/kyb.py:533-645); beneficial owners follow KYBBeneficialOwnerResponseSerializer (kyb/serializers/kyb.py:648-788, which adds date_of_birth, country_of_birth, email, company_name, registration_number, entity_type, roles, ownership_min_shares, ownership_max_shares, child_beneficial_owners, effective_ownership_percent). Both include per-party AML + KYC enrichment (aml_status, kyc_status, kyc_session_url, kyc_session_id, verification_workflow_type, verification_workflow_id, verification_workflow_label, verification_workflow_features, didit_internal_id, kyc_document_type, kyc_nationality, kyc_liveness_passed, kyc_verified_at, kyc_aml_categories, kyc_notification_sent_at). | { "officers": [...], "beneficial_owners": [...] } |
submitted | object | No | { parties[] } — entries the business confirmed / submitted via the key-people flow (BusinessParty rows with source=USER). Each party follows BusinessPartySubmissionResponseSerializer (kyb/serializers/party.py:146-194): uuid, entity_type, source, name, first_name, last_name, company_name, registration_number, email, nationality, phone_number, date_of_birth, position, custom_fields, is_active, is_skipped, requires_verification, roles[] ({ role, ownership_percent, voting_percent }), kyc_session_id, kyc_session_status, kyc_session_url, kyb_sub_session_id, kyb_sub_session_status, kyb_sub_session_url, verification_workflow_type, verification_workflow_id, verification_workflow_label, verification_workflow_features, didit_internal_id. | { "parties": [...] } |
ubo_kyc_summary | object | Yes | Counts across active UBOs with linked KYC: { total, approved, flagged, pending }. null when no active UBOs have KYC linked. | { "total": 2, "approved": 2, "flagged": 0, "pending": 0 } |
warnings | array | No | See Warning object. | [] |
Status enum reference
Two related value spaces share thestatus field name. Every per-feature report object on this page uses the feature-level enum; the parent session’s top-level status uses the wider session enum.
Feature-level statuses
Used by every report object’sstatus field. Source: common/config/choices.py:343-348 (FeatureStatusChoices).
| Value | Meaning |
|---|---|
Not Finished | The feature has been provisioned but the user has not completed it yet. |
Approved | The feature passed all checks. |
Declined | The feature failed at least one hard check (see warnings[] with log_type: "error"). |
In Review | The feature triggered soft-fail signals and is awaiting manual review (see warnings[] with log_type: "warning"). |
Resub Requested | A reviewer requested the user resubmit this feature. |
Expired when their step times out (PhoneStatusChoices at common/config/choices.py:377-382, EmailStatusChoices at common/config/choices.py:434-439).
Session-level statuses
Used by the parent session’s top-levelstatus. Source: common/config/choices.py:106-117 (StatusChoices).
| Value | Meaning |
|---|---|
Not Started | The session has been created but the user has not begun it. |
In Progress | The user has started the flow; result not yet finalized. |
Approved | The session passed all checks. |
Declined | The session failed at least one hard check. |
In Review | The session is awaiting manual review. |
Expired | The session expired before completion. |
Abandoned | The user left the flow without completing it. |
Kyc Expired | The KYC’s validity window elapsed (used in re-verification flows). |
Resubmitted | The user resubmitted after a prior decline; this session is superseded by a newer one. |
Awaiting User | The system is waiting on a user-side action (e.g. OTP entry). |