Infrastructure optimized for growth
35+
Networks Supported
25ms
Avg Processing Time
25,000+ rq/s
Enterprise-ready
100+ TB
of Big Data
Access to full transaction data on all transactions & addresses
Retrieve blockchain data, balances, and transactions
Detailed blockchain history and transaction data for any address.
Full smart contracts metadata, including token symbols & token names
Access to full transaction data on all transactions & addresses
Get live crypto prices, exchange rates, supply and token contracts across protocols via one REST API.
Real-time notifications for events on top blockchains. Response under 100ms.
AML address screening across 35+ networks
Sync and manage HD wallets, keys and addresses
Local signing for EVM, UTXO, Tron, XRP, Kaspa and Solana
Precise blockchain transaction fee estimates based on transaction priority
Broadcast and verify transactions with real-time monitoring
Prepare EVM transactions, including token transfers
Test EVM transactions, optimize gas fees and identify security flaws
Pay for HTTP APIs, or charge for your own, in USDC stablecoin over the open x402 protocol — non-custodial, on-chain settlement.
MCP servers, CLI and skills for AI agents
Dedicated nodes infrastructure for leading blockchains using JSON-RPC
Address validation, encoding & cryptographic tasks optimizations
Shared node infrastructure for top blockchains using JSON-RPC.
TL;DR: When an exploiter moves stolen funds toward a mixer, exchange and custody teams can subscribe to address webhooks on the exploiter's wallets. They then screen every inbound deposit with a GET call to /aml/transactions/{blockchain}/{transactionHash} and /aml/addresses/{address}. Any deposit that returns isFlagged: true or a high riskBand goes into a review queue instead of a user balance. This post walks through the subscription setup, the screening calls with real responses, and the decision logic for holding a credit.
Decrypt reported another exploit in which the attacker routed stolen Ethereum into Tornado Cash. The report covers the movement itself. It does not cover what happens next for an exchange operations engineer or a custody platform's compliance lead.
Funds that enter a mixer come out somewhere. Often they come out through fresh addresses, and some of those addresses eventually send to a deposit address that you issued to a customer. If your crediting pipeline only checks confirmations, that deposit lands in a user balance and can be withdrawn before anyone looks at it.
The build problem has two halves:
Our earlier post, Wallet Drain Detection: Address Webhooks for Custody Teams, covers drains from your own wallets. This post covers the other direction: tainted funds arriving at your wallets.
X-API-Key header on every request.Blockchain Events lets you register an address and receive a callback for transactions involving it. For an exploiter wallet on Ethereum, create two subscriptions:
POST /blockchain-events/{blockchain}/{network}/address-coins-transactions-unconfirmed. This fires when a transaction appears in the mempool, before confirmation.POST /blockchain-events/{blockchain}/{network}/address-tokens-transactions-confirmed. This catches ERC-20 (Ethereum token standard) movements such as stablecoin transfers that attackers swap into before mixing.Each subscription returns a referenceId. Store it alongside the watchlist entry so you can list subscriptions with GET /blockchain-events/{blockchain}/{network} and remove stale ones with DELETE /blockchain-events/{blockchain}/{network}/{referenceId}. The exact request body is documented in the monitor addresses with webhooks guide. Callbacks are delivered in under 100 milliseconds from detection.
When a callback arrives for an exploiter address, do two things. Alert the on-call compliance channel. Then add every counterparty address in that transaction to an internal heightened-risk list for the incident.
Your existing deposit webhooks already tell you when funds hit a customer address. Insert one screening step between detection and credit. Start with the transaction's counterparties:
GET https://rest.cryptoapis.io/aml/transactions/ethereum/{transactionHash}
X-API-Key: <your key>
{"apiVersion":"2024-12-12","requestId":"6aa3c4a32f6f68835e3dc003","data":{"item":{
"isFlagged":false,"riskScore":0,"riskBand":"low","flaggedAddresses":[]}}}
Then screen the sending address directly through Verify Address. The address goes in the path. There is no request body.
GET https://rest.cryptoapis.io/aml/addresses/{address}
X-API-Key: <your key>
A flagged result looks like this:
{"apiVersion":"2024-12-12","requestId":"6aa3c4642f6f68835e3dbd6c","data":{"item":{
"blockchain":"ethereum","isFlagged":true,"riskScore":80,"riskBand":"high",
"severity":"high","categories":["malicious","sanctions"],
"sources":[{"provider":"graphsense","label":"tornado.cash","categories":["malicious"],
"severity":"high","listingTimestamp":1784210009,"sanctionPrograms":[]}],
"attribution":{"entity":"tornado-cash","type":"mixer","label":"Tornado.Cash: Donate"},
"listingTimestamp":1784210009}}}
A clean result omits optional fields entirely:
{"apiVersion":"2024-12-12","requestId":"6aa3c48d2f6f68835e3dbf05","data":{"item":{
"isFlagged":false,"riskScore":0,"riskBand":"low","severity":"none",
"categories":[],"sources":[]}}}
Mixer outputs usually pass through one or more fresh addresses before reaching an exchange. Direct screening of the last hop can come back clean. For deposits above your review threshold, or from senders on the incident's heightened-risk list, call GET /aml/exposure/{blockchain}/{address} to assess indirect exposure. Call GET /aml/exposure/{blockchain}/{address}/paths when a reviewer needs to see the route funds took. Consult the API reference for the response fields of these two endpoints. Do not assume they match the address response.
item = response.data.item
hold = (
item.isFlagged == true
or item.riskBand in ["high", "severe"]
or len(txItem.flaggedAddresses) > 0
or sender in incident_heightened_risk_list
)
if hold:
ledger.set_status(deposit_id, "pending_review")
review_queue.push(deposit_id, item.categories, item.get("attribution"))
else:
ledger.credit(deposit_id)
Use item.get("attribution"), not direct access. On clean responses the field does not exist.
listingTimestamp tells you when a source labeled the address. Your own watchlist and heightened-risk list cover the gap until labels propagate. Re-screen held and recently credited deposits once labels update.riskBand takes the values low, medium, high, and severe. Decide explicitly what medium does in your pipeline. A silent default to credit is the usual mistake.referenceId so a retry does not create two review cases or two credits.Exploit response comes down to two calls placed correctly: a webhook on the attacker's wallet and an AML check before every credit. Blockchain Events handles the first, and Verify Address handles the second across 20+ chains. Teams running exchanges and custody providers can start on the free tier with no credit card, then size production volume on the pricing page.
Networks Supported
Avg Processing Time
Enterprise-ready
of Big Data