Skip to content

Risk · · 2 min read

Sanctions screening: lists, fuzzy names and false positives

Where the OFAC and UN lists come from, how names are normalised and scored, why a hit never declines a session on its own, and what screening does not cover.

Sanctions screening checks whether the person you are about to onboard is named on a sanctions list. The lists are public; the difficulty is names. The same person appears with aliases, transliterations, reordered names and missing dates of birth, and ordinary customers share names with listed people. This guide explains how KYCVerify handles that.

The two lists

ListPublisherFormatWhat KYCVerify reads
Specially Designated Nationals (SDN)US Treasury, OFACsdn.csv plus alt.csvNames, aliases, programmes, dates of birth and nationalities from the remarks
Consolidated listUN Security CouncilXMLIndividuals and entities, every alias quality, original-script names, date ranges, nationalities

The server downloads both from their official URLs, following the redirects to the publishers' signed storage, parses them and builds an in-memory index. It checks every 6 hours and re-downloads a list older than 7 days; an admin can refresh at any time. Each list's fetch time, size and checksum are recorded and returned with every screening, so a decision says exactly which version of which list it used.

Normalising names

  • Lower-case and strip diacritics (Unicode NFKD), so José Müller and jose muller compare equal.
  • Drop punctuation and honorifics such as mr and dr.
  • Keep particles as their own tokens (al-Rashid becomes al rashid), so they neither vanish nor glue to the surname.
  • Collapse whitespace. OFAC's SURNAME, Given order is rewritten as Given SURNAME for individuals.

Scoring

Names are compared as sets of tokens with Jaro-Winkler similarity, which is forgiving of small spelling differences and insensitive to order: Hussein Saddam scores like Saddam Hussein. Every alias is scored, and the best one is reported as matched_name.

  • Below 0.82: not reported
  • 0.82 to 0.90: potential_match (warn), session to review
  • 0.90 and above: potential_match (high), session to review

Name score

token-set Jaro-Winkler, order-insensitive, diacritics and honorifics removed

Date of birth

match +0.05, mismatch −0.10, unknown leaves the score as is

Review, not decline

a hit sends the AML check to review; a session still declines if another check fails with auto_decline on

Default AML thresholds, and the date-of-birth adjustment.

When a date of birth is known it adjusts the score: a match with a listed date, year or range adds 0.05, a clear mismatch subtracts 0.10, and an entry with no dates is left alone. UN entries recorded as approximate ("circa 1960") match within a year.

Why a hit never declines on its own

A name score cannot tell a listed person from a namesake. Declining automatically would turn away ordinary customers; approving would be worse. So in KYCVerify a potential match never fails the AML check by itself: the check goes to review with the matched entry, its list, programmes, dates of birth and source link. If nothing else failed, the session goes to review and a reviewer decides. If another check failed and auto_decline is on, the session is declined and the hit is recorded in the decision. The match's severity (warn from 0.82, high from 0.90) helps them prioritise.

What it does not cover

  • Other sanctions regimes, such as the EU, UK or Indian lists, unless you add them.
  • Politically exposed persons (PEP) and adverse media.
  • Ongoing monitoring: a person is screened when their session is submitted, not again when a list changes.
  • Entity and vessel screening for business verification.

If your obligations include any of these, combine KYCVerify with a provider that covers them, or treat KYCVerify's screening as one control among several. Try a name with POST /v1/checks/aml; the response lists the exact list versions it was screened against.

See it working on your own data.

Every guide describes code you can run in the sandbox today.