Denied-Party Screener
Screens importer, consignee, and supplier against the US government denied-party lists.
Deterministic service (not an LLM). Fuzzy-matches every party on an entry against US sanctions and watch lists. Auditable, reproducible, defensible.
What it does
Takes the supplier, importer, and consignee names off an entry and fuzzy-matches them against 31,400+ entity records from OpenSanctions us_trade_csl — the consolidated US trade screening list. Returns a band (block / review / watch / clear) per party with the matched entity, source list, and similarity score.
Why no LLM here: a denied-party hit must be reproducible across runs, must be cite-able in a CBP audit, and must never hallucinate. A pg_trgm similarity score with a documented cutoff is defensible; a model's "I think this looks like Hoshine" is not.
Inputs
{
parties: {
supplier?: { name: string; country?: string };
importer?: { name: string; country?: string };
consignee?: { name: string; country?: string };
};
origin?: string; // for UFLPA-sensitive geographic flags
htsChapter?: string; // for UFLPA-sensitive chapter flags (52, 54, 55, 61, 62, 64)
}
Outputs
{
band: 'block' | 'review' | 'watch' | 'clear',
blocking: boolean, // true if any party is in `block` band
hits: [
{
party: 'supplier',
partyName: 'Xinjiang Apparel Mfg Co.',
matched: 'XINJIANG APPAREL MFG. COMPANY LTD',
score: 1.0,
list: 'UFLPA', // 'OFAC_SDN' | 'BIS_ENTITY' | 'UFLPA' | 'BIS_DENIED' | 'BIS_UNVERIFIED' | 'STATE_NONPROL'
band: 'block',
sourceUrl: 'https://www.dhs.gov/uflpa-entity-list',
},
],
topHit: { … }, // highest-score hit across all parties
geographicFlags: [ // non-entity-match flags
{ type: 'UFLPA_chapter_sensitive', detail: 'China-origin cotton (chapter 52)' },
],
}
When it runs
- Every entry, automatically — in the
draft → ai_reviewtransition. The result is stored and surfaced as a header banner in the drawer. - Every Simulation — runs on the supplier name pulled from the PO so the user sees the band before any commitment.
- On-demand from the supplier passport — broker clicks "Re-screen" to pick up newly-added entries to the sanctions lists.
- On data refresh — when the screening lists refresh from OpenSanctions, all open entries are re-screened.
Dependencies
- OpenSanctions
us_trade_csl— 31.4K entities, consolidated from:- OFAC SDN (Treasury)
- BIS Entity List (Commerce)
- DHS UFLPA Entity List
- BIS Denied Persons List
- BIS Unverified List
- State Department non-proliferation lists
- Postgres with
pg_trgmextension for trigram similarity. - Corporate-suffix normalization — strips "Co., Ltd.", "Inc.", "GmbH", "Pvt.", "JSC", etc. before scoring, so "Hoshine Silicon Industry Co., Ltd." and "Hoshine Silicon" both resolve at 1.0.
What success looks like
Screens every party on the entry — importer, consignee, and supplier — against the full set of US denied-party lists in under a second, tuned so that a true match is never missed (recall is the priority; a broker would rather clear a near-miss than let a real hit through). The lists are refreshed daily, so screening always runs against the current denied-party universe.
The bands themselves are chosen to be CBP-defensible:
| Band | Score cutoff | What it means |
|---|---|---|
block | ≥ 0.55 | High-confidence match. Broker must clear before transmit. |
review | ≥ 0.40 | Likely match — surface to broker. |
watch | ≥ 0.35 | Possible alias — investigate. |
clear | < 0.35 | No actionable match. |
What it does NOT do
- Does not make the screening decision. It surfaces hits with evidence; the broker decides whether to dismiss (with a reason code) or hold the entry.
- Does not screen against EU, UK, or UN lists today. US-only — adding EU
consolidated_euis on the Q4 roadmap. - Does not rank or interpret matches with an LLM. Future LLM re-ranking pass to distinguish a true match from a generic word collision is on the roadmap (see AI architecture) but is NOT in production yet — the deterministic scoring is.
- Does not check DOB, address, or program-specific eligibility (e.g. USMCA certificate validity). Out of scope.
- Does not monitor for changes after the entry clears — that's a separate audit concern.
Roadmap
- Q3 2026 — LLM re-ranking pass on
reviewandwatchband hits to separate true alias matches from generic word collisions. The deterministic score stays as the primary signal; the LLM is a secondary confidence input only. - Q3 2026 — Add EU consolidated list + UK FCDO list for customers doing transshipment.
- Q4 2026 — Beneficial-ownership chain screening (today we screen only the parties named on the entry; this would walk the corporate graph one level).
- Q4 2026 — Address-based screening (some Entity List records have address-only entries; we'd parse the shipper address off the BoL).
Put your own book of entries through Commers.