# Watchtower — Sanctions & Watchlist Screening API Deterministic sanctions & export-control screening for AI agents. Screen names of people, companies, vessels, and aircraft against: US OFAC (SDN + Consolidated), UN Security Council, EU Financial Sanctions (FSF), UK OFSI, Canada (SEMA), Australia (DFAT), France (DG Trésor), Switzerland (SECO), US export-control, and US SAM procurement/benefit exclusions lists — Commerce/BIS (Entity List, Denied Persons, Unverified, Military End User) and State Dept (ITAR-Debarred, Nonproliferation). Also screens crypto addresses against OFAC's sanctioned-address list. ~229,000 designated parties, refreshed daily from official government sources. Same query + same list snapshot => byte-identical response, every time. Every response carries the list snapshot version (content hash) and algorithm version. ## Pay-per-call for agents (x402, no signup) — the recommended path Watchtower is x402-native. An autonomous agent pays per call in USDC on Base with NO account, NO API key, NO human in the loop: 1. Call the endpoint with no credentials. You get HTTP 402 with an `accepts` array (scheme "exact", network "base"/eip155:8453, USDC asset, amount in atomic units). 2. Retry with a signed payment header (X-PAYMENT for v1, PAYMENT-SIGNATURE for v2). Standard x402 client libraries do this automatically. 3. You get 200 + the result, plus a settlement receipt in the response header. // JS, any x402 client: import { wrapFetchWithPayment, x402Client } from '@x402/fetch'; import { ExactEvmScheme } from '@x402/evm'; const pay = wrapFetchWithPayment(fetch, new x402Client().register('eip155:8453', new ExactEvmScheme(signer))); await pay('https://justin-pacific-exchange-revelation.trycloudflare.com/v1/screen', { method:'POST', headers:{'content-type':'application/json'}, body:JSON.stringify({name:'Vladimir Putin'}) }); ## Alternative: prepaid API key (for teams without crypto) 1. Get a key: curl -X POST https://justin-pacific-exchange-revelation.trycloudflare.com/v1/keys -d '{"note":"my-agent"}' then fund it at /v1/topup (or pay per call via x402, no key) 2. Screen: curl -X POST https://justin-pacific-exchange-revelation.trycloudflare.com/v1/screen -H 'Authorization: Bearer YOUR_KEY' \ -H 'Content-Type: application/json' -d '{"name":"Vladimir Putin"}' 3. Address: curl -X POST https://justin-pacific-exchange-revelation.trycloudflare.com/v1/screen/address -H 'Authorization: Bearer YOUR_KEY' \ -H 'Content-Type: application/json' -d '{"address":"0x0330070FD38Ec3bB94F58FA55D40368271E9e54A"}' Top up the prepaid balance by card via POST https://justin-pacific-exchange-revelation.trycloudflare.com/v1/topup. ## Endpoints - GET|POST /v1/demo — {name} → a real, keyless screen capped to 3 hits. Free, rate-limited (10/hour). Zero-setup way to see a genuine result before getting a key or paying. - POST /v1/keys — create an API key (unfunded). Free to create; fund via /v1/topup or pay per call via x402. - POST /v1/screen — {name, threshold?, limit?, types?, dob?, nationality?, as_of?, snapshot_version?} → {match, matches[], snapshot_version, algorithm}. $0.02. Pass dob/nationality to cut false positives: a candidate whose known DOB or nationality contradicts yours is excluded; a matching one is confirmed and ranked first. Pass as_of (an ISO date) or snapshot_version to screen against the lists AS THEY STOOD on that date — an audit/point-in-time proof. - GET /v1/history — available points-in-time (list versions + the window each was in effect). Free. - POST /v1/screen/address — {address} → {match, result}. $0.01. - POST /v1/screen/batch — {names: [up to 500]} → per-name results. $0.015/name (25% off). - POST /v1/validate — {value, type?} → deterministically validate & normalize an identifier (iban, lei, isin, bic, vat, card, eth, btc, cusip, sedol, imei, email, domain, phone, uuid) by its checksum/format. Type auto-detected if omitted. $0.005/call. Batch: POST /v1/validate/batch {items:[…]} $0.003/item. - POST /v1/jurisdiction — {country} → FATF + EU high-risk AML classification of a country (call_for_action / increased_monitoring / not_listed) + risk_level. ISO alpha-2 or country name. Dated + sourced. $0.005/call. Batch: /v1/jurisdiction/batch. - POST /v1/scan — {text} → detect & redact PII and secrets (emails, cards, IBANs, SSNs, IPs, API keys, private keys, JWTs, tokens). Deterministic; checksum-validated; secrets returned masked. $0.005/call. - POST /v1/lei — {lei} → resolve a Legal Entity Identifier to its official GLEIF record (legal name, status, jurisdiction, country). LEI checksum-validated first; reflects GLEIF's live registry (CC0). $0.01/call. - POST /v1/lei/search — {name, limit?} → find candidate LEIs by company legal name via GLEIF. $0.01/call. - POST /v1/kyb — {name | lei} → ONE-CALL KYB: resolve a company's GLEIF legal identity AND screen it against sanctions + exclusion lists. Returns {entity, lei_candidates, screening}. $0.02/call. - POST /v1/watch — {name, webhook_url, days (1-90)} → monitor a name; your webhook gets POSTed whenever its match set changes as sanctions lists update. $0.01/day, prepaid. GET /v1/watch lists yours; DELETE /v1/watch/:id cancels. watch_changed events include added[] (new matching entries, full records) and removed[] (uids no longer matching) so you know exactly what changed. Failed webhook deliveries are retried on the next sweep — alerts are never silently dropped. - GET /v1/entity/:uid — full record (aliases, DOB, nationality, programs) for any uid returned by a screen. Free. - GET /v1/balance — remaining credit. Free. - POST /v1/topup — Stripe checkout link for credit packs. ## Paying with x402 (no signup needed) Both /v1/screen endpoints accept x402 v2 payments: call without credentials, read the 402 response's `accepts` array (USDC on Base, eip155:8453), retry with an X-PAYMENT header. Standard x402 client libraries handle this automatically. Settlement receipt is returned in the X-PAYMENT-RESPONSE header. - GET /v1/lists — list versions, source hashes, per-source freshness, pricing. Free. - GET /uptime — public status page (health + data freshness). Free. - POST /v1/verify — {name, result_hash?} → reproduce a screening receipt hash. Free, no matches revealed. - GET /openapi.json — machine-readable spec. - GET /docs — human-readable quickstart + full API reference (HTML). - POST /mcp — MCP (Model Context Protocol) streamable-HTTP endpoint exposing tools: create_api_key, screen_name, screen_names_batch, screen_crypto_address, validate_identifier, check_jurisdiction, scan_text, resolve_lei, search_lei_by_name, kyb_check, create_watch, get_screening_info. Point any MCP client at https://justin-pacific-exchange-revelation.trycloudflare.com/mcp — no auth handshake; keys are tool parameters. ## Matching semantics (algorithm wt-match-5) - Case-, punctuation-, and diacritic-insensitive; token-order-insensitive. - Typo-tolerant (Jaro-Winkler + trigram blend). - Subset detection: "Vladmir Putin" matches "PUTIN, Vladimir Vladimirovich". - Generic tokens (Inc, Company, Ltd...) carry reduced weight; at least two distinctive tokens are required for a subset match. - threshold (default 0.82): raise to 0.9+ for fewer, stronger matches. - Deterministic ordering: score desc, then uid asc. Lists refresh daily from official sources (Treasury/OFAC, UN). Not legal advice; informational screening only.