DEV Community

PublicAML
PublicAML

Posted on Originally published at publicaml.org

Free Crypto AML / KYT Address Screening in Python (No API Key)

Free Crypto AML / KYT Address Screening in Python (No API Key)

Need a quick Know Your Transaction (KYT) / AML gate in a bot, ETL job, or OTC ops script? You can enrich a wallet address in one HTTP call — no vendor signup for the free tier.

Endpoint: POST https://intelapi.publicaml.org/v1/enrich

Product: https://publicaml.org/

Minimal client

import requests

ENRICH_URL = "https://intelapi.publicaml.org/v1/enrich"

def enrich_address(wallet_address: str, chain: str = "ETH") -> dict:
    r = requests.post(
        ENRICH_URL,
        json={"addresses": [{"wallet_address": wallet_address, "chain": chain}]},
        timeout=30,
    )
    r.raise_for_status()
    entities = r.json().get("entities") or []
    if not entities:
        raise RuntimeError("empty enrich response")
    return entities[0]


def decide(entity: dict) -> str:
    score = float(entity.get("aml_score") or 0)
    if score >= 70:
        return "block"
    if score >= 40:
        return "warn"
    return "allow"


if __name__ == "__main__":
    e = enrich_address("0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "ETH")
    print(
        {
            "decision": decide(e),
            "aml_score": e.get("aml_score"),
            "label": e.get("label"),
            "category": e.get("category"),
            "chain": e.get("chain"),
        }
    )
Enter fullscreen mode Exit fullscreen mode

Example shape of useful fields:

  • aml_score — 0–100 risk score
  • label / category — entity tagging (e.g. CEX name)
  • aml_score_breakdown — exposure / propagated sources
  • behavioral_signals — heuristics like cross-chain hopping
  • counterparties — recent interaction context

Batch a small list

def enrich_many(pairs: list[tuple[str, str]]) -> list[dict]:
    """pairs = [(address, chain), ...] — keep batches modest for free-tier rate limits."""
    r = requests.post(
        ENRICH_URL,
        json={
            "addresses": [
                {"wallet_address": addr, "chain": chain} for addr, chain in pairs
            ]
        },
        timeout=60,
    )
    r.raise_for_status()
    return r.json()["entities"]
Enter fullscreen mode Exit fullscreen mode

Free tier guidance from the product site: about 1k requests/hour. Cache stable labels aggressively (CEX deposit addresses do not change hourly).

Tiny CLI for ops

python - <<'PY'
import sys, json, requests
addr, chain = sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else "ETH"
e = requests.post(
    "https://intelapi.publicaml.org/v1/enrich",
    json={"addresses": [{"wallet_address": addr, "chain": chain}]},
    timeout=30,
).json()["entities"][0]
print(json.dumps({
    "score": e["aml_score"],
    "label": e.get("label"),
    "category": e.get("category"),
}, indent=2))
PY
Enter fullscreen mode Exit fullscreen mode

Where this fits

  • Telegram / Discord bots that reply with risk before users tip
  • OTC deal intake: paste counterparty → auto score
  • Nightly jobs that re-score watchlists

This is address KYT, not full KYC. Pair it with your own policies for custody and fiat rails.

More at publicaml.org — free forever for this public enrich path.

Top comments (0)