Payment sanction compliance
1) Why do you need it (risk box)
Legal risk: fines/license revocation for violation of sanctions regimes.
Financial risk: freezing of funds/accounts on the corridor (correspondent/PSP/scheme).
Operational risk: force majeure returns, stuck transactions, an increase in manual checks.
Reputation: "sanctioned" incidents hit partner banks and access to corridors.
2) Modes and principles
Lists: OFAC (SDN/SSI), EU, UK (OFSI), CA, AU, UN, local.
Geo-embargo: total bans by country/territory.
Sectoral: industry/term limits (SSI/Directive).
"50% rule": if one or more SDNs own a total of ≥50%, the entity is considered blocked, even if not named.
Export control/dual purpose: payment for a prohibited product/service (important in A2A/SWIFT remits).
Crypto/Travel Rule: transfer of KYC attributes between VASPs in cross-border transfers.
3) Where and how to screen (payment loop)
3. 1. Deposits
Payer: name/address/date of birth (if available), card (BIN-geo), wallet, IP/ASN, device.
Provider: PSP/MID and their jurisdiction; check of "cleanness" of the route.
Events: profile creation (L0), first deposit (L1), anomalies (velocity/geo-conflict).
3. 2. Conclusions
Beneficiary: IBAN/BIC/name/address, card/wallet, crypto address (VASP).
Route: same-method/return-to-source, recipient bank, possible correspondents.
Travel Rule (crypto): exchange of originator/beneficial data, check of VASP status.
3. 3. Routing/Corridors
A2A/SEPA/FPS/PIX/RTP: recipient bank and its country/risk.
Push-to-card: card issuing bank (BIN-country/bank).
SWIFT: correspondent banks (all chain links).
E-wallets: the jurisdiction of the issuer/purse operator.
4) Screening types and signals
Name/aliases/transliteration (fuzzy match, reduction of diacritics).
Address/city/zip code (geo-triggers, "sanctioned" locations).
Date of birth/passport/MRN (when available from KYC).
Organizations/Beneficiaries (UBO): extended due diligence.
IBAN/BIC and receiving bank: country, "sanction bank" or sub-sanction UBO.
BIN/card issuer: country/bank, cross-check with sledge lists.
IP/ASN/VPN/hosting: sank geo, proxy/shadow ASN.
Device-graph/household: interferences with previously locked.
Crypto addresses: tags "sanctions/mixers/risk clusters" at blockchain providers.
Geo-conflict: KYC country ≠ IP ≠ SIM ≠ BIN geo.
5) Screening orchestration: "where to embed"
1. Onboarding: easy screening by name/DR, country risk.
2. Payment init: synchronous hit-check payer/beneficiary, IBAN/BIN, IP/ASN.
3. Pre-routing: deny/hold/step-up (SoF/documents) before sending to the corridor.
4. In-flight: status monitoring from PSP/banks (returns/holds).
5. Post-event: retrospective rescreen when updating lists (backfill).
6) Decision policy (risk-based)
AUTO-PASS: no hits; low country/bank risk; same-method; ND≥0.
MANUAL REVIEW: fuzzy hit below high threshold; a new beneficiary; geo-conflict; high country/sector risk.
DENY/BLOCK: exact SDN hit, "50% rule," GEO embargo, sanction bank/corridor.
STEP-UP: SoF/SoW request, beneficiary address/name confirmation, "name check/IBAN" (where available).
7) Reduction of false positives (precision)
Normalization of full name (permutation of names/surnames, patronymic, cases, particles).
Contextual attributes: date of birth/city reduce FPR.
White-lists: verified beneficiaries/banks/IBAN (with TTL and revalidation).
ASN/VPN blacklist: Fewer noisy hits over IP.
Segment thresholds: stricter for high-risk GEO/corridors, softer for low-risk.
Auto-resolution after manual APPROVE with the same fingerprint (device/IBAN).
Explainability logs: why rejected/allowed (speed, rules, matching fields).
8) UX and Communications
Transparent reasons: "Recipient validation is required due to bank/country."
Timeline: Honest ETAs for manual review/SoF.
Returns: automatic refand to the game wallet, link "choose another method/recipient."
Localization: legal texts, links to sanctions policy/support.
9) Engineering: data model (minimum)
sql sanctions.watchlists (
source TEXT, -- OFAC, EU, UK, UN, etc.
entity_id TEXT, -- уникальный ID записи entity_type TEXT, -- person org vessel bank name TEXT, aliases TEXT[], dob DATE, country TEXT,
programs TEXT[], -- санкционные программы ownership_json JSONB, -- связи для "50% правила"
updated_at TIMESTAMP
);
sanctions.hits (
hit_id PK, user_id, payout_id, deposit_tx_id,
entity_id, source, match_score NUMERIC, match_fields JSONB,
status TEXT, -- OPEN APPROVED DENIED ESCALATED FALSE_POSITIVE reviewer TEXT, decided_at TIMESTAMP, created_at TIMESTAMP
);
payments.endpoints (
beneficiary_id PK, user_id, type, -- IBAN CARD WALLET CRYPTO iban TEXT, bic TEXT, bin TEXT, wallet_ref TEXT, crypto_addr TEXT,
bank_country TEXT, bank_name TEXT, verified BOOLEAN,
last_screened_at TIMESTAMP, risk_tags TEXT[]
);
risk.context (
user_id, ip INET, asn INT, device_hash TEXT,
geo_ip TEXT, geo_kyc TEXT, geo_sim TEXT, updated_at TIMESTAMP
);
10) Pseudo-DSL policies
yaml policy: "sanctions_payments_v4"
lists:
sources: [OFAC, EU, UK, UN, CA]
refresh_interval_hours: 6 screening:
on_user_create: true on_deposit_init: true on_payout_init: true on_new_beneficiary: true rescreen_on_list_update: true thresholds:
name_fuzzy_pass: 0.72 name_fuzzy_manual: 0.62 org_fuzzy_pass: 0.80 crypto_risk_max: "MEDIUM"
routing_guards:
deny_if:
- geo in [EMBARGOED]
- bank_sanctioned == true
- ownership_sdn_agg >= 0.5 # "50% правило"
manual_review_triggers:
- fuzzy_hit == true
- new_beneficiary == true AND amount > 1000 EUR
- geo_conflict_score >= 2
- vasp_untrusted == true stepups:
- if: payout_amount > 2000 EUR then: ["name_check_iban"]
- if: crypto == true then: ["travel_rule", "beneficiary_vasp_check"]
audit:
store_feature_snapshot: true store_decision_tree: true exceptions:
whitelist_beneficiary_ttl_days: 180
11) SQL templates
11. 1. Fuzzy Search by Name/Alias
sql
SELECT w.entity_id, w.source, w.name,
similarity(unaccent(lower(:full_name)), unaccent(lower(w.name))) AS score
FROM sanctions.watchlists w
WHERE w.entity_type='person'
AND (unaccent(lower(:full_name)) % unaccent(lower(w.name))
OR EXISTS (SELECT 1 FROM unnest(w.aliases) a
WHERE unaccent(lower(:full_name)) % unaccent(lower(a))))
ORDER BY score DESC LIMIT 20;
11. 2. Checking the "50% rule" on ownership
sql
SELECT entity_id
FROM sanctions.watchlists
WHERE entity_type='org'
AND (ownership_json->>'sdn_agg_share')::numeric >= 0.5;
11. 3. List Refresh Rescreen Trigger
sql
INSERT INTO sanctions.hits (user_id, entity_id, source, match_score, status, created_at)
SELECT u.user_id, w.entity_id, w.source, 0.0, 'OPEN', now()
FROM users u
JOIN sanctions.watchlists w ON w.updated_at >:last_run
WHERE u.country IN (:risk_geos);
11. 4. IBAN/Beneficiary Bank: Risk Guard
sql
SELECT e.beneficiary_id,
(e.bank_country = ANY(:embargo_geos)) AS embargo_hit,
(e.bic IN (SELECT bic FROM ref.sanctioned_banks)) AS bank_hit
FROM payments.endpoints e
WHERE e.beneficiary_id=:bid;
11. 5. Crypto Travel Rule (simplified control)
sql
SELECT v.vasp_id, v.trust_level, tx.crypto_addr
FROM crypto.transfers tx
JOIN ref.vasps v ON v.domain = tx.beneficiary_vasp
WHERE tx.payout_id =:pid;
12) KPI and dashboards
Hit Rate: Proportion of transactions/beneficiaries with sanctioned hits.
False Positive % и Manual Approve %.
Manual TAT p50/p95 (decision time).
Denied% by Modes/Geo/Corridors/Banks.
Rescreen backlog after updating the lists.
Returns/holds% on sanka codes from PSPs/banks.
Travel Rule coverage% (crypto).
Whitelisted TTL breach% (rotten "trusted" without revalidation).
13) Alerts
List Update Spike: Soaring hits after list updates
FPR Surge: False Positive%> threshold d/d.
Manual Backlog: open cases> limit or p95 TAT> SLA.
Embargo Route Hit: Attempts to make payments on banned geo/banks.
Travel Rule Missing: crypto translations without VASP data exchange.
Policy Drift: transactions without a snapshot of rules/solutions.
14) Incident playbooks
A. Massive hits after OFAC/EU update
1. Freeze auto-routing on risk corridors → MANUAL.
2. Priority by amount/ETA, quick training for operators of new aliases/spelling.
3. PSP/bank communication: warn of temporary growth of manual.
B. Returns by Correspondent Bank
1. Normalize the cause code, collect samples (BIC, corridor).
2. Temporarily exclude bank/corridor from cascade, reroute.
3. Post-mortem: update the directory of "sledge banks," strengthen precheck.
C. Crypto without Travel Rule
1. Block pins on unverified VASPs, request data.
2. Enable "only trusted VASP" until integration is fixed.
3. Retest and report to regulator if necessary.
15) Best practices (short)
1. Policy-as-code with versions and snapshots of features/solutions.
2. Multiple-point screening (profile, init, pre-route, post).
3. Consider 50% rule and UBO links, not just name entries.
4. Name normalization and context (DR/city) to reduce FPR.
5. Whitelists of verified beneficiaries/banks with TTL and revalidation.
6. Segment thresholds by GEO/method/corridor.
7. Explainability logs and audit trail: "who/when/why."
8. Negotiate manual return codes and SLAs with PSP/banks.
9. Travel Rule and registry of trusted VASPs for crypto.
10. Regular post-incidents and rule tuning.
16) Implementation checklist
- List sources and refresh rate (OFAC/EU/UK/UN/local).
- 50% policy and UBO graph.
- Screening for onboarding/deposit/payout/new beneficial/rescreen.
- Integrations: PSP/banks/wasps, return codes.
- Threshold matrix (pass/manual/deny), GEO/method segments.
- White/black lists (beneficial/bank/ASN/IP) with TTL.
- Explainability logs, feature/solution snapshots, license reports.
- KPI dashboards and alerts; Manual SLAs.
- Playbooks (list update, returns, Travel Rule).
- Operator training (aliases/transliteration, country-rarities).
Resume Summary
Sanction compliance on payments is the orchestration of rules, data and routes, and not just "break through the list." Build screening into key payment path points, consider UBO and 50% rule, manage corridors/banks, reduce false positives through normalization and context, store explainable decisions and policy versions as code. This way you will maintain access to the corridors, reduce transaction costs and withstand license requirements without killing conversion.