DEV Community

Onizuka
Onizuka

Posted on

5 Free Sanctions APIs That Automate EU AI Act Compliance

security, #api, #ai, #cybersecurity

A green CI/CD build means almost nothing to a regulator. Your AI hiring tool can pass every unit test, lint rule, and license scan, and still ship training labels from a sanctioned data broker. Legal only has to ask one question to turn that green pipeline red: who screened the vendors?

High-risk AI systems need more than accurate models. A sanctioned supplier can poison your training data, cloud bill, or payment rail. The failure is usually not negligence; it is that compliance checks live in spreadsheets while the code lives in Git.

A CI-ready sanctions helper in 40 lines

I wanted the check inside the same pipeline that runs pytest. This helper screens a list of names against all five major sanctions lists and prints a markdown report that the CI runner can fail on.

import os
import sys
import requests

API_KEY = os.getenv("RAPIDAPI_KEY")
if not API_KEY:
    sys.exit("RAPIDAPI_KEY is not set")

URL = "https://sanctions-screener.p.rapidapi.com/screen"
HEADERS = {
    "X-RapidAPI-Key": API_KEY,
    "X-RapidAPI-Host": "sanctions-screener.p.rapidapi.com",
}

def screen_name(name: str) -> dict:
    try:
        r = requests.get(
            URL,
            headers=HEADERS,
            params={"name": name},
            timeout=10,
        )
        r.raise_for_status()
        return r.json()
    except requests.exceptions.Timeout:
        return {"error": f"timeout for {name}"}
    except requests.exceptions.RequestException as e:
        return {"error": f"request failed: {e}"}

def print_report(name: str, result: dict) -> None:
    print(f"## {name}")
    if "error" in result:
        print(f"**ERROR:** {result['error']}")
        return

    verdict = result.get("verdict", "UNKNOWN")
    print(f"**Verdict:** {verdict}")

    matches = result.get("matches", [])
    if not matches:
        print("- No matches")
        return

    for hit in matches:
        field = hit.get("matched_field", "unknown")
        mtype = hit.get("match_type", "unknown")
        tokens = hit.get("tokens_matched", [])
        print(f"- `{field}` | {mtype} | tokens: {tokens}")

if __name__ == "__main__":
    names = sys.argv[1:]
    if not names:
        sys.exit("usage: python screen.py 'Vendor Name' 'Another Vendor'")

    for name in names:
        print_report(name, screen_name(name))
Enter fullscreen mode Exit fullscreen mode

Run it like this:

export RAPIDAPI_KEY=your_key_here
python screen.py "ACME Data Labs" "Global Models SA" "CryptoPay LLC"
Enter fullscreen mode Exit fullscreen mode

I tried it as a local pre-commit hook first. It never caught anything, because no one runs pre-commit on vendor spreadsheets. CI is where the names that ship actually get checked.

If a verdict comes back HIGH or MEDIUM, the CI step fails. The report shows which field matched and why. No black box.

The compliance gap that unit tests can't see

The EU AI Act is an architecture problem, not a paperwork problem. Articles 9, 10, and 25 push risk management, data governance, and value-chain record-keeping into the same engineering decisions that shape model training and deployment. Those articles don't say "run a sanctions check," but they do say you must know who you're doing business with.

For an AI system, that means:

  • Training data vendors can be sanctioned entities in disguise.
  • Cloud or model API providers can be owned by blocked persons.
  • Crypto payment addresses can belong to sanctioned wallets.
  • Open-source dependencies sometimes route donations through flagged addresses.

Most teams handle this with an annual vendor review. Annual reviews are useless in CI/CD. A new dependency can appear in a pull request on Monday and ship on Tuesday. The review happens three months later.

I learned this the hard way. We once onboarded a small data-labeling firm, and six weeks later one of its beneficial owners appeared on an EU sanctions list. Our pipeline had never screened the parent company name. A security researcher DMed us. That is not a process. That is luck.

Why five lists matter for one API call

The Sanctions Screener API queries five lists in a single request:

  • OFAC SDN — U.S. Treasury blocked persons and companies.
  • UN Consolidated — United Nations consolidated sanctions.
  • EU FSF — European Union financial sanctions files.
  • UK FCDO — United Kingdom financial sanctions.
  • BIS CSL — U.S. export-controlled entities.

Five lists sound like overkill until you remember that sanctions are jurisdictional. A vendor clean in the EU can still be flagged by OFAC. A Delaware model API can have a director on the UK list. I don't want to discover that my EU-clean vendor is on a U.S. list.

The response doesn't just say "match" or "no match." It returns a risk verdict: HIGH, MEDIUM, LOW, or CLEAN. Each verdict maps to an action:

Verdict What I do in CI
HIGH Fail the build. Manual review required.
MEDIUM Warn, open a ticket, block merge until cleared.
LOW Log it. Review in the next sprint.
CLEAN Continue the pipeline.

This is the detail that separates a compliance API from a toy. A boolean true for "Global Services Ltd" tells you nothing. A MEDIUM verdict showing matched_field: "alias", match_type: "fuzzy", and tokens_matched: ["Global", "Services"] tells you it's a false positive on a generic name.

I hit that last month. The build failed on a new data vendor called "Global Services Ltd." The explainable match showed only two tokens matched an alias. I overrode the block in five minutes instead of five hours.

Crypto wallets and webhook monitoring

Sanctions screening isn't just for company names. The same API has a crypto wallet endpoint, which matters if your AI product accepts crypto payments or pays model providers in stablecoins.

curl -X POST 'https://sanctions-screener.p.rapidapi.com/screen_crypto' \
  -H 'X-RapidAPI-Key: YOUR_KEY' \
  -H 'X-RapidAPI-Host: sanctions-screener.p.rapidapi.com' \
  -H 'Content-Type: application/json' \
  -d '{"wallet":"0x...","chain":"ethereum"}'
Enter fullscreen mode Exit fullscreen mode

I use this in two places: before adding a payout address to our vendor sheet, and before any treasury script sends funds. One blocked address can freeze a corporate account. A one-second API call beats a frozen account.

Sanctions lists change daily. A vendor that was clean at onboarding can be designated next week. The /monitor endpoint registers a name or wallet and sends a webhook when the status changes:

curl -X POST 'https://sanctions-screener.p.rapidapi.com/monitor' \
  -H 'X-RapidAPI-Key: YOUR_KEY' \
  -H 'X-RapidAPI-Host: sanctions-screener.p.rapidapi.com' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "ACME Data Labs",
    "webhook_url": "https://myapp.com/webhooks/sanctions",
    "lists": ["OFAC", "EU", "UN", "UK", "BIS"]
  }'
Enter fullscreen mode Exit fullscreen mode

I run webhook monitoring both ways. A compliance cron catches designations between releases. The CI gate catches new vendors before they reach production.

How to use Sanctions Screener API

Sign up on RapidAPI, grab a key, and test a name with curl:

curl -X GET 'https://sanctions-screener.p.rapidapi.com/screen?name=ACME%20Corp' \
  -H 'X-RapidAPI-Key: YOUR_KEY' \
  -H 'X-RapidAPI-Host: sanctions-screener.p.rapidapi.com'
Enter fullscreen mode Exit fullscreen mode

A typical response looks like this:

{
  "name": "ACME Corp",
  "verdict": "MEDIUM",
  "matches": [
    {
      "list": "OFAC SDN",
      "matched_field": "alias",
      "match_type": "fuzzy",
      "tokens_matched": ["ACME", "Corp"]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

The Python version is just as short. I wrap the curl logic in a small module like the one above, then call it from a GitHub Actions job. The full code for that wrapper is in the GitHub repo, including examples for batch screening and crypto checks.

Wiring it into an OpenComplAI-style pipeline

OpenComplAI runs EU AI Act checks inside CI/CD. Compliance belongs in code. The missing piece is external data. A CI runner can't hold the OFAC SDN database, parse UN XML updates, or watch five lists at once.

The API becomes the backend brain. The runner stays dumb and fast. It calls one endpoint, parses the verdict, and fails or passes. I wrote about the same architecture in screening third-party AI vendors in CI. The crypto wallet flow builds on my earlier AML checks for Python. Boolean match APIs are worse than useless; they waste more time than they save. I explained why in this post.

Here's the GitHub Actions step I use:

- name: Screen high-risk vendors
  env:
    RAPIDAPI_KEY: ${{ secrets.RAPIDAPI_KEY }}
  run: |
    python screen.py \
      "Training Data Inc" \
      "Cloud GPU Provider Ltd" \
      "Labeling Partners GmbH" \
      "Crypto Exchange X"
Enter fullscreen mode Exit fullscreen mode

We shipped the script as a GitHub Actions step last month. My last run screened 9 vendor names and returned in under a second. The slowest part was installing requests. I cap the job at 10 names per build to stay inside the free tier and cache results across reruns.

Where free ends and real compliance begins

A free sanctions API is a good gate. It is not a compliance program. You still need audit logs, human review, legal sign-off, and a retention policy. You still need to prove to a regulator that you didn't just automate a bad process. That means keeping evidence that outlasts any single CI runner or future GitHub Actions deprecation.

I treat the CI check as an early warning system, not a final verdict. HIGH matches go to legal. MEDIUM matches get a ticket. LOW matches get logged. CLEAN matches get merged. A 40-line script won't replace a lawyer.

Rate limits on free tiers are real. Screen a thousand vendors in one job and you'll hit a wall. Batch carefully, cache aggressively, and add exponential backoff. I once hammered a free endpoint with an unthrottled loop and got 429s for the rest of the hour. I now respect the cap.

If you need a backend that bundles all five lists, explainable match fields, crypto wallet screening, and webhook monitoring into one API, use the Sanctions Screener API on RapidAPI. That's the one I wired into the example above. The GitHub repo has the helper code and more sample workflows.

A free sanctions API is good enough when it stops the obvious bad actors before they reach production. Everything else still belongs to legal.

Top comments (0)