# OFAC Sanctions List Search — SDN Screening with Fuzzy Matching (`ryanclinton/ofac-sanctions-search`) Actor

Screen names against the US Treasury OFAC SDN sanctions list and get a decision, not just rows: a clear / potential-match / likely-match verdict per subject, plus false-positive resolution that explains why a hit is NOT the sanctioned person. Batch screening, watchlist monitoring, no API key.

- **URL**: https://apify.com/ryanclinton/ofac-sanctions-search.md
- **Developed by:** [Ryan Clinton](https://apify.com/ryanclinton) (community)
- **Categories:** Developer tools, Lead generation
- **Stats:** 46 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 record fetcheds

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## OFAC Sanctions List Search

![OFAC sanctions screening, false positives explained — tells you who's NOT the match, screens names or a whole list, remembers prior decisions, 100% deterministic](https://apifyforge.com/readme-assets/ryanclinton-ofac-sanctions-search/hero.png)

Screen one name or a whole customer list against the US Treasury OFAC Specially Designated Nationals (SDN) sanctions list directly from the Apify platform. For every subject the actor returns a clear screening verdict -- **clear**, **potential-match**, or **likely-match** -- plus a recommended action (clear / manual-review / escalate-for-review) and the matching SDN entries with full biographical detail. It supports individuals, entities, vessels, and aircraft with fuzzy name matching, date-of-birth false-positive reduction, sanctions program and country filters, and optional watchlist monitoring that flags when a previously-clear subject becomes newly sanctioned. No API key is required -- the actor pulls data straight from the public OFAC source.

***

### Why use OFAC Sanctions List Search

Compliance screening against the OFAC SDN list is a legal requirement for many businesses operating in or with connections to the United States. Banks, fintech companies, law firms, real estate agencies, and import/export businesses must verify that their customers, partners, and counterparties do not appear on the sanctions list. Manual lookups through the OFAC website are slow, limited to one query at a time, and offer no programmatic access for bulk workflows.

This actor solves that problem by giving you full programmatic access to the complete SDN list through a simple API call. You can integrate it into your onboarding pipelines, run batch screening jobs against your entire customer database, or set up scheduled checks that alert you when new matches appear. The built-in fuzzy matching engine handles name variations, transliteration differences, and spelling discrepancies that would be missed by exact-match lookups.

Unlike the official OFAC search tool, this actor returns structured JSON data that can be piped directly into your compliance workflows, CRM systems, or case management platforms. Every result includes a confidence score from 0 to 100, letting you prioritize high-confidence matches for human review while filtering out noise. The actor processes the entire SDN list -- over 12,000 entries -- in seconds, so you get comprehensive coverage without the wait.

Whether you are building an automated KYC pipeline, conducting due diligence on business partners, or monitoring sanctions exposure across a portfolio, this actor provides the data backbone you need without requiring a Treasury API key, paid data vendor, or custom infrastructure.

***

### Key features

- **Explains false positives** -- For every subject it answers *"is this probably NOT the sanctioned person?"* with `resolutionLikelihood` (same-person / different-person / unknown), `negativeSignals`, an `autoClearCandidate` flag, a plain-English `screeningNarrative`, and a `reviewPriorityScore` that sorts the queue so analysts dismiss false positives fast and work real hits first. Most tools only explain why a name matched; this one explains why it should be dismissed.
- **Institutional memory** -- With a watchlist and scheduled runs, the actor remembers prior decisions: `priorScreenings` (seen 47 times, always cleared), `resolutionStability` (stable / changed), `suppressionCandidate` for repeat false positives, and `decisionConsistency` for audit. The batch summary compresses 10,000 verdicts into *what needs an analyst today* -- `newHighRiskHits` vs `stableHistoricalFalsePositives`.
- **Screening verdict per subject** -- Every subject gets a top-level `screeningResult` (clear / potential-match / likely-match) and a `recommendedAction` (clear / manual-review / escalate-for-review) so your pipeline can route on a stable value without parsing rows. Sanctions hits always recommend human review -- the actor never auto-blocks.
- **Batch screening** -- Screen a whole customer list in one run via `subjects` (array) or `subjectsText` (one name per line). The SDN list is downloaded and parsed once, then every subject is screened against it.
- **Date-of-birth false-positive reduction** -- Supply a subject's date or year of birth and individual matches are corroborated against the SDN entry's known DOBs. A conflicting year downgrades a strong name match as a likely false positive -- the #1 pain in sanctions screening.
- **Match strength bands** -- Each match is banded `exact / strong / partial / weak` (with the basis: primary-name, alias, id-number, uid) so reviewers triage on a stable enum, not a raw number.
- **Explainable scoring** -- Every match carries an `explanation` object (per-signal name/alias/ID similarity, DOB and country corroboration, matched tokens, risk factors) so a 92 and a 61 are self-explaining. Pair with `outputProfile: investigator` for the full evidence breakdown.
- **Screening confidence** -- A corroboration-based `high / medium / low` confidence distinct from raw match quality, plus case-management fields (`casePriority`, `reviewRequired`, `reviewReason`) that drop into a review queue.
- **OFAC-program risk indicators** -- Boolean flags (`terrorism`, `cyber`, `russia`, `iran`, `northKorea`, `narcotics`, `humanRights`, `weaponsProliferation`) derived from the entry's programs so analysts filter by sanctions context.
- **Screening profiles** -- `conservative / balanced / aggressive / investigative` presets set the thresholds for you; transliteration expansion, input aliases, and direct ID-number matching boost recall.
- **Audit-ready** -- Each run records the SDN list version, screening method, and thresholds applied, for reproducible, defensible screening.
- **Watchlist monitoring** -- Name a watchlist and each scheduled run flags per-subject change (new-hit / cleared / still-hit / unchanged), so you are alerted the moment a previously-clear customer is added to the SDN list.
- **Full SDN list coverage** -- Searches the complete OFAC Specially Designated Nationals list directly from treasury.gov, covering all sanctioned individuals, entities, vessels, and aircraft.
- **Fuzzy name matching** -- Uses Levenshtein distance, token matching, and substring analysis to catch spelling variations, transliterations, and partial name matches that exact searches would miss.
- **Tunable thresholds** -- `reviewThreshold` and `hitThreshold` let you set your own risk appetite for what counts as a potential vs likely match.
- **Entity type filtering** -- Narrow your search to specific categories: Individual, Entity, Vessel, or Aircraft, or search across all types at once.
- **Sanctions program filtering** -- Filter results by sanctions program codes such as SDGT, IRAN, UKRAINE-EO13662, CUBA, DPRK, SYRIA, and dozens more.
- **Country-based filtering** -- Filter by country across addresses, nationalities, citizenships, and vessel flags to focus on specific jurisdictions.
- **Diacritics normalization** -- Automatically strips diacritics and normalizes Unicode characters, so searches for "Muller" will match "Mueller" and vice versa.
- **Rich structured output** -- Returns complete records with aliases, ID documents, addresses, dates of birth, places of birth, vessel information, and direct OFAC detail page URLs.
- **No API key required** -- Pulls data from the publicly available treasury.gov XML feed with zero authentication setup.
- **Batch-friendly design** -- Combine with Apify scheduling and webhooks to run recurring compliance checks against your customer database automatically.

***

### How to use

#### Using the Apify Console

1. Navigate to [OFAC Sanctions List Search](https://apify.com/ryanclinton/ofac-sanctions-search) on the Apify Store.
2. Click **Try for free** to open the actor in the Apify Console.
3. Enter a name, entity, or ID number in the **Search Query** field (e.g., "Putin").
4. Optionally select a **Search Type** to filter by Individual, Entity, Vessel, or Aircraft.
5. Optionally enter a **Sanctions Program** code (e.g., "UKRAINE-EO13662") or **Country Filter** (e.g., "Russia").
6. Toggle **Fuzzy Matching** on or off depending on whether you want approximate or exact matching.
7. Set the **Max Results** to control how many matches are returned (default: 50, max: 500).
8. Click **Start** and wait for the run to complete.
9. View results in the **Dataset** tab, or export as JSON, CSV, or Excel.

#### Using the Apify API

**cURL:**

```bash
curl "https://api.apify.com/v2/acts/ryanclinton~ofac-sanctions-search/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Putin",
    "searchType": "Individual",
    "country": "Russia",
    "fuzzyMatch": true,
    "maxResults": 10
  }'
```

**JavaScript:**

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

const run = await client.actor('ryanclinton/ofac-sanctions-search').call({
    query: 'Putin',
    searchType: 'Individual',
    country: 'Russia',
    fuzzyMatch: true,
    maxResults: 10,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("ryanclinton/ofac-sanctions-search").call(run_input={
    "query": "Putin",
    "searchType": "Individual",
    "country": "Russia",
    "fuzzyMatch": True,
    "maxResults": 10,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

***

### Input parameters

Provide a subject in any one of three ways: `query` (single name), `subjects` (array, for richer per-subject fields), or `subjectsText` (one name per line).

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `query` | String | One of the three | -- | Single name, entity, vessel, or ID number to screen |
| `subjects` | Array | One of the three | -- | Batch: array of `{ subjectId?, externalReference?, name, aliases?, idNumber?, dateOfBirth?, yearOfBirth?, country?, program?, searchType? }`. Aliases are screened under the same subject; `idNumber` is matched against the SDN ID documents |
| `subjectsText` | String | One of the three | -- | Batch: a list of names, one per line |
| `runMode` | Enum | No | `"screen"` | `screen` (decisioning), `monitor` (with a watchlist, emit only changed subjects), `lookup` (exact UID/ID/name, no fuzzy) |
| `subjectId` | String | No | -- | Stable identifier echoed on every output record (single-subject; set per subject in the array for batch) |
| `externalReference` | String | No | -- | KYC case / transaction / CRM reference echoed on every record |
| `searchType` | Enum | No | `"All"` | Restrict to entry type: `All`, `Individual`, `Entity`, `Vessel`, `Aircraft` |
| `program` | String | No | -- | Filter by sanctions program code (e.g., `SDGT`, `IRAN`, `UKRAINE-EO13662`, `CUBA`, `DPRK`) |
| `country` | String | No | -- | The subject's known country. Corroborates matches (a mismatch becomes a `different-person` signal); does **not** filter hits out |
| `dateOfBirth` | String | No | -- | Subject DOB (YYYY or full date). Corroborates individual matches; a conflict downgrades a name match as a likely false positive |
| `yearOfBirth` | Integer | No | -- | Subject year of birth, if the full date is unknown |
| `screeningProfile` | Enum | No | -- | Preset posture: `conservative` (fewest false positives), `balanced`, `aggressive` (max detection), `investigative` (surface weak matches). Sets thresholds + fuzzy for you |
| `fuzzyMatch` | Boolean | No | `true` | Enable fuzzy/partial name matching. When disabled, requires exact substring match |
| `maxResults` | Integer | No | `50` | Maximum matching SDN entries returned per subject (1--500) |
| `reviewThreshold` | Integer | No | profile/`50` | Score at/above which a match counts as a potential match. Overrides the profile |
| `hitThreshold` | Integer | No | profile/`75` | Score at/above which a match is treated as a likely match (escalate). Overrides the profile |
| `expandNameVariants` | Boolean | No | `false` | Also screen common transliteration / corporate-suffix variants (Muhammad/Mohammed, Ltd/Limited) for higher recall |
| `deduplicateSubjects` | Boolean | No | `false` | Collapse duplicate subject names before screening |
| `includeRejected` | Boolean | No | `false` | Emit up to 5 near-miss candidates per subject (with the reason) for investigator audit |
| `watchlistName` | String | No | -- | Name a watchlist to track results across runs and flag changes (with a change reason) |
| `outputProfile` | Enum | No | `"standard"` | `minimal` (verdicts only), `standard` (verdict + lean matches), `full` (all fields), `investigator` (full + the evidence/explanation breakdown) |

**Example input (batch with DOB disambiguation):**

```json
{
    "subjects": [
        { "name": "Vladimir Putin", "yearOfBirth": 1952 },
        { "name": "Maria Gonzalez", "country": "Cuba" },
        { "name": "Rosneft", "searchType": "Entity" }
    ],
    "fuzzyMatch": true,
    "maxResults": 25,
    "watchlistName": "customer-book-q2"
}
```

**Tips for best input:**

- Use full names when possible (e.g., "Vladimir Putin" rather than just "Putin").
- Supply `dateOfBirth` / `yearOfBirth` for individuals -- it sharply reduces false positives on common names.
- Combine `country` and `program` filters to narrow results when screening common names.
- Set a `watchlistName` and schedule the run to be alerted when a customer is newly sanctioned.
- Program codes are case-insensitive -- "iran" works the same as "IRAN".

***

### Output

![Sample output: subjects with screening result, resolution likelihood, alert severity, review priority score, and recommended action — the false-positive contrast across rows](https://apifyforge.com/readme-assets/ryanclinton-ofac-sanctions-search/output-table.png)

The dataset carries two record types, discriminated by `recordType`. For each subject the actor emits **one `screening-summary` record (the verdict)** followed by its **`match` records (the SDN entries)**. A run-level `SUMMARY` (totals) is also written to the key-value store.

**Screening-summary record** -- the per-subject verdict your pipeline routes on:

```json
{
    "recordType": "screening-summary",
    "schemaVersion": "2.2.0",
    "decisionId": "ofac_sdn_20260602_cust-12345_2c5ad6d8",
    "subject": "Vladimir Putin",
    "subjectId": "cust_12345",
    "externalReference": "onboarding-88921",
    "screeningResult": "likely-match",
    "recommendedAction": "escalate-for-review",
    "resolutionLikelihood": "same-person",
    "autoClearCandidate": false,
    "alertSeverity": "critical",
    "reviewPriorityScore": 85,
    "screeningNarrative": "Exact name match to an OFAC SDN record. Date of birth confirmed. Country aligned. Corroborating identifiers present — escalate for review.",
    "sanctionsCategory": "state-actor",
    "programRisk": "high",
    "screeningFingerprint": "sdn:35096|dob:1952|country:russia",
    "screeningConfidence": "high",
    "casePriority": "high",
    "reviewRequired": true,
    "reviewReason": ["exact primary name match", "date of birth confirmed", "country aligned"],
    "riskIndicators": { "terrorism": false, "cyber": false, "russia": true, "iran": false, "northKorea": false, "narcotics": false, "humanRights": false, "weaponsProliferation": false },
    "matchCount": 3,
    "strongestMatchStrength": "exact",
    "strongestMatchScore": 100,
    "topMatchName": "Vladimir Vladimirovich PUTIN",
    "topMatchUid": "35096",
    "topMatchPrograms": ["RUSSIA-EO14024"],
    "changeFlag": "still-hit",
    "previousResult": "likely-match",
    "changeReason": { "entryAdded": false, "newPrograms": [], "changedFields": [], "resultChanged": false, "scoreDelta": 0, "changeSource": "run-comparison" },
    "summary": "\"Vladimir Putin\" — LIKELY-MATCH (3 matches, strongest: exact). Recommended action: escalate for review.",
    "extractedAt": "2026-06-04T02:13:34.890Z"
}
```

`screeningConfidence` is about **corroboration**, not raw match quality: a strong name match with a confirmed date of birth or aligned country is `high`; the same name match with no corroborating signal is at most `medium`; a date-of-birth conflict drops it to `low`. `casePriority` / `reviewRequired` / `reviewReason` drop straight into a case-management queue, and `riskIndicators` (derived from the OFAC programs) let analysts filter by sanctions context — `WHERE riskIndicators.russia = true`.

**Match record** -- one matching SDN entry, enriched with the decision + explanation layer:

```json
{
    "recordType": "match",
    "schemaVersion": "2.2.0",
    "subject": "Vladimir Putin",
    "subjectId": "cust_12345",
    "externalReference": "onboarding-88921",
    "uid": "36360",
    "fullName": "Vladimir PUTIN",
    "entityType": "Individual",
    "matchStrength": "exact",
    "matchBasis": "primary-name",
    "matchedInput": { "type": "name", "value": "Vladimir Putin", "originalSubjectName": "Vladimir Putin" },
    "variantGeneratedFrom": null,
    "dobMatch": "confirmed",
    "screeningConfidence": "high",
    "resolutionLikelihood": "same-person",
    "negativeSignals": [],
    "evidence": { "matchedPrimaryName": true, "matchedAlias": false, "matchedId": false, "matchedCountry": true, "matchedDob": true },
    "matchScore": 100,
    "screeningFingerprint": "sdn:36360|dob:1952|country:russia",
    "rankReason": "exact match — highest score (100), DOB confirmed.",
    "riskIndicators": { "russia": true, "terrorism": false, "cyber": false, "iran": false, "northKorea": false, "narcotics": false, "humanRights": false, "weaponsProliferation": false },
    "explanation": {
        "primaryNameSimilarity": 100,
        "aliasSimilarity": 90,
        "idSimilarity": 0,
        "dobConfidence": "confirmed",
        "countryConfidence": "aligned",
        "tokenMatches": ["vladimir", "putin"],
        "riskFactors": ["exact primary name match", "date of birth confirmed", "country aligned"]
    },
    "programs": ["RUSSIA-EO14024", "UKRAINE-EO13661"],
    "datesOfBirth": ["07 Oct 1952"],
    "country": "Russia",
    "ofacUrl": "https://sanctionssearch.ofac.treas.gov/Details.aspx?id=36360",
    "summary": "\"Vladimir Putin\" — exact match on OFAC SDN entry \"Vladimir PUTIN\" (basis: primary-name). DOB confirmed.",
    "source": "US Treasury OFAC SDN List",
    "extractedAt": "2026-02-17T14:30:00.000Z"
}
```

**Built for production integration.** Every record echoes your `subjectId` and `externalReference`, so downstream systems join on a stable key instead of a name. Each verdict carries a deterministic `decisionId` (subject + SDN version + thresholds + top match + verdict) for audit trails and cross-run deduplication. With aliases and variant expansion in play, `matchedInput` tells you exactly which input caused the hit (`{ type: "alias", value: "Bob Smith", originalSubjectName: "Robert Smith" }`), and `variantGeneratedFrom` records the transliteration rule when a generated variant matched.

***

![Four features: explains false positives (resolution engine), verdict plus recommended action (3 verdicts), batch plus watchlist monitoring (scheduled), institutional memory (audit-ready)](https://apifyforge.com/readme-assets/ryanclinton-ofac-sanctions-search/feature-callouts.png)

### Explaining false positives (analyst acceleration)

In real sanctions operations, the overwhelming majority of alerts are false positives, and analysts spend most of their day proving *"this is NOT that person."* Most tools only tell you why a name matched. This actor also tells you **why a match should be dismissed** -- and orders the queue so analysts work the real hits first.

For every subject the verdict carries:

- **`resolutionLikelihood`** -- `same-person` / `different-person` / `unknown`. Distinct from the match score: a 95 name match with a date-of-birth conflict and a country mismatch resolves to **`different-person`**, not a strong hit.
- **`negativeSignals[]`** (on each match) -- the explicit reasons it is probably not the sanctioned entity: `date-of-birth-conflict`, `country-mismatch`, `id-no-overlap`, `weak-name-match`.
- **`autoClearCandidate`** -- `true` when the whole alert is a likely false positive and safe to deprioritise. The actor identifies these; it never auto-clears.
- **`reviewPriorityScore`** (0-100) -- sort the review queue automatically; false positives sink to the bottom.
- **`alertSeverity`** -- `critical` / `high` / `medium` / `low`, from confidence + corroboration + program risk.
- **`screeningNarrative`** -- a template-driven, audit-ready sentence (no LLM): *"Partial name similarity... date of birth conflicts... country mismatch detected. Likely false positive -- recommend dismissal after review."*
- **`evidence`** (on each match) -- a decision matrix of which signals corroborated: `matchedPrimaryName`, `matchedAlias`, `matchedId`, `matchedCountry`, `matchedDob`.

The same name screened twice shows the contrast:

| Subject | DOB | Country | resolutionLikelihood | alertSeverity | priority |
|---|---|---|---|---|---|
| Vladimir Putin | 1952 (confirmed) | Russia (aligned) | `same-person` | `critical` | 85 |
| Vladimir Putin | 1900 (conflict) | Spain (mismatch) | `different-person` | `low` | 0 |

### Institutional memory

Set a `watchlistName` and screen on a schedule, and the actor **remembers prior screening decisions** -- deterministically, no LLMs, no human notes. The same customer screened at onboarding, on every payment, and at annual re-screen stops being a fresh investigation each time:

- **`priorScreenings`** -- `{ seenBefore, timesScreened, firstSeen, lastSeen, previousOutcome }`. The analyst sees this exact subject was screened 47 times before and always resolved `different-person`.
- **`resolutionStability`** -- `stable` (same result as last time) / `changed` (new evidence, new program, new match) / `new`. The field that tells an analyst *"nothing changed, you cleared this last month."*
- **`suppressionCandidate`** + **`suppressionReason`** -- a *recommendation* (never an auto-suppression) to deprioritise a false positive the analyst has cleared before: `["date-of-birth-conflict", "country-mismatch", "screened-3-times"]`.
- **`decisionConsistency`** -- `{ matchesPriorOutcome, lastOutcome, lastReviewedAt }`. The audit field big banks build internally: "this decision matches the prior outcome, last reviewed on X."
- **`commonNameRisk`** + **`uniquenessScore`** -- common names (Mohammed, Ali, Smith, Kim, Li, Wang) generate most false positives. The uniqueness score is derived from the actual SDN name population and feeds queue prioritisation -- not matching.
- **`identityConfidence`** (per match) -- `{ name, dob, country, id }` 0-100, so analysts see exactly what is driving the decision.

#### Case compression -- what actually needs attention

Given 10,000 screened customers, the batch `SUMMARY` answers the only question an operations lead is asking -- *what needs an analyst today?* -- instead of returning 10,000 verdicts:

```json
{
    "batchIntelligence": {
        "commonNameClusters": 482,
        "repeatSubjects": 9129,
        "newSubjects": 871,
        "manualReviewQueue": 41,
        "autoClearCandidates": 763,
        "stableHistoricalFalsePositives": 128,
        "newHighRiskHits": 3
    }
}
```

`newHighRiskHits: 3` is the number that matters; `stableHistoricalFalsePositives: 128` is the noise the team has already cleared and can suppress. That is the difference between a screening tool and an operations platform.

**Output field descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `uid` | String | Unique OFAC identifier for the entry |
| `firstName` | String/null | First name (null for entities without a first name) |
| `lastName` | String | Last name or entity name |
| `fullName` | String | Combined first and last name |
| `entityType` | String | Entry type: Individual, Entity, Vessel, or Aircraft |
| `title` | String/null | Title or position if available |
| `programs` | String\[] | Sanctions program codes (e.g., SDGT, IRAN, CUBA) |
| `remarks` | String/null | OFAC remarks field with additional details |
| `addresses` | Object\[] | Known addresses with street, city, state, postal code, and country |
| `nationalities` | String\[] | Listed nationalities |
| `citizenships` | String\[] | Listed citizenships |
| `datesOfBirth` | String\[] | Known dates of birth |
| `placesOfBirth` | String\[] | Known places of birth |
| `idNumbers` | Object\[] | ID documents with type, number, country, issue/expiration dates |
| `aliases` | Object\[] | Known aliases with type, category, and name components |
| `vesselInfo` | Object/null | Vessel details (call sign, type, flag, owner, tonnage) for vessel entries |
| `country` | String/null | Primary country derived from nationality, citizenship, or address |
| `matchScore` | Number | Confidence score from 0 to 100 (higher is a stronger match) |
| `ofacUrl` | String | Direct link to the official OFAC details page |
| `source` | String | Always "US Treasury OFAC SDN List" |
| `extractedAt` | String | ISO 8601 timestamp of when the data was extracted |

A run-level `SUMMARY` record in the key-value store carries the **audit metadata** auditors ask for:

```json
{
    "schemaVersion": "2.2.0",
    "runStatistics": { "subjectsScreened": 5000, "clear": 4922, "hits": 78, "matchRecords": 214, "newHitsSinceLastRun": 3 },
    "auditRecord": {
        "sdnVersion": "06/02/2026",
        "screeningMethod": "fuzzy-v2",
        "runMode": "screen",
        "fuzzyMatch": true,
        "thresholds": { "review": 50, "hit": 75 },
        "screeningProfile": "balanced"
    },
    "datasetInfo": { "publishedDate": "06/02/2026", "entryCount": 19024, "downloadedAt": "2026-06-04T02:13:34.526Z", "source": "US Treasury OFAC SDN List" },
    "watchlist": { "name": "customer-book", "watchlistSize": 5000, "lastCheckedAt": "2026-06-04T11:00:00.000Z", "newHits": 3 },
    "generatedAt": "2026-06-04T11:00:01.000Z"
}
```

`auditRecord` answers "which list version, which method, which thresholds?" for reproducibility; `datasetInfo` records exactly which SDN publication was screened; `watchlist` summarises the monitoring run.

***

### OFAC website vs this actor

| Capability | OFAC sanctions search website | This actor |
|---|---|---|
| Bulk / batch screening | ❌ one name at a time | ✅ a whole list in one run |
| Structured JSON output | ❌ HTML page | ✅ verdict + matches + explanation |
| Screening verdict + recommended action | ❌ you decide | ✅ clear / potential-match / likely-match |
| Date-of-birth false-positive reduction | ❌ | ✅ |
| Fuzzy + transliteration matching | partial | ✅ |
| Watchlist / ongoing monitoring | ❌ | ✅ change flags + change reason |
| Audit metadata (list version, method, thresholds) | ❌ | ✅ in the run summary |
| Pipeline / automation integration | ❌ | ✅ API, webhooks, Zapier, Make, Dify |

This actor reads from the same official US Treasury OFAC SDN source as the OFAC website. It is **not** a licensed commercial sanctions vendor and does not cover non-SDN lists or multi-source watchlists -- see "What this does NOT do" below.

***

### Matching methodology

The match score (0--100) is a deterministic, transparent combination of signals -- no LLM, no black box:

- **Exact primary-name match** scores 100; substring containment 70--95; token overlap up to 55; Levenshtein fuzzy matching for short strings.
- **Alias matches** are weighted 0.9x and **ID-number matches** 0.85x relative to primary-name matches.
- **Date-of-birth corroboration**: a confirmed year raises screening confidence; a conflicting year reduces the effective score and downgrades the match as a likely false positive.
- **Country corroboration** aligns or flags the match.

Every match carries an `explanation` object exposing each of these signals, so a `92` and a `61` are self-explaining rather than something an analyst has to reverse-engineer. Because the scoring is deterministic, the same input + same SDN list version + same thresholds always produce the same result -- which is what the `auditRecord` records for reproducibility.

***

### Enterprise workflow examples

**Customer onboarding (KYC gate).** Screen one applicant; route on the verdict.

```json
{ "subjects": [{ "name": "Maria Gonzalez", "yearOfBirth": 1979, "country": "Cuba" }], "screeningProfile": "conservative" }
```

`recommendedAction = clear` continues onboarding; `manual-review` / `escalate-for-review` holds it for a compliance officer.

**Payment screening.** Screen the counterparty on a transaction with the strict profile to minimise false holds.

```json
{ "query": "Bank Melli Iran", "searchType": "Entity", "screeningProfile": "conservative" }
```

**Vendor / supplier due diligence.** Batch-screen a supplier list with transliteration expansion for international names.

```json
{ "subjectsText": "Acme Trading Ltd\nMuhammad Imports\nVostok Logistics", "expandNameVariants": true }
```

**Ongoing monitoring.** Schedule a daily run over your customer book on a watchlist; alert on `changeFlag = "new-hit"`.

```json
{ "subjects": [{ "name": "Robert Smith", "aliases": ["Bob Smith"], "yearOfBirth": 1980 }], "watchlistName": "customer-book" }
```

***

### Use cases

- **KYC/AML compliance screening** -- Integrate into your customer onboarding pipeline to automatically check new customers against the SDN list before account approval.
- **Ongoing monitoring** -- Schedule daily or weekly runs to re-screen your entire customer database and detect newly added sanctions entries.
- **Vendor and supplier due diligence** -- Screen business partners, suppliers, and third-party vendors before entering into contracts or processing payments.
- **Real estate transaction screening** -- Verify buyers, sellers, and beneficial owners in property transactions as required by FinCEN guidance.
- **Trade compliance** -- Check counterparties, shipping companies, and vessel names before processing international trade transactions.
- **Investment portfolio screening** -- Scan portfolio companies, board members, and beneficial owners against the sanctions list for ESG and compliance reporting.
- **Legal case research** -- Search for sanctioned individuals and entities by name, alias, or ID number during legal investigations and litigation support.
- **Journalist investigations** -- Cross-reference persons of interest against the SDN list for investigative reporting on sanctions evasion or financial crime.
- **Insurance underwriting** -- Screen policy applicants and beneficiaries against sanctions lists as part of the underwriting risk assessment process.
- **Nonprofit grant screening** -- Verify grant recipients and partner organizations are not sanctioned before disbursing funds, as required by US federal grant conditions.

***

### API & Integration

The actor's output is available through the Apify API immediately after each run completes. You can retrieve results in JSON, CSV, XML, or Excel format.

**Python -- fetch results from the last run:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
dataset = client.dataset(client.actor("ryanclinton/ofac-sanctions-search").last_run().get()["defaultDatasetId"])
for item in dataset.iterate_items():
    if item.get("matchScore", 0) >= 80:
        print(f"HIGH MATCH: {item['fullName']} (score: {item['matchScore']})")
```

**JavaScript -- fetch results from the last run:**

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

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('ryanclinton/ofac-sanctions-search').lastRun().get();
const { items } = await client.dataset(run.defaultDatasetId).listItems();

const highMatches = items.filter(item => item.matchScore >= 80);
console.log(`Found ${highMatches.length} high-confidence matches`);
```

**cURL -- download results as CSV:**

```bash
curl "https://api.apify.com/v2/acts/ryanclinton~ofac-sanctions-search/runs/last/dataset/items?token=YOUR_API_TOKEN&format=csv" \
  -o sanctions_results.csv
```

**Integrations:**

This actor works with all Apify integrations out of the box. Connect it to **Zapier**, **Make** (formerly Integromat), **Google Sheets**, **Slack**, **Microsoft Teams**, or **email notifications** using Apify's built-in integration options. Use **webhooks** to trigger downstream workflows whenever a run completes -- for example, automatically sending a Slack alert when high-confidence matches are found. You can also chain this actor with other actors using the Apify API for multi-step compliance pipelines.

***

### Use in Dify

Drop this actor into [Dify](https://docs.apify.com/platform/integrations/dify) workflows via the Apify plugin's Run Actor node. Each subject returns a screening **decision** as structured JSON -- `screeningResult` (`clear` / `potential-match` / `likely-match`) plus the `recommendedAction` (`clear` / `manual-review` / `escalate-for-review`) your downstream node branches on. The official OFAC search returns an HTML results page a human has to read; this returns the routing primitive an automation acts on.

- **Actor ID:** `ryanclinton/ofac-sanctions-search`
- **Sample input** (gate a customer onboarding check):

```json
{
    "subjects": [
        { "name": "Maria Gonzalez", "yearOfBirth": 1979, "country": "Cuba" }
    ],
    "watchlistName": "onboarding-checks"
}
```

A Dify **if/else** node routes on the `screening-summary` record's enum fields:

- `recommendedAction == "clear"` → continue onboarding automatically
- `recommendedAction == "manual-review"` → create a review task
- `recommendedAction == "escalate-for-review"` → block onboarding and alert compliance
- `changeFlag == "new-hit"` (on scheduled re-screens) → fire an "existing customer newly sanctioned" alert

Because every value is a stable enum, the branch conditions are exact-match equality checks -- no prose parsing, no LLM in the routing path. Set `outputProfile: "minimal"` for a one-record-per-subject verdict stream that keeps the workflow payload lean.

***

### How it works

![Intelligence stack: name or list of subjects, OFAC SDN list (19,000+ entries cached daily), fuzzy + transliteration match, DOB and country corroboration, resolution engine, decision + priority, institutional memory, screening verdict](https://apifyforge.com/readme-assets/ryanclinton-ofac-sanctions-search/intelligence-layers.png)

1. **Download** -- The actor fetches the complete SDN XML file (~30 MB) directly from the US Treasury website at `treasury.gov/ofac/downloads/sdn.xml`.
2. **Parse** -- The XML is parsed in memory using `fast-xml-parser` with array hints to ensure consistent handling of single-element and multi-element lists.
3. **Normalize** -- The search query is normalized: lowercased, diacritics stripped, punctuation removed, and whitespace collapsed. The same normalization is applied to every field being compared.
4. **Filter** -- Entries are filtered by search type (Individual/Entity/Vessel/Aircraft) and sanctions program code. Country is used to *corroborate* a match (a mismatch becomes a `different-person` signal), never to filter potential hits out.
5. **Score** -- Each surviving entry is scored 0--100 against the query using a multi-signal approach: exact full-name match (100), substring containment (70--95), token overlap (up to 55), and Levenshtein fuzzy matching for short strings. Alias matches receive a 0.9x multiplier, ID number matches receive 0.85x, and remarks matches cap at 30.
6. **Threshold** -- Entries scoring below the threshold are discarded (20 for fuzzy mode, 50 for exact mode).
7. **Rank and output** -- Remaining entries are sorted by score descending, truncated to `maxResults`, transformed into structured JSON with all available fields, and pushed to the Apify dataset.

```
  treasury.gov/sdn.xml
          |
          v
  +-----------------+
  | Download ~30 MB |
  +-----------------+
          |
          v
  +-----------------+
  |   Parse XML     |
  | (fast-xml-parser)|
  +-----------------+
          |
          v
  +-----------------+
  | Normalize query |
  | + all fields    |
  +-----------------+
          |
          v
  +-----------------+
  | Filter by type, |
  | program, country|
  +-----------------+
          |
          v
  +-----------------+
  | Score & rank    |
  | (0-100 fuzzy)   |
  +-----------------+
          |
          v
  +-----------------+
  | Output to       |
  | Apify dataset   |
  +-----------------+
```

***

### Performance & cost

| Metric | Value |
|--------|-------|
| Average run time | 15--30 seconds |
| XML download | 5--15 seconds (~30 MB) |
| Parse + search | 3--10 seconds |
| Memory usage | 512 MB (recommended) |
| Compute units per run | ~0.01--0.02 CU |
| Cost per run (pay-as-you-go) | ~$0.005--$0.01 |
| Free tier estimate | ~50--100 runs/month on the free plan |
| SDN list size | ~12,000+ entries |
| Max results per run | 500 |

Costs depend on Apify's current pricing and may vary based on platform load and actual run duration. The actor is optimized for single-pass in-memory processing, so it does not make multiple HTTP requests or use persistent storage beyond the output dataset.

***

### Limitations

- **SDN list only** -- This actor screens against the OFAC SDN list. It does not cover the Consolidated Sanctions List, the Sectoral Sanctions Identifications (SSI) list, the Non-SDN Palestinian Legislative Council list, or other OFAC sub-lists. For broader multi-source coverage (SDN + global watchlists + PEPs) see the related actors below.
- **No historical data** -- The actor always downloads the current SDN list. It does not provide historical snapshots or track when entries were added or removed.
- **Name matching is heuristic** -- While fuzzy matching handles many variations, heavily transliterated names across different scripts (e.g., Arabic, Cyrillic, Chinese) may not always match perfectly.
- **Download dependency** -- The actor relies on the treasury.gov XML feed being accessible. If the Treasury website is down or the XML format changes, the actor will fail.
- **In-memory processing** -- The entire SDN XML (~30 MB parsed) is held in memory. The 2 GB memory floor handles this comfortably and keeps the parse fast; the daily list is cached so warm runs skip the download.
- **No real-time updates** -- OFAC typically updates the SDN list a few times per week. There may be a delay between OFAC publishing an update and the XML file reflecting the change.

***

### What this does NOT do

This actor screens against the **OFAC SDN list specifically**. It is the focused, no-API-key tool for that one source. For adjacent needs, use the right sibling actor instead:

| Need | Use this instead |
|------|------------------|
| Global multi-source sanctions + PEPs + watchlists (80+ sources) | [OpenSanctions Search](https://apify.com/ryanclinton/opensanctions-search) |
| Full financial-crime risk screening across 16 sources | [Financial Crime Screening](https://apify.com/ryanclinton/financial-crime-screening) |
| Interpol Red/Yellow/UN notices for wanted & missing persons | [Interpol Notice Search](https://apify.com/ryanclinton/interpol-red-notices) |
| The other OFAC lists (Consolidated/SSI/Non-SDN) | not covered here — use OpenSanctions Search |

It also does **not** auto-block or auto-clear anyone: every match recommends human review, never an automated decision. The verdict (`screeningResult` + `recommendedAction`) is a routing primitive for your compliance workflow, not a final adjudication.

***

### Responsible use

- **Not a substitute for legal compliance programs** -- This actor is a screening tool, not a compliance program. Always consult qualified legal counsel for sanctions compliance obligations specific to your jurisdiction and industry.
- **Human review required** -- Fuzzy matching may produce false positives. All results, especially those with match scores below 80, should be reviewed by a trained compliance professional before taking action.
- **Respect the data source** -- The SDN list is published by the US Department of the Treasury. Avoid excessive request frequency that could burden the treasury.gov servers. Use Apify scheduling at reasonable intervals (daily or weekly) rather than minute-by-minute polling.
- **Privacy considerations** -- Sanctions screening results contain personal information (names, dates of birth, addresses, ID numbers). Handle this data in accordance with applicable privacy regulations such as GDPR, CCPA, and your organization's data protection policies.
- **Do not use for discrimination** -- Sanctions screening should be applied uniformly as part of a documented compliance process. Do not use this tool to discriminate against individuals based on nationality, ethnicity, or other protected characteristics beyond what is required by sanctions regulations.

***

### FAQ

**Q: Do I need an API key or Treasury account to use this actor?**
**A:** No. The actor downloads the SDN list from a publicly available XML file hosted on treasury.gov. No API key, registration, or authentication is required.

**Q: How current is the SDN data?**
**A:** The actor downloads the live SDN XML file from treasury.gov on every run. The data is as current as the latest OFAC publication, which is typically updated several times per week.

**Q: What does the match score mean?**
**A:** The match score ranges from 0 to 100. A score of 100 means an exact match on the primary name. Scores of 70--95 indicate strong substring matches. Scores of 50--70 suggest partial token overlap. Scores below 50 are weaker fuzzy matches. Alias matches are weighted at 0.9x and ID matches at 0.85x relative to primary name matches.

**Q: How does fuzzy matching work?**
**A:** Fuzzy matching uses a combination of Levenshtein edit distance (for detecting typos and transliteration variations), token-based matching (for name word overlap), substring detection, and diacritics normalization. It is designed to catch common variations like "Muller" vs. "Mueller" or "Mohammad" vs. "Muhammad".

**Q: Can I search by ID number or passport number?**
**A:** Yes. Enter the ID or passport number as the search query. The actor checks against all ID documents listed for each SDN entry. ID matches are scored at 0.85x the primary name match weight.

**Q: Can I screen a list of names in bulk?**
**A:** Yes. Pass a `subjects` array (with per-subject `subjectId`, `dateOfBirth`, `country`, etc.) or a `subjectsText` list (one name per line) and the actor screens every subject in a single run -- the SDN list is downloaded and parsed once, then each subject is screened against it. Each subject gets its own `screening-summary` verdict.

**Q: What sanctions programs are covered?**
**A:** All programs on the SDN list are searchable. Common codes include SDGT (terrorism), IRAN, CUBA, DPRK (North Korea), SYRIA, UKRAINE-EO13661, UKRAINE-EO13662, RUSSIA-EO14024, CYBER2, GLOMAG (Global Magnitsky), and many more.

**Q: Does this actor cover the full consolidated OFAC sanctions list?**
**A:** No, this actor specifically covers the SDN (Specially Designated Nationals) list. It does not include the Sectoral Sanctions (SSI), the Non-SDN Menu-Based Sanctions, or other supplementary lists published by OFAC.

**Q: How do I set up recurring screening?**
**A:** Use the Apify scheduling feature to run the actor on a daily or weekly basis. Combine it with a webhook to receive a notification or trigger a downstream workflow whenever results are returned.

**Q: Can I search for vessel names?**
**A:** Yes. Set the `searchType` to "Vessel" and enter the vessel name or IMO number as the query. Results will include vessel-specific fields such as call sign, vessel type, flag, owner, and tonnage.

**Q: What happens when no results are found?**
**A:** The actor pushes a single object to the dataset with a `message` field indicating no matches were found, along with the query parameters and the SDN list metadata (publication date and total entry count).

**Q: How much does it cost to run?**
**A:** A typical run costs approximately $0.005--$0.01 in Apify compute units. On the free plan, you can run approximately 50--100 screenings per month at no cost.

***

### Related actors

| Actor | Description | Link |
|-------|-------------|------|
| OpenSanctions Search | Search the OpenSanctions global dataset covering sanctions, PEPs, and criminal watchlists from 80+ data sources | [Link](https://apify.com/ryanclinton/opensanctions-search) |
| Interpol Red Notice Search | Search Interpol's database of Red Notices for wanted persons worldwide | [Link](https://apify.com/ryanclinton/interpol-red-notices) |
| UK Companies House | Search the UK Companies House register for company details, officers, and filing history | [Link](https://apify.com/ryanclinton/uk-companies-house) |
| OpenCorporates Search | Search the world's largest open database of company information across 140+ jurisdictions | [Link](https://apify.com/ryanclinton/opencorporates-search) |
| GLEIF LEI Lookup | Look up Legal Entity Identifiers (LEIs) for corporate entity verification and ownership data | [Link](https://apify.com/ryanclinton/gleif-lei-lookup) |
| SEC Insider Trading | Search SEC EDGAR for insider trading filings (Form 4) by company or individual | [Link](https://apify.com/ryanclinton/sec-insider-trading) |

# Actor input Schema

## `query` (type: `string`):

One name, entity, vessel, or ID number to screen. For multiple subjects use Subjects or Subjects (text) below.

## `subjects` (type: `array`):

Screen many subjects in one run. Array of objects: { "name": string, "aliases"?: string\[], "idNumber"?: string, "dateOfBirth"?: string, "yearOfBirth"?: number, "country"?: string, "program"?: string, "searchType"?: string }. Aliases are screened under the same subject; idNumber is matched against the SDN ID documents. The SDN list is downloaded once and every subject is screened against it.

## `subjectsText` (type: `string`):

Paste a list of names, one per line. The simplest way to batch-screen a customer list.

## `runMode` (type: `string`):

screen = normal decisioning (default); monitor = with a watchlist, emit only subjects that changed since last run; lookup = exact UID / ID / name resolution (no fuzzy matching).

## `subjectId` (type: `string`):

Stable identifier echoed on every output record so downstream systems join on an ID, not a name. For batch, set per subject inside the Subjects array.

## `externalReference` (type: `string`):

KYC case / transaction / CRM reference echoed on every output record. For batch, set per subject inside the Subjects array.

## `searchType` (type: `string`):

Restrict screening to one SDN entry type.

## `program` (type: `string`):

Filter by sanctions program code (e.g. SDGT, IRAN, UKRAINE-EO13662, CUBA, DPRK, SYRIA).

## `country` (type: `string`):

The subject's known country. Used to corroborate matches: a country mismatch becomes a negative (different-person) signal. It does NOT filter results out -- a screening tool should never hide a potential hit listed under a different country.

## `dateOfBirth` (type: `string`):

Subject's date of birth (YYYY or a full date). When provided, individual matches are corroborated against the SDN entry's known DOBs — a conflicting year downgrades a name match as a likely false positive.

## `yearOfBirth` (type: `integer`):

Subject's year of birth, if the full date is unknown. Same false-positive-reduction effect as Date of Birth.

## `fuzzyMatch` (type: `boolean`):

Enable fuzzy/partial name matching (catches spelling and transliteration variants). When disabled, requires an exact substring match.

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

Maximum number of matching SDN entries returned per subject.

## `screeningProfile` (type: `string`):

Preset posture that sets the thresholds and fuzzy matching for you. conservative = fewest false positives; balanced = default; aggressive = maximum detection; investigative = surfaces weak matches for analyst review. Explicit thresholds below override the profile.

## `reviewThreshold` (type: `integer`):

Match score (0-100) at or above which a result counts as a potential match worth reviewing. Overrides the screening profile.

## `hitThreshold` (type: `integer`):

Match score (0-100) at or above which a result is treated as a likely match (escalate for review). Overrides the screening profile.

## `watchlistName` (type: `string`):

Name a watchlist to track screening results across scheduled runs. Each subject then carries a change flag (new-hit / cleared / still-hit / unchanged) so you are alerted when a previously-clear subject is newly sanctioned. First run flags every subject as 'new'; change detection activates from the second run.

## `expandNameVariants` (type: `boolean`):

Also screen common transliteration and corporate-suffix variants of each name (e.g. Muhammad / Mohammed, Ltd / Limited) to boost recall on transliterated names.

## `deduplicateSubjects` (type: `boolean`):

Collapse duplicate subject names before screening (useful for messy customer lists).

## `includeRejected` (type: `boolean`):

Emit up to 5 near-miss candidates per subject that were cut from the returned matches, with the reason. Useful for investigators auditing why something did or did not match.

## `outputProfile` (type: `string`):

minimal = one verdict record per subject (no entry detail); standard = verdict + lean match rows; full = verdict + complete match rows; investigator = full rows plus the explanation/evidence breakdown on every match.

## Actor input object example

```json
{
  "query": "Putin",
  "runMode": "screen",
  "searchType": "All",
  "fuzzyMatch": true,
  "maxResults": 50,
  "expandNameVariants": false,
  "deduplicateSubjects": false,
  "includeRejected": false,
  "outputProfile": "standard"
}
```

# Actor output Schema

## `verdicts` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {
    "query": "Putin"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ryanclinton/ofac-sanctions-search").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 = { "query": "Putin" }

# Run the Actor and wait for it to finish
run = client.actor("ryanclinton/ofac-sanctions-search").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 '{
  "query": "Putin"
}' |
apify call ryanclinton/ofac-sanctions-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ryanclinton/ofac-sanctions-search"
        }
    }
}

```

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/t398ffhJgct2clv9s/builds/KeATcSO1hyLniXeWn/openapi.json
