Blog › How to check if a company is sanctioned, with an API
How to check if a company is sanctioned, with an API
Bosco Labs ·
Check the name against the official lists that apply to you, then have a person look at every hit. For most businesses trading in Europe or with the US, that means OFAC's SDN list, the UK Sanctions List, the EU's consolidated financial sanctions list and the UN Security Council list. All of them are free. Most of the work goes into matching names well and knowing what a "no match" actually covers.
Where the official lists are
OFAC publishes the SDN list and its non-SDN lists through the Sanctions List Service. The full SDN file is at https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.XML. No key needed, and it changes most weekdays.
The UN publishes its consolidated list as XML at https://scsanctions.un.org/resources/xml/en/consolidated.xml.
The UK changed things this year. Since 28 January 2026 the UK Sanctions List from the FCDO is the only source for UK designations, and OFSI's old consolidated list is frozen. If your code still downloads the OFSI file, it's been reading a list that stopped updating. The new formats also use a "Unique ID" where the old one used the OFSI Group ID, so any matching or deduplication keyed on Group ID needs changing. The FCDO publishes a format guide that maps old fields to new ones.
The EU list is the awkward one. The Commission's Financial Sanctions Files are free, but you need an EU Login account to get a download URL with a token in it.
The US also has the Consolidated Screening List from the International Trade Administration. It adds the Commerce Entity List and other export lists to the OFAC data. If you ship goods, you'll want that one too.
Matching is where it goes wrong
Company names come with legal forms that differ by country: Ltd, LLC, GmbH, PJSC, OOO. Russian and Chinese names are transliterated in more than one way. Listings carry aliases, and the name your counterparty uses might only appear as an alias. Word order varies. A plain string comparison misses most of this, and a loose fuzzy match buries you in namesakes.
So you end up with a similarity score and a threshold. Set it high and you miss spelling variants. Set it low and someone spends the afternoon clearing false positives. Whatever you pick, a hit is a candidate. Before you act on it, compare what else the listing says: country, registration number, LEI, addresses. Many listings carry identifiers, and a matching registration number settles it much faster than a matching name.
The bigger gap is ownership. Under OFAC's 50 percent rule, a company owned 50 percent or more by one or more blocked persons is itself blocked, even if it's not on any list. The EU and UK apply their own ownership and control tests. A name screen will never find those companies. If that risk applies to you, you need ownership data, and that's a different product.
One call from Python
If you'd rather not maintain the downloads and the matcher, our sanctions screening API checks names against all six lists we carry (OFAC SDN, OFAC non-SDN, the US Consolidated Screening List, UK, EU and UN) in one request. You can see what it would run without a key by asking the free planner:
curl -s -X POST https://api.boscolabs.dev/v1/plan \
-H 'Content-Type: application/json' \
-d '{"question": "Is Sovcomflot on any sanctions list?"}'
That returns the exact call, its input and its maximum price. If part of the question is outside what we have, not_covered says which part and why. To run it, you need a key ($5 free credit, no card):
import os
import httpx
r = httpx.post(
"https://api.boscolabs.dev/v1/sanctions-screening",
headers={"Authorization": f"Bearer {os.environ['BOSCO_API_KEY']}"},
json={
"names": ["Sovcomflot", "Novo Nordisk A/S"],
"entityType": "organization",
},
timeout=60,
)
r.raise_for_status()
for row in r.json()["rows"]:
print(row["query"], "match" if row["match_found"] else "no match", row["best_score"])
print(" ", row["summary"])
if not row["complete"]:
print(" NOT CHECKED:", row["lists_not_checked"])
for m in row["matches"]:
print(" ", m["list_name"], "|", m["listed_name"], "|", m["score"], "|", m["source_url"])
A few fields are worth knowing about. summary is one sentence you can show a reviewer or pass to an agent. complete is false when one of the lists couldn't be loaded, and then a "no match" only covers the lists that were checked. lists_checked gives each list's own publish date, which is what you'd cite in an audit note. The default threshold is 85 out of 100, and you can change it with minScore.
It costs $0.01 per name, match or not. Wallet addresses work too: pass them in addresses and they're matched exactly against the addresses OFAC lists.
Screen the people too
Screening only the company name misses a lot. A company that isn't listed can have a listed director or owner. To catch that, you need the officers and owners from the company register, and then you screen each of them.
That's what our counterparty-check adds. Give it a company number and it pulls the officers and people with significant control from the register, then screens the company and each person in the same call:
curl https://api.boscolabs.dev/v1/counterparty-check \
-H "Authorization: Bearer $BOSCO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "00445790", "country": "GB"}'
Look at the sanctions_entity and sanctions_people checks in the result. People are screened where the register publishes their names: the UK, Norway and France. Poland lists officers too, but masks the names. Everywhere else sanctions_people comes back unverified, and the detail says why. Please don't read unverified as clear. It costs $0.05 per company and also covers register status and insolvency.
In our own benchmark against a model doing web search, sanctions was where the difference showed up. The write-up has the per-company results and the cases where we got it wrong.
What a sanctions check doesn't cover
Name screening against official lists isn't the same as a compliance program. It doesn't cover politically exposed persons or adverse media. It won't find companies caught only by ownership rules. It doesn't cover national lists from other countries. And neither a match nor a no-match is a legal determination. Every result from us carries a notice saying so, and a link to the official entry so the person reviewing it can check the source.
If you need PEPs and adverse media, that's a job for a dedicated screening vendor. If what you need is a quick, sourced answer to "is this name on an official list right now", an API call is a reasonable way to get it.
Bosco Labs makes the sanctions screening API and counterparty-check.
Bosco Labs: official-source data for AI agents, as an HTTP API, MCP server and Apify Actors. API docs.