DEV Community

PublicAML
PublicAML

Posted on Originally published at publicaml.org

Build a Free Telegram Bot for Crypto Wallet AML / KYT Checks

Build a Free Telegram Bot for Crypto Wallet AML / KYT Checks

Support channels and OTC chats drown in “is this address safe?” messages. A bot that replies with a KYT / AML score in under a second is a force multiplier — and you can wire it with a free enrich API (no key) from PublicAML.

There is already an official bot at @publicaml. This article shows how to build your own branded checker for a community or desk.

Prerequisites

  • Python 3.10+
  • A bot token from @BotFather
  • pip install pyTelegramBotAPI requests (or python-telegram-bot — same idea)

Core: enrich helper

import os
import re
import requests

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

EVM_RE = re.compile(r"^0x[a-fA-F0-9]{40}$")
# simplistic BTC bech32 / legacy sniff — extend as needed
BTC_RE = re.compile(r"^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,62}$")


def detect_chain(addr: str) -> str | None:
    if EVM_RE.match(addr):
        return "ETH"
    if BTC_RE.match(addr):
        return "BTC"
    return None


def kyt(addr: str, chain: str) -> dict:
    r = requests.post(
        ENRICH,
        json={"addresses": [{"wallet_address": addr, "chain": chain}]},
        timeout=30,
    )
    r.raise_for_status()
    return r.json()["entities"][0]


def format_report(e: dict) -> str:
    score = e.get("aml_score")
    label = e.get("label") or ""
    category = e.get("category") or ""
    if score is None:
        return "No score returned."
    if score >= 70:
        verdict = "HIGH RISK — do not send blindly"
    elif score >= 40:
        verdict = "MEDIUM — review carefully"
    else:
        verdict = "LOW — still DYOR"
    return (
        f"*KYT / AML report*\n"
        f"Score: `{score}`\n"
        f"Label: `{label}`\n"
        f"Category: `{category}`\n"
        f"Chain: `{e.get('chain')}`\n"
        f"Verdict: {verdict}\n"
        f"_Powered by PublicAML — https://publicaml.org/_"
    )
Enter fullscreen mode Exit fullscreen mode

Bot handlers (pyTelegramBotAPI)

import telebot

bot = telebot.TeleBot(os.environ["TELEGRAM_BOT_TOKEN"])


@bot.message_handler(commands=["start", "help"])
def help_cmd(m):
    bot.reply_to(
        m,
        "Send /check <address> for a free KYT/AML screen.\n"
        "Example: /check 0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
    )


@bot.message_handler(commands=["check"])
def check_cmd(m):
    parts = (m.text or "").split(maxsplit=1)
    if len(parts) < 2:
        bot.reply_to(m, "Usage: /check <wallet_address>")
        return
    addr = parts[1].strip()
    chain = detect_chain(addr)
    if not chain:
        bot.reply_to(m, "Could not detect chain (supported demo: ETH / BTC).")
        return
    try:
        entity = kyt(addr, chain)
        bot.reply_to(m, format_report(entity), parse_mode="Markdown")
    except Exception as exc:
        bot.reply_to(m, f"Enrich failed: {exc}")


bot.infinity_polling()
Enter fullscreen mode Exit fullscreen mode

Run:

export TELEGRAM_BOT_TOKEN=123:ABC
python bot.py
Enter fullscreen mode Exit fullscreen mode

Production notes

  • Respect the free-tier rate limit (~1k/h): debounce per chat, cache identical addresses for 5–15 minutes.
  • Log only hashes/prefixes if you store history — addresses are sensitive.
  • For desks, add an allowlist of staff chat IDs.
  • Extend detect_chain for TRON / others as your product supports them.

Why bots convert search traffic

People Google “check wallet AML free” and “KYT telegram bot”. Pair this tutorial with the live product bot and the REST API so readers can graduate from chat → API → wallet integration.

Ship it, pin /check in your community, and stop answering the same risk question by hand.

Top comments (0)