Screening with the OFAC API: a 20-line integration
To screen names against OFAC in code, download OFAC's list files and match against them; do not script the Sanctions List Search website. OFAC says that tool is for individual users, should not be driven by automated systems, and points developers to its XML and CSV files instead (OFAC FAQ 287). OFAC's Sanctions List Service delivers those files and, per OFAC, supports retrieval through an API (OFAC, Other OFAC Sanctions Lists). The Node.js script below fetches SDN.CSV, checks a name, and records the list version it used.
The script
// screen.mjs: node screen.mjs "Banco Nacional de Cuba" (Node 18 or later)
import { createHash } from "node:crypto";
const URL = "https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.CSV";
const res = await fetch(URL);
if (!res.ok) throw new Error("SDN.CSV unavailable (HTTP " + res.status + "). This is not a clear result.");
const body = await res.text();
const norm = (s) => s.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase()
.replace(/[^a-z0-9 ]/g, " ").split(/\s+/).filter(Boolean).sort().join(" ");
// No header row. Field 1 is the entry number, 2 the name, 3 the type, 4 the program.
const rows = body.split(/\r?\n/).map((line) => (line.match(/("([^"]|"")*"|[^,]*)(,|$)/g) ?? [])
.map((f) => f.replace(/,$/, "").replace(/^"|"$/g, "")));
const query = norm(process.argv[2] ?? "");
const hits = rows.filter((r) => r[1] && norm(r[1]) === query);
console.log({
checked: process.argv[2], checkedAt: new Date().toISOString(),
listLastModified: res.headers.get("last-modified"),
listSha256: createHash("sha256").update(body).digest("hex"),
exactNameMatches: hits.map((r) => ({ entNum: r[0], name: r[1], type: r[2], program: r[3] })),
});Run on 7 October 2026, it printed (whitespace condensed):
{
checked: 'Banco Nacional de Cuba',
checkedAt: '2026-10-07T15:54:00.696Z',
listLastModified: 'Mon, 05 Oct 2026 19:35:12 GMT',
listSha256: '880ce3f23ac99e766f90a93b00b939ca2ff80c4d6aca6380d6a8c58825fea9e0',
exactNameMatches: [
{ entNum: '306', name: 'BANCO NACIONAL DE CUBA', type: '-0- ', program: 'CUBA' }
]
}The listLastModified and listSha256 fields are the point: every check records exactly which publication of the list it ran against. Store them next to the result and the check proves itself later.
What the file looks like
The URL above is the Sanctions List Service export we fetch from. In the copy we downloaded on 7 October 2026, SDN.CSV had no header row, and empty fields held the placeholder -0-: the type field reads individual for people and -0- for companies such as Banco Nacional de Cuba. OFAC publishes the SDN list as CSV for spreadsheets and databases (OFAC FAQ 80) and describes the layouts in its data specification, linked from OFAC FAQ 83.
What this script does not do
It is a starting point, not a screening program:
- Exact names only. It normalises case, accents, punctuation and word order, then requires every word to match. Real screening needs fuzzy matching; OFAC's own search tool scores names with Jaro-Winkler and Soundex (OFAC FAQ 249), plus a further algorithm added in its 2021 upgrade (OFAC FAQ 892).
- Primary names only. Aliases are in a separate file, ALT.CSV. Many listed parties trade under an alias.
- SDN only. OFAC's non-SDN lists are published separately as the Consolidated list (Sanctions List Service).
- No ownership. Entities 50 percent or more owned by blocked persons are blocked without being listed (OFAC FAQ 91).
- A hit is a candidate. OFAC's steps for deciding whether it is valid are in FAQ 5.
Keeping it current
OFAC cannot tell you how often to download; many institutions run a scheduled download and set the schedule from their own risk assessment (OFAC FAQ 88). The full files are complete each time, so you can overwrite the old copy (OFAC FAQ 89). OFAC also publishes a delta file of changes through the Sanctions List Service (OFAC FAQ 90).
One rule worth copying from the script: if the download fails, the answer is "list unavailable", never "no match". A failed fetch that reads as a clear result is the worst bug a screening integration can have.
Try a name first
Run a free OFAC check to see how a name scores against the SDN and Consolidated lists, aliases included, before you write your own matcher. This is screening data, not legal advice.