API & MCP
Wallet Reputation API
The Wallet Reputation API lets exchanges, DeFi protocols, compliance teams and AI agents query a wallet's risk score, entity attribution and sanctions status programmatically. It reads ChainHint's own database of 48M+ attributed addresses instead of tracing the chain, which is why it suits real-time screening at deposit, withdrawal or payment time.
Free tier — no key, no signup
Call the endpoint with no credentials and you get 3 checks per IP per 24 hours. The response carries "tier": "free" and standardX-RateLimit-Limit / Remaining / Reset headers.
curl "https://kjiwfwymnuzxriokhcjk.supabase.co/functions/v1/wallet-reputation?address=0x47666fab8bd0ac7003bce3f5c3585383f09486e2&chain=ethereum"API key — 10,000 requests per day
Agency plan keys start with ch_live_ and are created in Settings → API Keys (up to 5 per account). Pass the key as a Bearer token or in X-Api-Key.
curl "https://kjiwfwymnuzxriokhcjk.supabase.co/functions/v1/wallet-reputation?address=0x47666fab8bd0ac7003bce3f5c3585383f09486e2&chain=ethereum" \
-H "Authorization: Bearer ch_live_YOUR_KEY"Response
{
"address": "0x47666fab8bd0ac7003bce3f5c3585383f09486e2",
"chain": "ethereum",
"risk_score": 85,
"risk_level": "critical",
"category": "hacker",
"entity": {
"name": "Bybit Hack Exploiter",
"category": "hacker",
"subcategory": null,
"verified": false,
"attribution_unconfirmed": false,
"operating_status": null,
"actor": null,
"freeze_requestable": false,
"contact_source_verified": null,
"contact_note": null,
"label_trust": "verified",
"heuristic_flag": null
},
"labels": ["Hacker/Exploiter", "Bybit Hack Exploiter"],
"sanctions": { "hit": false, "complete": true },
"screen_status": { "complete": true, "incomplete": [], "note": null },
"restricted_assets": [],
"agent": null,
"evidence": [],
"held_evidence": [],
"is_contract": false,
"found_in_db": true,
"sources": ["chainhint:manual"],
"checked_at": "2026-09-02T16:20:00.000Z",
"tier": "free"
}risk_level is one of clean · low · medium · high · critical · sanctioned · unknown — on the same 81 / 61 / 41 / 21 ladder as the address page and the Telegram bot, and risk_label carries the words they print (Low Risk · Moderate · Elevated · High Risk · Critical). unknown (with risk_score: null) means a screen that could have found something did not answer, and there was nothing else to score. It is a refusal, not a clearance. screen_status says which — { complete, incomplete[], note }, where incomplete holds any of sanctions · restricted_assets · address_record and note is one sentence naming the screen and the reason. sanctions.complete is the same fact for the sanctions screen alone, and sanctions.hit is null — not false — when that screen did not finish. A score the screens already raised is still printed: only a zero is refused.restricted_assets lists crypto-assets the wallet holds that are themselves prohibited (EU Annex LIII — A7A5), matched by contract and valued at par, each with a summary such as “holds EU-restricted asset A7A5 (Reg. (EU) 2025/2033 Art. 5ba)”; [] = checked, none; null = the chain could not be read. A holding is a property of the asset, never a sanctions hit on the holder. risk_score is the verdict the address page printed, outbound exposure included, as of risk_as_of — at most 24 hours old and from the current engine, otherwise recomputed. exposure_checked: false means outbound counterparties were not read, so the score is the known floor, not a full answer. agent is the agent-infrastructure overlay: { is_agent, kind, framework, label, summary, source_url } when the address is in ChainHint's registry of known autonomous-agent infrastructure — kind is one of launchpad · factory · router · facilitator · known_agent (agent-token launchpads, deployer factories, routers, payment facilitators, known agent wallets; is_agent is true only for known_agent) — else null. It is a registry fact you can check against the named contract at source_url, not a behavioural classification, and it does not move risk_score. evidence lists what each source actually establishes about the address — one item per finding, { class, authority, subject, document_ref, document_url, document_date, legal_basis, token, chain, first_seen_at }, where class is one of sanctions_designation · law_enforcement_attribution · issuer_freeze · national_seizure_order · industry_blocklist · analyst_verified. Only sanctions_designation sets sanctions.hit and the level sanctioned; an FBI attribution, an address frozen by Tether or Circle, or a national seizure order is not a sanctions designation — each lands in the high band and says so. [] = none; null = could not be read. held_evidence lists findings a third-party dataset reports that ChainHint has not yet read at the source — { class, authority, subject, reported_via, held_since, note }. They are a note, not evidence: they do not move risk_score, risk_level or sanctions.hit until reviewed. [] = none; null = could not be read. is_contract is boolean | null, and null means not recorded — never “not a contract”: this endpoint reads the stored address record and makes no live contract call, so null is “we hold no value for this address”. On the richer address-lookup endpoint (the lookup_address MCP tool) the same field is accompanied by contract_status — ok · unavailable · unsupported, the same vocabulary as goplus_status — where unavailable is “the provider refused the read” and unsupported is “this chain has no contract read here” (TRON, Solana). Both are is_contract: null, and neither claims anything about the address; only false with contract_status: "ok" says “measured, and it is not a contract”. entity.label_trust is verified · attributed · unverified · heuristic: only a verified label (a designation, law-enforcement attribution, seizure order, issuer freeze or analyst verification on the address — no entity source verifies by itself) floors or buckets other addresses; an attributed label (a named clustering / tracing source without evidence) carries entity.attribution = { method, publisher, note } — method is clustering · hackscan_trace · victim_report · public_label_registry — and is shown and counted, never scored. entity.heuristic_flag is { detector, status, note } when the label is a heuristic detector flag (Forta) — status is unverified · pending_review, the note reads “Flagged by a heuristic detector (Forta), unverified — not scored.” — else null; it never moves risk_score. When the free quota is used up, an autonomous agent can pay per call via x402: the endpoint answers 402 Payment Required with the terms — $0.10 USDC on Base — the agent re-requests with a signed X-PAYMENT header (EIP-3009), the payment is settled through a facilitator and the check runs. One payment, one call, no signup. Without a payment it falls back to 429 with anupgrade link and reset_at. Full reference, error shapes and Python / Node examples: WALLET_REPUTATION_API.md.
| Access | Limit | Who |
|---|---|---|
| AccessNo key | Limit3 checks / IP / 24h | WhoAnyone — try it, wire it into an agent |
| AccessPay-per-call (x402) | Limit$0.10 USDC / call on Base, no signup | WhoAI agents past the free tier |
| AccessAgency key | Limit10,000 / day per key, 100 / min burst | WhoExchanges, protocols, compliance teams |
| AccessEnterprise | LimitCustom | WhoContact us |
MCP Server
chainhint-mcp is an MCP (Model Context Protocol) server that gives Claude Desktop, Claude Code, Cursor or any MCP-compatible agent three ChainHint tools. It runs straight from npm and needs no API key to start — every tool has a free allowance.
Available Tools
| Tool | What it returns | Without a key | With an Agency key |
|---|---|---|---|
| Toolcheck_wallet_risk | What it returnsRisk score & level, entity, labels, sanctions hit — fast, database-only | Without a key3 / day | With an Agency key10,000 / day |
| Toollookup_address | What it returnsDeep report: risk factors, GoPlus flags, counterparty exposure by category, balance, tx count | Without a key10 / day | With an Agency key100 / hour |
| Toolget_trace_status | What it returnsPublic hack incident: loss, hops, where funds went (exchange / mixer / bridge / defi), attacker exposure | Without a keyUnlimited | With an Agency keyUnlimited |
lookup_address carries the same verdict vocabulary as the REST endpoint above, in risk_verdict — { score, level, screen_status }, where score is null and level unknown when a screen that could have found something did not answer. Its older risk block is deprecated, removal 2026-12-31: it used to print 0 · clean in that case and is now null there instead, so risk.score throws rather than reading as a zero. Branch on risk_verdict, or on risk_status, not on it.
Setup (Claude Desktop / Cursor / Claude Code)
// Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json
// Cursor: .cursor/mcp.json Claude Code: claude mcp add chainhint -- npx -y chainhint-mcp
{
"mcpServers": {
"chainhint": {
"command": "npx",
"args": ["-y", "chainhint-mcp"]
}
}
}To lift the free limits add "env": { "CHAINHINT_API_KEY": "ch_live_…" } to the entry. Get a key from Settings → API Keys (Agency plan).
What the agent sees
Ask "Is 0x47666fab… a known hacker?" and the model calls check_wallet_risk:
## Wallet Risk Report: 0x47666f...9486e2
**Chain:** ethereum
**Risk Score:** 85/100 — **CRITICAL**
**Entity:** Bybit Hack Exploiter (hacker)
**Labels:** Hacker/Exploiter, Bybit Hack Exploiter
**In ChainHint DB:** yes (sources: chainhint:manual)
Free tier: 2 of 3 checks left today — set CHAINHINT_API_KEY for 10,000/day.Ask "Where did the CoinEx hack funds go?" and it calls get_trace_status:
## Fund Trace: CoinEx
**Status:** TRACED · **Loss:** $55.00M · **Date:** 2023-09-12
### Trace Graph
**Hops traced:** 4 · **Addresses:** 124 · **Transfers:** 244
### Where the funds went (122 endpoints, $12.32M tracked)
- **unknown**: $10.21M (82.9%) across 46 address(es) — Forta: Attacker, Cult DAO
- **defi**: $2.09M (17.0%) across 72 address(es) — uniswap, Uniswap V3, Uniswap V2
- **exchange**: $19.9K (0.2%) across 4 address(es) — KuCoin deposit, OKX deposit
🔗 View full trace: https://chainhint.com/incident/9a1964d8-…Installation
No install step — the config above runs the server from npm via npx. Source: github.com/seomarlboro/chainhint-mcp (MIT). To build locally:
git clone https://github.com/seomarlboro/chainhint-mcp
cd chainhint-mcp
npm install && npm run build