Browse help guides
← Help

KYC

KYC data reference

For implementers and auditors: files, event types and payload keys, the Sumsub calls, the status mapping and the failure table.

Where it lives

PathContainsEdit by hand?
subjects/SUB-….mdThe user; kycStatus, currentApplicantId, kycOverridden, verifiedAt are copies written by the app.Body only, never the KYC keys
kyc/events.jsonlApplicant and provider events, append-only, hash-chained.Never
config/kyc.yamlDefault method and the Sumsub connection (no secrets).No — use Settings
audit/events.jsonlOne PII-free line per KYC event.Never
OS keychain (userData/secrets.bin)Encrypted Sumsub token and secret, outside the vault.No

Event types

TypeWhen
provider.connectedSumsub keys tested and saved.
provider.testedTest pressed in Settings.
provider.disabledDisconnect.
provider.fetch_requestedFetch status pressed.
applicant.createdA KYC record starts (Sumsub or manual).
applicant.link_issuedA hosted Sumsub link is minted.
applicant.fetchedSumsub's current answer, recorded on every fetch.
applicant.status_changedThe status actually changed (fetch, webhook or manual).
applicant.manual_overrideCompliance or owner override.
Each line of kyc/events.jsonl
seq            1, 2, 3 …
id             KEV-<ulid>
type           one of the event types
at             ISO-8601 with offset
actor          who wrote it (the app)
actorRole      owner | compliance | operator
subjectId      SUB-<ulid> or null
applicantId    APL-<ulid> or null
payload        keys below
prevHash       sha256 of the previous line
hash           sha256 of this line without hash

Payload keys

Manual KYC
applicant.created
  provider                 manual
  provider_connection_id   null
  provider_ref             "manual:{applicant_id}"
  flow                     manual
  level_name               "manual"

applicant.status_changed
  source                   manual
  kyc_status               pending | need_docs | approved | rejected
  aml_status               clear | hit | review | unknown
  doc_type, doc_country, doc_valid_until, name_on_doc, dob_on_doc
Sumsub
applicant.created
  provider                 sumsub
  provider_connection_id   <active connection>
  provider_ref             <Sumsub applicantId>
  flow                     link
  level_name               <connection level name>

applicant.link_issued
  link_url
  link_expires_at
  token_ttl_sec            1800
Override and connection
applicant.manual_override
  from_kyc_status
  to_kyc_status            approved
  reason_code              staff_review | cba_instruction | data_fix | other
  reason_text              required

provider.connected
  provider                 sumsub
  mode                     byok
  scopes                   applicant_create, applicant_read
  secret_ref               pointer only, never the key
  environment, level_name

Sumsub calls

Base https://api.sumsub.com — sandbox tokens only work against sandbox data
POST /resources/applicants?levelName=
POST /resources/sdkIntegrations/levels/-/websdkLink
GET  /resources/applicants/{id}/one
GET  /resources/applicants/-;externalUserId={id}/one

Each request is signed: HMAC-SHA256 over timestamp + method + path with query + body, hex, sent as X-App-Access-Sig with X-App-Token and X-App-Access-Ts. The user's id (SUB-…) is the externalUserId. Not in this version: document upload, re-check requests, share tokens, level creation, or an embedded WebSDK.

Status mapping

Sumsub reviewKYC status
initNot started (Link sent while a link is out)
pending / queued / onHoldPending
completed + GREENApproved
completed + RED + RETRYNeeds documents
completed + RED + FINALRejected

Only the adapter reads GREEN or RED. Everything else — the badge, the booking gate, exports — reads the normalized KYC status.

The round trip

sequenceDiagram
  actor Staff
  participant Desk
  participant Sumsub
  actor Client
  Staff->>Desk: Create user
  Desk->>Sumsub: applicants + websdkLink
  Desk-->>Staff: link
  Staff->>Client: send link
  Client->>Sumsub: documents + liveness
  Sumsub-->>Desk: webhook or Fetch
  Desk-->>Staff: badge approved
Create, link, client verification, result.

Rules that always hold

  • The access token used to mint a link is never stored; the link and its expiry are.
  • Document details stay on the KYC record, not in the audit log.
  • AI proposals cannot change KYC; only the app writes KYC events.
  • The booking gate reads the user's KYC status; an override is visible as “approved (overridden)”.
  • Vaults made before this feature are upgraded once on open (format 2), with a backup in .bak/. Posted transactions are never rewritten.

Continue reading

KYC in Open Dram →Where your data lives →Work with an external AI tool →

Something missing or out of date? Send feedback.