Sanctions screening

  1. sanctions.network (default, free)
  2. OpenSanctions (licensed) or self-hosted yente (free)
  3. Selecting the provider on a framework
  4. Result and scoring
  5. A note on names

A SanctionsProvider screens a counterparty by name and returns matches. A match is a deterministic FAIL in the report - never softened, never left to the AI.

interface SanctionsProvider
{
    public function screen(Counterparty $counterparty): SanctionsResult;
}

SanctionsResult carries a list<SanctionsMatch> (name, score, list name, source URL, raw) plus an optional sourceUrl / proofId.

sanctions.network (default, free)

A free, public PostgREST API over consolidated OFAC/EU data - no key. Matching is performed server-side by a search_sanctions(name) function.

The service is named sanctions.network, but the framework config value (the provider key) is sanctions_network (with an underscore).

use Gawrys\Counterparty\Adapter\Sanctions\SanctionsNetworkProvider;
use Gawrys\Counterparty\Check\SanctionsScreeningCheck;

$check = new SanctionsScreeningCheck(new SanctionsNetworkProvider($http), $clock);

This is the default precisely because it carries no restrictive licence.

OpenSanctions (licensed) or self-hosted yente (free)

OpenSanctions data is offered under a non-commercial licence; commercial use of the hosted API requires a paid agreement. It is therefore not the default. You may instead run a free, self-hosted yente instance and point the adapter at it with no key.

use Gawrys\Counterparty\Adapter\Sanctions\OpenSanctionsProvider;

// Hosted (commercial licence):
$provider = new OpenSanctionsProvider($http, apiKey: $key);

// Self-hosted yente (free, no key):
$provider = new OpenSanctionsProvider($http, baseUri: 'http://localhost:8000');

The adapter POSTs to /match/{dataset} and reads the responses.q.results[] entries (caption, score, id), filtering by a score threshold.

Selecting the provider on a framework

Laravel - config/counterparty.php:

'sanctions' => [
    'provider' => env('COUNTERPARTY_SANCTIONS', 'sanctions_network'), // or 'opensanctions'
    'threshold' => 0.7,
    'opensanctions' => [
        'api_key'  => env('OPENSANCTIONS_API_KEY'),
        'base_uri' => env('OPENSANCTIONS_BASE_URI', 'https://api.opensanctions.org'),
        'dataset'  => env('OPENSANCTIONS_DATASET', 'sanctions'),
    ],
],

Symfony - config/packages/counterparty.yaml:

counterparty:
    sanctions:
        provider: opensanctions
        opensanctions:
            api_key: '%env(OPENSANCTIONS_API_KEY)%'
            base_uri: '%env(OPENSANCTIONS_BASE_URI)%'  # a yente URL for keyless use

Result and scoring

A match yields a fail CheckResult from the sanctions source; the bundled SanctionsHitRule escalates it to critical with human review required. No match yields a pass. To run multiple providers (e.g. a free pre-screen plus a licensed deep check), register several under a SanctionsManager and add a SanctionsScreeningCheck per provider.

A note on names

Name screening is fuzzy by nature: expect false positives, and treat a hit as “block pending human review”, not an automated legal determination. Consider passing aliases / transliterated forms for non-Latin names.


Counterparty Verification - a due-diligence aid, not a compliance product. MIT licensed.

This site uses Just the Docs, a documentation theme for Jekyll.