How to check crypto AML in code — free API (Python, JS, Go, cURL)

A free, keyless API to screen a crypto address or transaction for AML/KYT risk — sanctions, mixers, scam and hack exposure. One POST request, no API key, no signup. Copy the example for your language and ship it.

Full API reference →

Trusted by crypto users worldwide • Bitcoin, Ethereum, BNB Chain and TRON

One request — no API key

The enrich endpoint takes an address and chain and returns a risk score, category, sanctions status and counterparties. No key is required to start; an optional key only raises the rate limit.

Request — cURL
curl -sS -X POST 'https://intelapi.publicaml.org/v1/enrich' \
  -H 'Content-Type: application/json' \
  -d '{
    "addresses": [{ "wallet_address": "0x...", "chain": "ETH" }],
    "include": ["aml_score", "category"]
  }'
Response
{
  "entities": [{
    "wallet_address": "0x...",
    "chain": "ETH",
    "aml_score": 87,
    "category": "hack",
    "sanctioned": false
  }]
}

The same check in your language

Python (requests)
import requests

def aml_check(address, chain="ETH"):
    r = requests.post(
        "https://intelapi.publicaml.org/v1/enrich",
        json={
            "addresses": [{"wallet_address": address, "chain": chain}],
            "include": ["aml_score", "category"],
        },
        timeout=10,
    )
    r.raise_for_status()
    return r.json()["entities"][0]

e = aml_check("0x...")
print(e["aml_score"], e["category"], e["sanctioned"])
JavaScript / TypeScript (fetch)
// Node 18+ / browsers — no API key needed
async function amlCheck(address, chain = 'ETH') {
  const r = await fetch('https://intelapi.publicaml.org/v1/enrich', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      addresses: [{ wallet_address: address, chain }],
      include: ['aml_score', 'category'],
    }),
  })
  if (!r.ok) throw new Error('enrich failed: ' + r.status)
  const { entities } = await r.json()
  return entities[0]
}

const e = await amlCheck('0x...')
console.log(e.aml_score, e.category, e.sanctioned)
Go (net/http)
package main

import (
	"bytes"
	"encoding/json"
	"net/http"
)

func amlCheck(address, chain string) (map[string]any, error) {
	body, _ := json.Marshal(map[string]any{
		"addresses": []map[string]string{{"wallet_address": address, "chain": chain}},
		"include":   []string{"aml_score", "category"},
	})
	resp, err := http.Post("https://intelapi.publicaml.org/v1/enrich",
		"application/json", bytes.NewReader(body))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var out struct{ Entities []map[string]any }
	json.NewDecoder(resp.Body).Decode(&out)
	return out.Entities[0], nil
}

More examples and SDKs on GitHub: github.com/publicaml.

Pattern: block risky addresses before a transaction

The point of a pre-send check is to decline rather than unwind. Screen the recipient before you sign or accept funds and reject anything sanctioned or above your risk threshold.

Pre-transaction gate — JS/TS
// Pre-transaction gate: block risky recipients before you send.
async function assertClean(address, chain = 'TRON') {
  const e = await amlCheck(address, chain)
  if (e.sanctioned || (e.aml_score ?? 0) >= 75) {
    throw new Error('High AML risk (' + e.category + ') — transfer blocked')
  }
}

await assertClean(recipient) // throws if the address is risky

aml_score is 0–100 (higher = riskier). category is the entity type (exchange, mixer, hack, scam, sanction…). Treat sanctioned: true as an override regardless of score. It is a risk signal, not a legal compliance guarantee — keep your own KYC/AML process alongside it.

Frequently asked questions

Is there a free API to check crypto AML / KYT?

Yes. PublicAML exposes a public enrich endpoint that needs no API key: POST https://intelapi.publicaml.org/v1/enrich with the address and chain, and you get back an aml_score (0–100), category, sanctions status and counterparties. It is a non-profit, so there is no paid tier — an optional key only raises the rate limit.

How do I check a crypto address for AML risk in Python?

POST the address and chain to the enrich endpoint with the requests library and read entities[0].aml_score / category / sanctioned. See the Python example on the page — no key or account is required to start.

Which chains can I screen?

Bitcoin, Ethereum, BNB Chain and TRON. Pass the chain per address ("BTC", "ETH", "BSC", "TRON"). An ERC20 and a BEP20 address look identical, so send the correct chain for the network you are on.

How do I block sanctioned or high-risk addresses before a transaction?

Call the API before you sign or accept funds and reject the transfer when sanctioned is true or aml_score is above your threshold (75 is a common cut-off). The pre-transaction gate example on the page shows the pattern.

Do I need to handle rate limits?

For low volume, no — the public endpoint works without a key. For higher throughput, request an optional key to raise the limit and add simple retry/back-off on HTTP 429.

Start screening — free, no key

Send one request and get a risk score back. No account, no card, no API key.