# Sanctions Screening API - OpenSanctions PEP, Watchlist Match (`nabeelbaghoor/sanctions-watchlist-screening-api`) Actor

Sanctions, PEP and watchlist screening with the OpenSanctions API: fuzzy match people, companies, vessels and crypto wallets against OFAC, EU, UN, UK and hundreds more lists, PEPs, debarment and crime data, with match scores, topics, programs and full entity records. Bring your own key.

- **URL**: https://apify.com/nabeelbaghoor/sanctions-watchlist-screening-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Developer tools, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 sanctions, pep or watchlist entity record returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Sanctions Screening API - OpenSanctions PEP, Watchlist Match

Screen people, companies, vessels and crypto wallets against global sanctions lists, politically exposed persons (PEPs), debarment, crime and regulatory watchlists with your own OpenSanctions API key, and get one clean, scored dataset row per candidate entity.

Works with the official hosted OpenSanctions API on api.opensanctions.org: the /match entity screening API (fuzzy, cross-script name matching that also weighs birth date, nationality, registration numbers and IMO numbers), the /search text search with facets and filters, and the /entities endpoint for full records with sanction designations, family, associates and ownership links. Paste customer, supplier or counterparty names and get back the match score, sanctioned and PEP flags, risk topics, sanction program IDs, countries, dates of birth, aliases and source lists, ready to download as JSON, CSV or Excel, schedule for re-screening, or feed into KYC, KYB, AML and onboarding workflows. Bring your own API key.

BYOK, route-checked but not live-tested: every path, parameter and enum comes from the OpenSanctions OpenAPI definition (api.opensanctions.org/openapi.json) and documentation, and each route was confirmed with a probe (documented paths answer 401 "Invalid API key" to an invalid key, invented paths 404 "Not Found"), but the actor has not been run against a live OpenSanctions key.

### What it does

- **Entity screening (match)**: scores each name or detailed entity against the OpenSanctions database with the documented /match API and returns ranked candidates with a score from 0 to 1, a match flag at your threshold, and the matched alias. Covers Person, Company, Organization, LegalEntity, Vessel, Airplane, CryptoWallet, Security and PublicBody.
- **Precise screening with details**: add birth dates, nationality, country, jurisdiction, registration, tax, LEI or IMO numbers per entity to cut false positives, and a ref of your own (customer ID) that is copied to every row.
- **Scope and filters**: screen against everything, or just consolidated sanctions, PEPs, crime, debarment, enforcement, regulatory, wanted, maritime, EU, US or securities collections; filter by risk topic (sanction, sanction.linked, role.pep, role.rca, debarment, reg.warn and more), include or exclude source lists such as us_ofac_sdn or eu_fsf, and re-screen only entities changed since a date.
- **Text search**: keyword search with entity type, country, topic, dataset and property filters (such as properties.programId:EU-UKR), paged up to your row limit.
- **Entity details**: the full record for any OpenSanctions entity ID, with nested sanction designations (authority, program), addresses, identification documents, relatives, associates, owners and subsidiaries. Merged IDs are followed to the canonical entity. Free on your OpenSanctions plan.
- **Pay only for results**: screens with no match, unknown IDs and requests the provider refuses are recorded as a free row that says why, never charged.

### How to get an API key

Get a key on the OpenSanctions API page (opensanctions.org/api). Business use runs on prepaid credit bundles; OpenSanctions issues free keys for public-interest work (journalism, civil society advocacy and academic research). Copy the key from your account (opensanctions.org/account), paste it into the API key field, or set the DATA_API_KEY secret. The key is sent only to api.opensanctions.org in the `Authorization: ApiKey ...` header the API requires and is removed from everything the actor logs.

### Input

| Field | Modes | Description |
| --- | --- | --- |
| `mode` | all | `match` (default), `search` or `entity` |
| `names` | match | One name per line, screened as `entityType`, up to 1,000 |
| `entityType` | match | `Person` (default), `Company`, `Organization`, `LegalEntity`, `Vessel`, `Airplane`, `CryptoWallet`, `Security`, `PublicBody` |
| `entities` | match | JSON list of detailed entities: `schema`, FollowTheMoney properties, optional `ref` |
| `threshold` | match | Match score threshold, 0 to 1 (default 0.7) |
| `algorithm` | match | `best` (default), `logic-v2`, `ofac`, `name-based`, `name-qualified`, `logic-v1`, `regression-v1` |
| `resultsPerEntity` | match | Candidates per entity, 1 to 500 (default 5) |
| `onlyMatches` | match | Keep only candidates at or above the threshold (default true) |
| `searchQuery` | search | Keywords, with the documented search syntax |
| `searchSchema` | search | `Thing` (any, default) or one of the entity types |
| `countries` | search | Two letter ISO codes, such as `ru` |
| `filters` | search | `field:value` property filters, such as `properties.programId:EU-UKR` |
| `fuzzy` | search | Allow fuzzy query syntax (default false) |
| `entityIds` | entity | OpenSanctions entity IDs, such as `Q7747` or `NK-...` |
| `nested` | entity | Include linked entities (default true) |
| `dataset` | match, search | Collection scope: `default`, `sanctions`, `peps`, `crime`, `debarment`, `enforcement`, `regulatory`, `wanted`, `maritime`, `eu_sanctions`, `us_sanctions`, `securities`, `special_interest` |
| `topics` | match, search | Risk topics to keep |
| `includeDatasets` / `excludeDatasets` | match, search | Source dataset names, such as `us_ofac_sdn` |
| `changedSince` | match, search | Only entities updated since a date, such as `2026-01-31` |
| `maxResults` | all | Row ceiling for the run (default 100) |
| `requestsPerMinute` | all | Pacing, default 60 |
| `apiKey` | all | Your OpenSanctions API key (or the DATA_API_KEY secret) |

Example: screen three customers against sanctions lists only, with a strict threshold.

```json
{
    "mode": "match",
    "dataset": "sanctions",
    "threshold": 0.8,
    "entities": [
        { "ref": "cust-1001", "schema": "Person", "name": "Arkadii Rotenberg", "birthDate": "1951", "nationality": "ru" },
        { "ref": "cust-1002", "schema": "Company", "name": "Stroygazmontazh", "jurisdiction": "ru" },
        { "ref": "cust-1003", "schema": "Person", "name": "Jane Example", "birthDate": "1984-02-11", "nationality": "gb" }
    ]
}
```

Example: PEP check for a list of names.

```json
{
    "mode": "match",
    "dataset": "peps",
    "entityType": "Person",
    "names": ["Olaf Scholz", "Jane Example"]
}
```

### Example output

An illustrative screening row, shaped like the documented /match response (values are an example, not a guaranteed result). The full OpenSanctions record is kept under `record`; only part of it is shown.

```json
{
    "mode": "match",
    "modeLabel": "Entity screening (match)",
    "recordType": "match",
    "input": "Aleksandr Zacharov",
    "queryRef": "cust-2001",
    "found": true,
    "entityId": "NK-aU5ybkbRFJucf8YMwsJvDw",
    "caption": "Alexander Vyacheslavovich ZAKHAROV",
    "schema": "Person",
    "score": 0.92,
    "isMatch": true,
    "topics": ["sanction", "corp.disqual", "debarment"],
    "sanctioned": true,
    "pep": false,
    "datasets": ["us_ofac_sdn", "eu_fsf", "gb_fcdo_sanctions", "ch_seco_sanctions"],
    "countries": ["ru"],
    "birthDates": ["1965-09-21"],
    "aliases": ["Aleksandr Vyacheslavovich ZAKHAROV", "Zacharov Aleksandr Vjačeslavovič"],
    "positions": ["Owner of LLC CST"],
    "programIds": ["EU-UKR", "US-RUSHAR", "GB-RUS"],
    "sanctionAuthorities": null,
    "identifiers": ["183111242406"],
    "sourceUrls": ["https://sanctionssearch.ofac.treas.gov/Details.aspx?id=45937"],
    "target": true,
    "firstSeen": "2023-07-19T18:02:43",
    "lastSeen": "2026-04-27T06:40:02",
    "lastChange": "2026-04-24T10:57:01",
    "mergedFrom": null,
    "nameMatch": "Zacharov Aleksandr Vjačeslavovič",
    "profileUrl": "https://www.opensanctions.org/entities/NK-aU5ybkbRFJucf8YMwsJvDw/",
    "record": { "id": "NK-aU5ybkbRFJucf8YMwsJvDw", "schema": "Person", "score": 0.92, "match": true, "explanations": { "name_match": { "score": 0.92 } } },
    "retrievedAt": "2026-10-19T09:00:00.000Z",
    "note": null
}
```

### FAQ

#### What is OpenSanctions?

OpenSanctions (OpenSanctions Datenbanken GmbH, Berlin) consolidates international sanctions lists (OFAC SDN, EU Financial Sanctions Files, UN Security Council, UK HM Treasury and FCDO, Swiss SECO and many more), a global dataset of politically exposed persons and their relatives and close associates, debarment and procurement exclusion lists, wanted and criminal lists, and regulatory warnings into one de-duplicated entity graph. Key sanctions lists are fetched at least four times a day under its API terms.

#### Do I need my own OpenSanctions API key?

Yes. This is a bring-your-own-key actor: it calls OpenSanctions with your key, under your account and the OpenSanctions API terms. A missing, rejected or out-of-credit key ends the run cleanly with a status message that explains what to change, and nothing is charged.

#### How much does OpenSanctions charge, and what does this actor cost?

OpenSanctions bills prepaid credits: one credit per screened entity on /match, one per /search request (page), and /entities lookups are free; only successful (HTTP 200) answers count. This actor charges 0.01 USD per entity record it returns, on top of that. Screens with no match, unknown IDs and refused requests are never charged.

#### How accurate is the matching, and how do I reduce false positives?

The /match API scores candidates with the logic-v2 algorithm by default, which compares names across scripts and transliterations and then weighs supporting or contradicting facts. Add a birth date, nationality, country or a registration, tax, LEI or IMO number to each entity, use the most specific entity type, and raise the threshold from 0.7 to 0.8 or 0.85 for low tolerance screening. Every row keeps the score and the full explanation under record.

#### Can I use it for continuous monitoring?

Yes, as OpenSanctions documents it: schedule the actor to re-screen your counterparties, optionally with changed since set to the date of the last run so only updated entities come back, and use the free entity details mode to re-check entity IDs you already resolved. Alert state and case management stay on your side.

#### What happens when a name has no match?

The row comes back with found set to false and a note saying there was no match in the chosen scope (and how many weaker candidates were left out below the threshold). It is never charged.

#### What happens if my key is wrong or my credits run out?

A 401 (wrong key) ends the run cleanly with the API's own words, and so does an empty credit balance. A 429 means the key reached its request quota; it is waited out a few times and then ends the run. Server errors are retried.

### Pricing

| Event | Price | Charged for |
| --- | --- | --- |
| `sanctions-entity-record` | 0.01 USD | Each candidate entity, search result or entity record OpenSanctions returns |

### Keyword map

OpenSanctions API, sanctions screening API, PEP screening, politically exposed persons check, AML screening, KYC screening, KYB, watchlist screening, OFAC SDN check, EU sanctions list, UN sanctions, UK sanctions list, adverse list check, debarment check, sanctions name matching, fuzzy name matching, counterparty screening, vessel sanctions IMO check, crypto wallet sanctions, continuous monitoring, compliance automation.

### Terms and data use

Use of the hosted OpenSanctions API is governed by the General Terms and Conditions for the OpenSanctions API (opensanctions.org/docs/terms/api/202609). Section 7.2 grants you the right, for the term of your contract, to obtain the data through the API and to store and display it for internal purposes or within your own products or services offered to third parties. Section 7.3 forbids duplicating or scraping the data collection or significant parts of it (7.3(a)), selling, renting or lending it (7.3(b)), making it publicly accessible (7.3(c)), passing it on or distributing it in whole or in substantial parts (7.3(d), (e), (l)), editing its contents (7.3(f)), using it for marketing (7.3(g)) or to compete directly with OpenSanctions (7.3(h)). Section 7.4 states the rights are granted to you alone and not in favor of your technical service providers or other third parties. There is no storage or cache time limit. Run this actor with your own key, keep the results inside your own organization or products, and do not publish, resell or bulk export them; redistribution needs an OpenSanctions reseller licence. This actor is not affiliated with or endorsed by OpenSanctions.

# Actor input Schema

## `mode` (type: `string`):

Entity screening scores each name or entity against the OpenSanctions database with the /match API (fuzzy, cross-script name matching plus birth date, nationality and identifier checks), one credit per entity. Text search runs a keyword search with filters, one credit per page. Entity details reads the full record of known OpenSanctions entity IDs with sanctions, family and ownership links, free on your plan.

## `names` (type: `array`):

Entity screening. One person, company or vessel name per line, all screened as the entity type below. Up to 1,000 a run, each one OpenSanctions credit.

## `entityType` (type: `string`):

Entity screening. The FollowTheMoney schema the names are screened as. Use the most specific one you know; LegalEntity covers both companies and organizations.

## `entities` (type: `array`):

Entity screening, for better precision. A JSON list of entities with extra details, each with a schema and FollowTheMoney properties, either flat or under properties, and an optional ref that is copied to every row. Example: \[{"ref": "cust-42", "schema": "Person", "name": "Arkadii Rotenberg", "birthDate": "1951", "nationality": "ru"}, {"schema": "Company", "name": "Stroygazmontazh", "jurisdiction": "ru", "registrationNumber": "1077762942212"}, {"schema": "Vessel", "name": "Example", "imoNumber": "9123456"}].

## `threshold` (type: `number`):

Entity screening. The score (0 to 1) at or above which a candidate counts as a match. 0.7 is the calibrated default; 0.8 or 0.85 gives fewer false positives.

## `algorithm` (type: `string`):

Entity screening. The OpenSanctions scoring algorithm. Best is recommended; pin logic-v2 if you need stable scores for audit.

## `resultsPerEntity` (type: `integer`):

Entity screening. The most candidates OpenSanctions returns for each screened entity (API maximum 500).

## `onlyMatches` (type: `boolean`):

Entity screening. Keeps only candidates at or above the threshold. Turn off to also get (and pay for) weaker candidates for manual review.

## `searchQuery` (type: `string`):

Text search. Keywords such as a name, with the documented search syntax: field searches, wildcards and, with fuzzy on, name~ for fuzzy terms.

## `searchSchema` (type: `string`):

Text search. Restricts results to one entity type.

## `countries` (type: `array`):

Text search. Two letter ISO country codes in lower case, one per line, such as ru, ir or us.

## `filters` (type: `array`):

Text search. One field:value filter per line on entity properties, such as properties.programId:EU-UKR or properties.birthDate:1965.

## `fuzzy` (type: `boolean`):

Text search. Allows the fuzzy query syntax in the search query.

## `entityIds` (type: `array`):

Entity details. One OpenSanctions entity ID per line (the entityId column of a screening or search row, or the ID in an opensanctions.org/entities/ link). Merged IDs are followed to the canonical entity. Up to 1,000 a run.

## `nested` (type: `boolean`):

Entity details. Includes adjacent entities in the record: sanction designations, addresses, identification documents, family, associates, owners and subsidiaries.

## `dataset` (type: `string`):

Entity screening and text search. The OpenSanctions collection to screen or search against.

## `topics` (type: `array`):

Entity screening and text search. Only entities with at least one of these risk topics.

## `includeDatasets` (type: `array`):

Entity screening and text search. Only entities in at least one of these source datasets, such as us_ofac_sdn, eu_fsf or gb_hmt_sanctions (names as on opensanctions.org/datasets).

## `excludeDatasets` (type: `array`):

Entity screening and text search. Leaves out entities from these source datasets.

## `changedSince` (type: `string`):

Entity screening and text search. Only entities updated since this date (2026-01-31, optionally with a time such as 2026-01-31T12:00). Useful for re-screening as part of continuous monitoring.

## `maxResults` (type: `integer`):

The most rows this run returns and charges for. Only this many entities are screened or looked up, and a search stops paging here.

## `requestsPerMinute` (type: `integer`):

Pacing. A 429 quota answer is waited out and retried a few times, then ends the run.

## `apiKey` (type: `string`):

Your own OpenSanctions API key (opensanctions.org/account). Stored as a secret, sent only to api.opensanctions.org in the Authorization header as ApiKey, and never logged. You can instead set the DATA_API_KEY environment secret.

## Actor input object example

```json
{
  "mode": "match",
  "names": [
    "Vladimir Putin"
  ],
  "entityType": "Person",
  "threshold": 0.7,
  "algorithm": "best",
  "resultsPerEntity": 5,
  "onlyMatches": true,
  "searchSchema": "Thing",
  "fuzzy": false,
  "entityIds": [
    "Q7747"
  ],
  "nested": true,
  "dataset": "default",
  "maxResults": 100,
  "requestsPerMinute": 60
}
```

# Actor output Schema

## `records` (type: `string`):

One row per candidate entity returned for the chosen mode.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "names": [
        "Vladimir Putin"
    ],
    "entityIds": [
        "Q7747"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/sanctions-watchlist-screening-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "names": ["Vladimir Putin"],
    "entityIds": ["Q7747"],
}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/sanctions-watchlist-screening-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "names": [
    "Vladimir Putin"
  ],
  "entityIds": [
    "Q7747"
  ]
}' |
apify call nabeelbaghoor/sanctions-watchlist-screening-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/sanctions-watchlist-screening-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4VUdiXEDtbzqbeBx5/builds/YAN2sfJckvcqtX8Rf/openapi.json
