Verify a payee

Use POST /v1/verify/payee before initiating a payment. v1.1 enriches payee checks with public, read-only sources — sanctions, entity identifiers, offshore-leaks context, and adverse media — on top of format detection and the reputation graph.

curl https://api.farofinance.app/v1/verify/payee \
  -H "Authorization: Bearer $FARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"value": "Apple Inc."}'

What Faro calls (v1.1)

Checks run in parallel. One failing integration is logged and skipped; the rest still contribute signals.

SourceWhat it addsTypical signals
Format detectionRecognizes the payment rail (UPI, Venmo, IBAN, …) — transparency onlypayee_format (info)
OpenSanctionsGlobal sanctions, PEP, and watchlist name matchingsanctions_match, sanctions_possible_match, sanctions_clean
GLEIFLegal Entity Identifier lookup for business / entity nameslei_verified, lei_lapsed
ICIJ OffshoreLeaks (via OpenSanctions)Offshore and shell-network context for entity names — queries both LegalEntity and Company schemas; not evidence of wrongdoing on its ownoffshore_leaks_match
GDELTGlobal adverse-media mentions (fraud, scam, default); may include a short LLM summaryadverse_media
Reputation graphPrior verdicts and reports on this payee nodereputation_reports, reputation_prior_critical
LLM (tier 3 only)Mule-account and scam patterns when deterministic tiers are inconclusivellm_assessment

OffshoreLeaks and GDELT are skipped for payment handles (UPI IDs, Venmo, etc.) — they apply to entity / business names, not @handles or VPAs.

Global rails

Faro recognizes payee handles across payment networks worldwide and names the rail in the payee_format signal:

RailExample
UPI VPA (India)ramesh@okaxis
Venmo (US)@jane-doe-99
Cash App (US)$JaneDoe
Pix random key (Brazil)123e4567-e89b-12d3-a456-426614174000
IBAN (Europe / global)GB82WEST12345698765432
Email / phone rails (Zelle, PayPal, PayID, PromptPay, PayNow…)jane@example.com, +5511998765432

Example — enriched business name

A well-known company with a verified LEI may return 🟢 with signals from GLEIF and clean sanctions screening:

{
  "verdict": "green",
  "confidence": 0.85,
  "reason": "Legal entity identifier verified for this business name.",
  "recommended_action": "allow",
  "signals": [
    { "name": "lei_verified", "severity": "low", "source": "gleif", "detail": "..." },
    { "name": "sanctions_clean", "severity": "info", "source": "opensanctions", "detail": "..." }
  ]
}

OffshoreLeaks troubleshooting

OffshoreLeaks uses your same OPENSANCTIONS_API_KEY as sanctions — there is no separate dashboard connection. Faro scopes the OpenSanctions match API with include_dataset=ext_icij_offshoreleaks and queries both LegalEntity and Company in one call, then takes the best-scoring hit.

Setup checklist

  1. Create an API key at OpenSanctions.
  2. Set OPENSANCTIONS_API_KEY in .env locally and on Render (faro-api, faro-mcp).
  3. Redeploy after changing env vars.
  4. Test with a business / legal name — not a UPI ID, Venmo handle, or IBAN.

Optional tuning:

# OPENSANCTIONS_OFFSHORELEAKS_DATASET=ext_icij_offshoreleaks   # default
# OFFSHORE_LEAKS_MATCH_THRESHOLD=0.75                          # default

Verify locally (faro_AI repo)

uv run python scripts/verify_offshore_leaks.py "Your Test Company Name"

Prints HTTP status, candidates per schema, and whether Faro would emit offshore_leaks_match.

Direct OpenSanctions probe

curl -X POST "https://api.opensanctions.org/match/default?include_dataset=ext_icij_offshoreleaks" \
  -H "Authorization: ApiKey $OPENSANCTIONS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "queries": {
      "legal_entity": { "schema": "LegalEntity", "properties": { "name": ["TEST NAME"] } },
      "company": { "schema": "Company", "properties": { "name": ["TEST NAME"] } }
    }
  }'
HTTPMeaning
200 + empty resultsAPI works; no match in the scoped dataset (common)
401Invalid or missing API key
403Plan may not include API access — see dataset terms

Why you often see no offshore_leaks_match signal

ReasonWhat to do
Payee is a payment handle (VPA, @venmo, IBAN, …)Expected — use a legal entity / company name instead
OPENSANCTIONS_API_KEY unsetSet key; check API logs for skipping OffshoreLeaks check
Name not in searchable subsetOpenSanctions exposes ~1k OffshoreLeaks entities linked to their main graph, not the full ICIJ dump. Search opensanctions.org filtered to ICIJ Offshore Leaks and test an exact caption
Score below thresholdLower OFFSHORE_LEAKS_MATCH_THRESHOLD (default 0.75) if you accept noisier matches
OpenSanctions outage / rate limitCheck fails open — other payee signals still return; retry later

A missing OffshoreLeaks signal is neutral, not proof the integration is broken. Look for offshore_leaks_match with severity: medium and a detail that includes "not evidence of wrongdoing" when a match fires.

Know a bad payee Faro missed, or a false positive? Use POST /v1/reports.

See the API reference for the full schema.