# SanctionScreen — full agent documentation SanctionScreen is a per-call sanctions screening API for AI agents: sanctions screening and company enrichment as MCP tools. No seats, no enterprise contract. Pay per call. - Web: https://sanctionsscreen.io - API docs: https://api.sanctionsscreen.io/docs [PLACEHOLDER — replace with real Worker URL] - MCP endpoint: https://api.sanctionsscreen.io/mcp [PLACEHOLDER — replace with real Worker URL] - Machine-readable tool docs: tools.json (same directory / docs URL) - Auth: scoped API keys (`cs_live_…` prefix), per-tenant, per-tool scopes, instant revocation. OAuth 2.1 (auth-code + PKCE, PRM, DCR, client-credentials) planned for Claude Connectors / ChatGPT listings. - Metering: one meter per tool; a billable event is a successful outcome (HTTP 200 with result JSON) — failures are never billed. Idempotency via `request_id` (screening_id / company_id). Rate limits: per-minute burst token bucket + monthly quota bucket; 429 returns `X-RateLimit-*` + `Retry-After`. ## Pricing (PROPOSED — UNLOCKED: charging anyone requires the user's money decision) - Free: 50 calls/mo total (screen + enrich), no card. Abuse bound: ~$5–10 worst-case enrichment-resell COGS = acceptable CAC. - PAYG: screen $0.10 · enrich $0.15 · bundle (both in one session) $0.20. Anchors: dilisense €0.10/screen, Didit $0.20–0.27/check, Bizfile $0.019/validation–$0.50/screen. - Starter $29/mo: 300 screens + 100 enrichments included; overage at PAYG rates. - Growth $99/mo: 3,000 screens + 1,000 enrichments; lower overage. - Enterprise (custom): SSO/SCIM, audit logs, zero-data retention, static egress, SLA. - MCP included in every tier — metered through the same outcome quota. ## Tool 1: screen_counterparty Screen a person or entity against sanctions lists with cited sources. ### Input schema ```json { "type": "object", "required": ["name"], "properties": { "name": { "type": "string", "description": "Person or entity name to screen" }, "country": { "type": "string", "description": "ISO-3166 alpha-2 country code (optional)" }, "dob": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$", "description": "Date of birth, YYYY-MM-DD (persons only, optional)" }, "identifiers": { "type": "array", "items": { "type": "object", "required": ["type", "value"], "properties": { "type": { "type": "string", "description": "e.g. passport, national_id, place_of_birth, nationality" }, "value": { "type": "string" } } } }, "request_id": { "type": "string", "description": "Idempotency key (optional)" }, "include_low_confidence": { "type": "boolean", "default": true, "description": "Low-confidence matches are always returned by default; hiding them is a compliance liability" } } } ``` ### Output schema ```json { "type": "object", "properties": { "screening_id": { "type": "string" }, "disposition": { "type": "string", "enum": ["clear", "potential_match", "review_advised"] }, "matches": { "type": "array", "items": { "type": "object", "required": ["list", "list_date", "record_uid", "matched_name", "name_kind", "confidence", "confidence_score", "citation"], "properties": { "list": { "type": "string", "enum": ["OFAC_SDN", "EU_CONSOLIDATED", "UK_FCDO"], "description": "EU_CONSOLIDATED is pending EU Login account availability" }, "list_date": { "type": "string", "description": "Publish date of the list file used" }, "record_uid": { "type": "string" }, "matched_name": { "type": "string" }, "name_kind": { "type": "string", "enum": ["primary", "alias_strong", "alias_weak"] }, "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, "confidence_score": { "type": "number", "minimum": 0, "maximum": 100 }, "matched_fields": { "type": "array", "items": { "type": "string" }, "example": ["name", "dob"] }, "citation": { "type": "object", "required": ["source", "url", "accessed_at"], "properties": { "source": { "type": "string" }, "url": { "type": "string" }, "accessed_at": { "type": "string" } } } } } }, "disclaimer": { "type": "string", "const": "Informational only — not a legal verdict. Not a substitute for due diligence. Human review required before any adverse action." }, "generated_at": { "type": "string" } } } ``` ### Disposition rules - no matches → `clear` - ≥1 high/medium match → `potential_match` - any high match corroborated by an identifier → `review_advised` ### Language rule (hard) Results are reported as "potential match" — NEVER "sanctioned" or "is on a list." Screening is never presented as a legal verdict. ### Fixed disclaimer (verbatim, on every response) "Informational only — not a legal verdict. Not a substitute for due diligence. Human review required before any adverse action." ### Compliance rule All matches at or above the low threshold are ALWAYS returned — hiding low-confidence matches is a compliance liability. Matches sorted by confidence descending. ### Few-shot examples 1. High-confidence hit with identifier corroboration ```json // input { "name": "Vladimir Putin", "country": "RU", "dob": "1952-10-07" } // output (abbreviated) { "screening_id": "cs_scr_…", "disposition": "review_advised", "matches": [{ "list": "OFAC_SDN", "list_date": "2026-09-23", "record_uid": "35096", "matched_name": "Putin Vladimir", "name_kind": "alias_strong", "confidence": "high", "confidence_score": 85, "matched_fields": ["name", "dob"], "citation": { "source": "…", "url": "…", "accessed_at": "…" } }], "disclaimer": "Informational only — not a legal verdict. Not a substitute for due diligence. Human review required before any adverse action.", "generated_at": "…" } ``` 2. Name-only match (medium, no identifiers) ```json // input { "name": "TALIBAN" } // output disposition: potential_match; matches: OFAC_SDN uid 6636, name_kind primary, // confidence medium, confidence_score 80 ``` 3. Clear (no matches) ```json // input { "name": "John Smith" } // output: { "screening_id": "cs_scr_…", "disposition": "clear", "matches": [], // "disclaimer": "Informational only — not a legal verdict. Not a substitute for due diligence. Human review required before any adverse action.", // "generated_at": "…" } ``` 4. Cyrillic query (transliteration path) ```json // input { "name": "Путин Владимир" } // output disposition: potential_match; matches: OFAC_SDN uid 35096, name_kind alias_strong, // confidence medium, confidence_score 70 ``` ## Tool 2: enrich_company Look up a company's legal identity and profile. ### Input schema ```json { "type": "object", "properties": { "domain": { "type": "string", "description": "Company domain, e.g. acme.example" }, "name": { "type": "string", "description": "Company name (alternative to domain)" }, "request_id": { "type": "string", "description": "Idempotency key (optional)" } }, "anyOf": [{ "required": ["domain"] }, { "required": ["name"] }] } ``` ### Output schema ```json { "type": "object", "properties": { "company_id": { "type": "string" }, "legal_name": { "type": "string" }, "domain": { "type": "string" }, "industry": { "type": "string" }, "industry_code": { "type": "string" }, "size_band": { "type": "string", "example": "201-500" }, "employee_range": { "type": "array", "items": { "type": "integer" }, "example": [201, 500] }, "hq": { "type": "object", "properties": { "country": { "type": "string" }, "city": { "type": "string" } } }, "founded": { "type": "string" }, "sources": { "type": "array", "items": { "type": "object", "required": ["field", "source", "url"], "properties": { "field": { "type": "string" }, "source": { "type": "string" }, "url": { "type": "string" } } } }, "confidence": { "type": "string" }, "generated_at": { "type": "string" } } } ``` ### Data (v1) GLEIF LEI data (free, public) for legal identity + one commodity enrichment API wrapped in this schema. Every field carries its source in `sources`. ### Few-shot example ```json // input { "domain": "acme.example" } // output { "company_id": "cs_co_…", "legal_name": "ACME Corporation", "domain": "acme.example", "industry": "Manufacturing", "size_band": "201-500", "employee_range": [201, 500], "hq": { "country": "US", "city": "Austin" }, "sources": [{ "field": "legal_name", "source": "GLEIF", "url": "…" }], "confidence": "high", "generated_at": "…" } ``` ## Matching method (full summary — from live OFAC data, verified 2026-09-26) - **Normalization:** Unicode NFKD fold → strip punctuation → lowercase → transliterate (anyascii). Index BOTH token orderings per name variant (OFAC stores "Putin Vladimir"; without this, Western-order "Vladimir Putin" misses on exact). Also index single-token last-name form and initials variants. - **Alias expansion:** OFAC `akaList` with strong/weak quality categories (ADVANCED XML); EU `NameAlias`. name_kind: primary (AliasType 1403+Primary) / alias_strong (A.K.A./F.K.A./N.K.A.) / alias_weak (LowQuality=true). - **Confidence tiers:** high ≥ 85 · medium ≥ 60 · low ≥ 30. - exact primary (80) / alias_strong (70) / alias_weak (55), no identifiers → medium or low - +15 identifier (DOB/place of birth/nationality/ID number) corroboration, e.g. 70+15=85 → high - fuzzy (Jaro-Winkler ≥ 0.92 or Levenshtein ≤ 2) → low, score 30–55 - **Corroboration:** DOB/place of birth/nationality/ID-doc numbers from OFAC ADVANCED XML (FeatureType 8=Birthdate, 9=Place of Birth, 10=Nationality, 11=Citizenship, 1571=Passport, 1572=SSN, etc.); EU birth dates/IDs from EU v1.1 schema. - **Calibration (live data 2026-09-26):** fuzzy JW floor 0.92 validated sane (~1.3 avg low-tier matches on common full names); common names (JOHN SMITH, LI WEI, MUHAMMAD ALI, …) never reached medium or high — no false positive ever did. All low-tier matches returned, never hidden. Query performance ~110 ms single-threaded. - **Disposition:** no matches → `clear`; ≥1 high/medium → `potential_match`; any high corroborated by an identifier → `review_advised`. ## Data-source provenance | Source | Format / update | License | Status | |---|---|---|---| | OFAC SDN | ADVANCED XML, daily full refresh; live file Publish_Date 2026-09-23, 19,391 parties | Public domain | VERIFIED live 2026-09-26 | | EU consolidated | FSD XML (~15 MB, daily, token via EU Login) | Permitted w/ attribution | PENDING — EU Login account needed (user decision) | | UK FCDO | CSV, OGL v3.0 | Open Government Licence | VERIFIED live 2026-09-26 (6,328 records, Publish_Date 2026-09-21) | | UN list | — | Terms block commercial use | EXCLUDED from v1 (EU regulations cover UN designations) | Every screening response carries `list_date` from the source file. Raw files versioned by publish date; normalized names/AKAs indexed with citations (list name, record_uid, list publish date, source URL, accessed_at). ## Errors and retries - Idempotency: pass `request_id`; retries return the original `screening_id`/`company_id`. - Failures are never billed. 429 carries `X-RateLimit-*` + `Retry-After` headers. - Agent guidance: never retry a failed call in a tight loop — quota covers retry traffic.