Sanctions screening
- sanctions.network (default, free)
- OpenSanctions (licensed) or self-hosted yente (free)
- Selecting the provider on a framework
- Result and scoring
- 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
providerkey) issanctions_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
yenteinstance 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.