# Global Sanctions/PEP Delta-Change Feed (`conceivable_extension/sanctions-pep-delta-feed`) Actor

Screens names against real OFAC SDN, UN, EU, and UK FCDO sanctions lists with fuzzy matching and cross-list deduplication, and flags exactly when a watched entity's match status changes — new listing or delisting — since your last check.

- **URL**: https://apify.com/conceivable\_extension/sanctions-pep-delta-feed.md
- **Developed by:** [joseph fadero](https://apify.com/conceivable_extension) (community)
- **Categories:** Developer tools, Integrations
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 entity screened clears

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

## Global Sanctions/PEP Delta-Change Feed

**OFAC applies strict liability — penalties up to $377,700 per violation, or twice transaction value, under IEEPA.** Sanctions lists change constantly, and — this matters, and is verified below, not assumed — the authoritative UK source itself changed in 2026. Screening against a stale or wrong list is a compliance failure that looks identical to not screening at all.

### What it does

Screens a name against four real sanctions lists (OFAC SDN, UN Consolidated, EU Financial Sanctions, UK FCDO Sanctions List) with fuzzy name matching, deduplicates the same real-world entity when it appears on 2+ lists under slightly different spellings, and — the actual point of this actor — flags exactly when a watched entity's match status changes: a new listing, or a delisting, since the last time you checked.

### Verified, not assumed — including the exact 2026 gotcha this build's PRD warned about

Every one of the four data sources was fetched and inspected live while building this actor, not assumed to work from documentation:

- **The UK source switch is real, and confirmed by comparing dates, not just trusting a claim.** The legacy OFSI "Consolidated List of Targets" (`ofsistorage.blob.core.windows.net`) — the URL still linked from some GOV.UK pages — was **over 2 months stale** (`Last-Modified: 03 Jun 2026`) when checked. The current FCDO UK Sanctions List (`sanctionslist.fcdo.gov.uk`) was **5 days old** (`Last-Modified: 06 Aug 2026`) on the same check. This actor uses the FCDO source. Using the old URL here would have been exactly the documented failure mode the PRD called out.
- **OFAC SDN** (`sanctionslistservice.ofac.treas.gov`) — real 12-column CSV, ~19k rows, no auth. A plain request without following redirects returns an empty 302; this actor's HTTP client follows redirects by default.
- **EU Financial Sanctions** — found via the EU's own official open-data catalog (data.europa.eu) metadata, not the interactive FSD tool at `webgate.ec.europa.eu/fsd/fsf` (which requires an EU Login/ECAS account — hit that wall directly while researching this). The direct CSV export is separately public with a fixed access token published as part of the dataset's own metadata.
- **UN Consolidated List** — real, clean, documented XML, no auth.
- **A real bug was caught and fixed by this live testing**, not left for production to find: the FCDO CSV has a one-line "Report Date: ..." preamble before the actual header row. Parsing it as a normal CSV silently treated that line as the header, and every single row lookup failed — the actor loaded 0 UK entities and never reported an error. Fixed by stripping the preamble before parsing; verified against a real run afterward (6,334 UK entities loaded correctly).

### Two honest scope decisions — read before relying on results

**`ofac_non_sdn` is not offered as a list option.** OFAC's other lists (Sectoral Sanctions, CAPTA, Menu-Based, Non-SDN CMIC, etc.) have no lean, dedicated public export the way the SDN list does. The only endpoint that includes them bundles everything into a single combined file — confirmed live at **over 100MB**, and explicitly labeled by OFAC itself as including historic/archived data "not considered to be an official OFAC sanctions list" and "should not be used for active transaction screening." Rather than fetch that and present it as equivalent to the clean SDN feed, this actor only screens against SDN for OFAC. If non-SDN coverage is a hard requirement, that combined export is the only public path to it, with the caveats above.

**`isPEP` is always `false`.** None of the four sources this actor reads are PEP (Politically Exposed Person) databases — sanctions lists and PEP designations are different data categories entirely. Comprehensive, structured, free PEP data doesn't exist publicly at the scale this would need; real PEP screening is normally sourced from commercial providers (Refinitiv World-Check, Dow Jones, LexisNexis) or specific national beneficial-ownership registries. The field is kept in the output schema for compatibility with the PRD, but it's never a real signal — treat any downstream logic keyed on it accordingly.

### Matching approach — what it's good at and what it isn't

Fuzzy matching uses Levenshtein edit-distance similarity, normalized for length and diacritics — implemented directly rather than pulling in Fuse.js, since the actual need (compare a query against a name or short alias list) doesn't need a general-purpose search library. Verified live:

- Correctly matches "Aerocaribean Airlnes" (deliberate misspelling) against the real OFAC entry "AEROCARIBBEAN AIRLINES" at **0.909** similarity, above the default 0.85 threshold.
- Correctly returns no match for an unrelated name.

**What it doesn't do well: abbreviations and partial names.** Levenshtein ratio penalizes length differences, so a short informal name scores low against a much longer official designation even when it's a clear match conceptually — verified live that "Islamic State" only scores **0.619** against the real UN entry "Islamic State of Iraq," well under the default threshold. This is a real, load-bearing characteristic of the algorithm, not a bug: screen using the full official/legal name where possible, since that's what these lists are actually keyed on.

### Deduplication

When a screen finds candidate matches from multiple lists that are themselves near-identical to each other (similarity ≥ 0.92), they're merged into one output record — `listSource` carries the primary hit, `additionalListSources` carries the rest — rather than emitted as separate, confusing near-duplicate rows. This runs only against the small candidate set for one query (a handful of results), not the full ~33,000-entity combined dataset — a genuine full-dataset entity-resolution pass would need a real blocking/indexing strategy this build doesn't implement.

### Caching

All four lists are cached in a KV store for 20 hours (named store, not the bare `Actor.openKeyValueStore()` default — that specific distinction is the subject of a real bug found and fixed in Actor 26, this actor's sibling build; see that actor's README/memory for the full story). Re-downloading ~80MB combined on every single `screen` call would be wasteful given these sources update at most daily; a scheduled daily `monitor` run always gets fresh data since the cache window is under 24h.

### Delta detection

Reuses `src/shared/deltaStore.ts` from Actor 26 verbatim, per this build's own PRD instruction — unmodified, including the fix that makes it use a named store. Per watched entity, the full set of currently-matched entity IDs is compared against what was stored last run: entities newly present are `newSinceLastRun: true`, entities present last time but absent now are emitted as separate `removedSinceLastRun: true` rows.

### Input schema

```json
{
  "mode": "monitor",
  "lists": ["ofac_sdn", "un", "eu", "uk_sanctions"],
  "fuzzyMatchThreshold": 0.85,
  "watchList": [{ "entityName": "string", "entityType": "individual | organization" }]
}
```

`mode: "monitor"` (default) walks `watchList`; `mode: "screen"` does a single check using top-level `entityName`. Per the batch's x402/agent-payable design constraint, `monitor` is the default agent-facing pattern.

### Output schema

```json
{
  "queryName": "string",
  "matchedEntity": "string",
  "matchScore": "number (0-1)",
  "matchType": "exact | fuzzy | alias",
  "listSource": "ofac_sdn | un | eu | uk_sanctions | null",
  "additionalListSources": ["array — cross-list dedup, extends the PRD schema"],
  "isPEP": "false, always — see above",
  "sanctionType": "string",
  "listedDate": "string | null",
  "newSinceLastRun": "boolean",
  "removedSinceLastRun": "boolean",
  "sourceUrl": "string",
  "checkedAt": "ISO timestamp",
  "status": "success | no_match | failed"
}
```

### Pricing

| Event | Price |
|---|---|
| Run started | £0.05 |
| Screen checked (no change) | £0.04 |
| New match detected | £0.15 |
| Match removed (delisted) | £0.08 |
| No match found | £0.02 |

Priced per-screen rather than flat monitoring, benchmarked toward the higher end given genuinely differentiated fuzzy-matching and dedup versus the crowded field of low-quality Store clones the PRD's research flagged (15+ existing actors, most low-rated wrappers around a single free list).

### Setup note

No browser needed — all four sources are plain HTTP downloads (CSV/XML). Runs on `apify/actor-node:20`. Set `memoryMbytes: 2048` (already the default here) — the four lists combined are roughly 40,000 parsed entities held in memory during a run.

### n8n integration

- **Workflow A (trigger):** scheduled daily re-screen of a client/counterparty watch list.
- **Workflow B (processing):** urgent alert on any `newSinceLastRun: true` — the highest-severity alert type in this whole actor portfolio; route to immediate Slack/email, not a digest.

# Actor input Schema

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

screen: one-off check for a single entityName. monitor: re-screen every entry in watchList and flag new/removed matches since last run — the default agent-facing mode.

## `entityName` (type: `string`):

Name to screen. Required when mode is screen.

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

Optional hint, not currently used to filter matches (list sources don't reliably tag this either) — kept for schema compatibility.

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

Optional. Not currently used to refine matching — most source lists don't populate DOB consistently enough to filter on reliably. Reserved for a future version.

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

Optional. Not currently used to refine matching, same reason as dateOfBirth.

## `lists` (type: `array`):

Which sanctions lists to screen against. ofac\_non\_sdn is deliberately not offered — see README for why.

## `fuzzyMatchThreshold` (type: `number`):

0-1. Minimum name similarity to count as a match. Lower catches more misspellings/variants but risks false positives.

## `watchList` (type: `array`):

One entry per entity to monitor. Each item: { "entityName": "string", "entityType": "individual | organization" }. Required when mode is monitor.

## Actor input object example

```json
{
  "mode": "monitor",
  "lists": [
    "ofac_sdn",
    "un",
    "eu",
    "uk_sanctions"
  ],
  "fuzzyMatchThreshold": 0.85,
  "watchList": [
    {
      "entityName": "Example Name",
      "entityType": "individual"
    }
  ]
}
```

# Actor output Schema

## `resultsDatasetUrl` (type: `string`):

Fuzzy-matched sanctions and PEP screening results across OFAC SDN, UN Consolidated, EU Financial Sanctions and UK FCDO lists, with listing and delisting change flags since the last check, produced by this run.

# 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 = {
    "watchList": [
        {
            "entityName": "Example Name",
            "entityType": "individual"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("conceivable_extension/sanctions-pep-delta-feed").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 = { "watchList": [{
            "entityName": "Example Name",
            "entityType": "individual",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("conceivable_extension/sanctions-pep-delta-feed").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 '{
  "watchList": [
    {
      "entityName": "Example Name",
      "entityType": "individual"
    }
  ]
}' |
apify call conceivable_extension/sanctions-pep-delta-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,conceivable_extension/sanctions-pep-delta-feed"
        }
    }
}

```

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/hjU5hnDCRQEwdSiap/builds/dpnvC3QfZC9kYD76K/openapi.json
