Read this before the code: SanctionRail is one input to your own OFAC compliance program — not a substitute for it, not a sole or final screening control, and not legal or compliance advice. Fuzzy matching produces both false positives and false negatives. You independently review every result and make all blocking, rejection, and reporting determinations. Hudson Enterprises LLC is a software publisher, not a regulated screening provider, law firm, or compliance advisor. Use is governed by the SanctionRail Terms of Service.
U.S. businesses handling regulated transactions are required to screen counterparties against the OFAC Specially Designated Nationals (SDN) list. If a transaction involves a listed party, you're required to block it and report it to Treasury.
The tooling gap is real. OFAC.gov has a search box — browser only, no API, no fuzzy matching. If the name is transliterated differently or the parts are reordered, an exact-string search misses it. Enterprise tools like LexisNexis WorldCompliance and ComplyAdvantage start at $1,000+/month on annual contracts. There's nothing useful in between for a team that needs a screening signal without a six-figure budget.
This tutorial walks through calling SanctionRail — a REST API that does fuzzy name matching against the OFAC SDN and consolidated sanctions lists. Free tier: 1,500 calls/month, no credit card. I built it; I'll be upfront about that throughout.
There's also a free web checker — no account required, type a name and see whether it matches. Good for a manual spot-check before you write any code.
Before you integrate: what this is and isn't
This needs to be said plainly before the code.
What SanctionRail screens against: U.S. Treasury OFAC Specially Designated Nationals (SDN) list and the OFAC consolidated (non-SDN) sanctions lists, sourced from treasury.gov and refreshed daily. Approximately 18,959 records across individuals, entities, vessels, and aircraft, plus their indexed aliases and AKAs (total_records_searched in every response tells you the exact count at query time).
What it does NOT screen against: EU, UN, UK (HM Treasury / OFSI), Canadian (OSFI), or any other non-U.S. sanctions regime. No PEP lists. No adverse-media. If your compliance program requires multi-regime screening, this is not the right tool.
What fuzzy matching means in practice: the API catches transliteration variants, reordered name parts, and partial matches that exact-string search misses. It also means false positives (a legitimate customer whose name resembles a listed party) and false negatives (a listed party whose name is transliterated differently than the indexed alias). You review every match result. You make all blocking and reporting decisions. The API does not make compliance determinations for you.
Step 1 — Set up
A free RapidAPI account → subscribe to SanctionRail on the Free tier → copy your X-RapidAPI-Key.
export RAPIDAPI_KEY="your_key_here"
Python 3.8+ with requests is all you need for the examples below.
Step 2 — The 3-line version
import requests
r = requests.post(
"https://sanctionrail.p.rapidapi.com/screen",
json={"name": "Vladimir Putin", "threshold": 0.85, "limit": 5},
headers={"X-RapidAPI-Key": "YOUR_KEY", "X-RapidAPI-Host": "sanctionrail.p.rapidapi.com"},
)
print(r.json())
That's the core call. One endpoint, a ranked list of matches with confidence scores.
Step 3 — Read the response
{
"query": "Vladimir Putin",
"threshold": 0.85,
"list_version": "05/11/2026",
"list_loaded_at": "2026-05-14T22:52:21Z",
"total_records_searched": 18959,
"match_count": 1,
"matches": [
{
"sdn_id": 35096,
"name": "PUTIN, Vladimir Vladimirovich",
"sdn_type": "Individual",
"score": 1.0,
"matched_via": "primary",
"matched_text": "PUTIN, Vladimir Vladimirovich",
"program": ["RUSSIA-EO14024"],
"remarks": null
}
]
}
Fields worth noting:
-
list_versionandlist_loaded_at— the age of the data at query time. Check this against the current OFAC publication date on treasury.gov for high-stakes transactions. -
score— confidence of the match (0–1). Not a compliance determination. -
matched_via— whether the match came from the primary name or an indexed alias. -
program— the sanctions program(s) the record is listed under (e.g.RUSSIA-EO14024,SDGT,IRAN).
Step 4 — Understand the parameters
POST /screen accepts:
| Param | Type | Default | What it does |
|---|---|---|---|
name |
string | — | Required. The name to screen (2–200 chars) |
threshold |
float | 0.85 | Minimum confidence score to return a match (0–1) |
sdn_type |
string | Any |
Scope to Individual, Entity, Vessel, Aircraft, or Any
|
include_aliases |
bool | true |
Match against indexed aliases and AKAs |
limit |
int | 20 | Max matches returned (1–100). Must be ≥ 1. |
The threshold parameter is the most operationally significant decision you'll make. 0.85 is the default — a reasonable starting point. Drop it toward 0.70 for higher recall and more false positives to review. Raise it toward 0.95 to cut noise, accepting higher false-negative risk. What the right value is for your program depends on your risk tolerance and review capacity — that's a judgment call for your compliance team, not something this documentation can prescribe.
Step 5 — Screen a batch of names
import os
import requests
RAPIDAPI_KEY = os.environ["RAPIDAPI_KEY"]
HEADERS = {
"X-RapidAPI-Key": RAPIDAPI_KEY,
"X-RapidAPI-Host": "sanctionrail.p.rapidapi.com",
}
def screen_name(name, threshold=0.85, sdn_type="Any"):
r = requests.post(
"https://sanctionrail.p.rapidapi.com/screen",
json={
"name": name,
"threshold": threshold,
"sdn_type": sdn_type,
"include_aliases": True,
"limit": 5,
},
headers=HEADERS,
timeout=15,
)
r.raise_for_status()
return r.json()
names_to_screen = [
"Acme Trading Co",
"Kim Jong Un",
"Jane Smith",
]
for name in names_to_screen:
result = screen_name(name)
match_count = result["match_count"]
if match_count > 0:
top = result["matches"][0]
print(f"{name}: {match_count} match(es) — top score {top['score']:.2f} ({top['name']})")
print(f" → REQUIRES REVIEW — do not proceed without manual verification")
else:
print(f"{name}: no matches above threshold {result['threshold']}")
print(f" → No match found; your own compliance process determines next steps")
A match does not mean block. No match does not mean clear. Those determinations belong to your compliance program and your legal or compliance advisors. The API surfaces whether a name resembles an OFAC-listed party; what you do with that signal is yours.
Step 6 — Look up a full entity record
When a match returns an sdn_id, pull the full record — aliases, addresses, citizenships, dates of birth, ID documents, and sanctions programs:
sdn_id = 35096 # from the match result
r = requests.get(
f"https://sanctionrail.p.rapidapi.com/entity/{sdn_id}",
headers=HEADERS,
timeout=15,
)
entity = r.json()
print(entity)
This is the record as published on the OFAC list. If you're doing manual review on a positive match, start here.
Step 7 — Check list freshness
r = requests.get(
"https://sanctionrail.p.rapidapi.com/list-status",
headers=HEADERS,
timeout=15,
)
status = r.json()
print(f"List version: {status['list_version']}")
print(f"Loaded at: {status['list_loaded_at']}")
print(f"Record count: {status['record_count']}")
The list refreshes daily from treasury.gov. Because the refresh depends on Treasury's own publication timing, newly-designated parties may not appear immediately. For high-stakes transactions, cross-reference list_version against the current OFAC publication date at sanctions.ofac.treas.gov.
What this is not
- Not a compliance program. SanctionRail is one input to your own OFAC compliance program — not a substitute for it and not a final screening control. Your program must include review procedures, documentation, and blocking/reporting determinations that no API can make for you.
- Not multi-regime. U.S. OFAC SDN and consolidated lists only. EU, UN, UK (OFSI), and other regimes are out of scope.
- Not PEP or adverse-media. No politically-exposed-person lists, no adverse-media screening.
- Not legal or compliance advice. If you're building OFAC compliance into a regulated product, work with a qualified attorney or compliance professional.
Pricing
| Tier | Price | Calls/month |
|---|---|---|
| BASIC | $0 | 1,500 |
| PRO | $9/mo | 10,000 |
| ULTRA | $49/mo | 100,000 |
| MEGA | $199/mo | 1,000,000 |
No credit card on the free tier. Subscribe at the RapidAPI listing. Every call needs X-RapidAPI-Key and X-RapidAPI-Host: sanctionrail.p.rapidapi.com — that's the full auth story.
Enterprise tools (LexisNexis WorldCompliance, ComplyAdvantage, Refinitiv World-Check) cover multiple global regimes + PEP + adverse-media at $1,000+/month on annual contracts. SanctionRail is narrower — U.S. OFAC only — at a fraction of the cost. If you need multi-regime coverage, budget for the enterprise tier; if U.S. OFAC is the specific gap, this fills it.
Questions or issues
support@hudsonenterprisesllc.com — same-business-day response, async only. Include your RapidAPI key prefix (first 8 chars), the endpoint, and the request body.
For list data questions — a suspected outdated record, an incorrect alias — we can point you to the originating OFAC record on treasury.gov so you can verify against the source.
Built by Hudson Enterprises LLC. Use governed by the SanctionRail Terms of Service.
Top comments (0)