Wallet screening and on-chain risk checks with one API: what the Triport Intelligence API does

Most teams that screen wallets glue together a label source, a risk score, an explorer scrape and a simulator. Here is what it looks like when all of that sits behind one key, and where it still stops.

Endpoints and plans for the networks in this post: Ethereum RPC endpoint · Solana RPC endpoint.

A deposit arrives from an address you have never seen. Before you credit it, someone on your team wants to know three things: who this address is, whether it has touched anything you are not allowed to touch, and where its money came from. A few weeks later a different team ships a wallet and wants to warn users before they sign an unlimited approve to a contract nobody has heard of.

Both teams usually end up building the same pile: a label list from one place, a risk score from another, an explorer page scraped for the deployer, and a simulator they host themselves. Each piece has its own key, its own rate limit and its own idea of what "no data" means.

On 2026-11-06 we released the Triport Intelligence API, our security and compliance intelligence layer, under https://triport.io/v1/intelligence/. It puts those questions behind the same API key you already use for Ethereum RPC. This post walks through what it answers, with requests you can run, and is explicit about where it stops.

What is in the release

Eighteen methods are live, on nineteen routes (address labels has a single and a batch form). Grouped by the job they do:

JobMethods
Who is this address?Address labels, address labels (batch), implementation labels
Is it risky?Address risk score, funder risk
Is this spender safe to approve?Token approval risk
Where did the money go?Fund flow graph
Who deployed this contract?Contract creation and deployer
What is this contract and this call?Verification metadata, storage variable list, function signature lookup, selector lookup, calldata decode
What would this transaction do?Transaction simulation (read-only)
ContextSearch, token markets, latest block, conservative block, base fee estimate

The full route list, with the chains each one accepts, is in the method reference.

Access is simple on purpose. The API is part of the Business and Enterprise plans, with no separate price and no per-call weight. Business gets 30 requests per second in the intelligence category, Enterprise 150, both with a short burst of twice that. The key needs the intelligence:read scope; keys created with the default all-networks scope already have it. Batch endpoints count each address as one request, so a batch of 200 labels on Business takes several seconds of budget, not one.

Chains: Ethereum for every chain-specific method. Address labels also accept Solana and Avalanche C-Chain. Search, selector lookup and calldata decode take no chain at all. Anything else answers 422 with state unsupported, and more chains are on the way.

Use case 1: screening a deposit or a withdrawal

The core call is the address risk score:

curl -X POST "https://triport.io/v1/intelligence/address-risk" \
  -H "x-token: $TRIPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chain":"eth","address":"0x28c6c06298d514db089934071355e5743bf21d60"}'

That address is a well-known exchange hot wallet. On 2026-11-06 the answer was (timestamps shortened):

{
  "state": "ok",
  "meta": { "cached": true, "complete": false, "observedAt": "2026-11-06T09:30:36Z", "expiresAt": "2026-11-07T09:30:36Z" },
  "data": {
    "subject": { "chain": "eth", "address": "0x28c6c06298d514db089934071355e5743bf21d60" },
    "assessment": { "address": "0x28c6c06298d514db089934071355e5743bf21d60", "risk": { "value": "1", "level": "none" } }
  }
}

Three details in that envelope are the whole design.

First, state comes before data. It is one of ok, empty, partial, stale, unsupported or unavailable, and it is the first thing your code should branch on. A partial answer is still useful; an unavailable one is not a verdict on the address at all.

Second, the score is a string, and it can be null. When the layer has no assessment, you get risk.value: null with level unknown. That is the most important rule in the API: missing risk is not zero risk. If your screening code maps null to 0, or to "low", you have built a system that approves exactly the addresses nobody knows anything about. Route unknown to review.

Third, meta says how old the answer is. cached, observedAt and expiresAt tell you whether you are looking at a cached observation and until when it is considered fresh. If a decision needs a new lookup, send "fresh": true.

For fresh wallets, add funder risk: it checks whether the address that funded the wallet carries a risk signal. A brand-new address with no history of its own is common, and its funder is often the only signal there is. The answer is a hint (risky: true or false), not proof of where the first funds came from, and it comes back as partial when the picture is incomplete.

What you do with the level is your policy, not ours. Log the full assessment next to the decision, so a reviewer can see what the score was based on when someone asks why a deposit was held.

Use case 2: labeling counterparties

Labels turn an address into something a human can read: an exchange deposit address, a bridge, a protocol contract. The batch endpoint takes up to 200 addresses of one chain:

curl -X POST "https://triport.io/v1/intelligence/labels/batch" \
  -H "x-token: $TRIPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"chain":"eth","addresses":["0xdac17f958d2ee523a2206206994597c13d831ec7","0x7a250d5630b4cf539739df2c5dacd4c659f2488d"]}'

The answer keeps your input order, and every item has its own state. In our run the first address came back ok with the label "Tether: USDT Stablecoin", and the second came back partial with no label. The batch as a whole was partial because one item was. That is the behavior you want: one weak item does not erase the strong one, and the weak one is not dressed up as "no label exists".

Labels are attribution hints. A label does not prove who controls a wallet and is not an identity check. For proxy contracts, implementation labels names the code behind the proxy separately: in our run, the USDC proxy came back as "Circle: USDC Token" with its implementation labeled separately as "Circle: Fiat Token V2_2". Keep the two apart in your UI.

If you also need names, balances and activity of an EVM wallet, the existing wallet identity endpoint covers that from chain data; the Intelligence API adds the attribution and risk side.

Use case 3: checking a spender before the user signs

An ERC-20 approve, or an EIP-2612 permit signature, gives a spender the right to move a user's tokens. Wallets and dapps that want to warn before that signature can call token approval risk with the spender they are about to approve, up to 50 at once:

curl -X POST "https://triport.io/v1/intelligence/approval-risk" \
  -H "x-token: $TRIPORT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"spenders":[{"chain":"eth","address":"0x7a250d5630b4cf539739df2c5dacd4c659f2488d"}]}'

Each spender gets its own item with a state and an assessment, using the same null-is-unknown rule as address risk. Be precise about what this is: it checks spenders you supply. It does not list the allowances a wallet has already granted, and it never changes one. To find existing approvals you still read the chain, for example Approval logs over eth_getLogs.

Pair it with calldata decode to show the user what the transaction actually says. You supply the ABI and the calldata, and each decoded parameter comes back as exact JSON text, so a uint256 amount is never rounded by a JavaScript number. A good warning shows both: "this call approves this amount to this spender, and the spender's risk level is X".

Use case 4: following the money and finding the deployer

For investigations and source-of-funds reviews, the fund flow graph returns nodes (addresses, with labels and risk labels when known) and edges (transfers with token, amount and timestamp), optionally filtered to one token. Every graph carries a coverage block with historyComplete and truncated. Read it. Graphs are bounded, and an empty graph is not proof that no transfers happened.

Fund flow is also the slowest method. In our own test on 2026-11-06, from one client in Europe through triport.io, an uncached graph for a busy exchange wallet took about 25 seconds, and a repeat a few minutes later was served from cache. That is a single measurement, network included, not a promise; set a client timeout of at least a minute and do not retry in a tight loop.

Contract creation answers the other investigation question: which address created a contract, in which transaction and block, and when. For USDT it returned the creation transaction, block 4634748 and the creator address, with the timestamp as a string in milliseconds. The record carries a kind field because a creation record is not always a plain deployment; read it before you write "deployed by" in a report.

Use case 5: a pre-trade check

Transaction simulation runs a hypothetical transaction (sender, receiver, calldata, value, gas) without signing or broadcasting anything. The answer is a simulation reference with outcome: unknown. It is a check you run before you sign, not a receipt and not a promise that the real transaction will succeed. For the canonical head, receipts and finality, keep using JSON-RPC; the finality glossary entry explains why that distinction matters.

The contract inspection methods fill in the rest: function signature lookup and selector lookup turn 0xa9059cbb into transfer(address,uint256), and the storage variable list shows what a contract declares. A selector is not a unique identity, since two functions can share one, so treat a match as a hint and confirm it against the ABI when the decision matters.

When this is the wrong approach

The Intelligence API is not the right tool in a few situations, and it is better to know them before you build on it.

  • You need a chain other than Ethereum today. Apart from labels on Solana and Avalanche C-Chain, chain-specific methods are Ethereum only for now. If your screening has to cover BNB Smart Chain or Tron this month, this is not enough on its own.
  • You need a compliance decision, not data. The API returns labels, scores and graphs with their coverage. It does not decide what to block, file or report, and it is not legal advice.
  • You need identity. A label is an attribution hint, not know-your-customer verification of a person.
  • You need complete history. Graphs and search are bounded and there is no pagination. For a full transfer history of an address, index the chain yourself with eth_getLogs.
  • You need contract metadata for everything. Verification metadata is not available for every contract; several well-known contracts answered unsupported on release day. When you already have the ABI, decode calldata yourself or with calldata decode.
  • You are on a trial, Basic or Pro plan. The API is part of Business and Enterprise only.
  • You need execution truth. Simulation and the analytics block numbers are not the canonical chain. Receipts and finality come from RPC.

Getting started

Create or reuse a key on a Business or Enterprise plan, check that it carries intelligence:read, and start with address risk and labels; they are the calls most screening flows need. The overview has the response states, errors and limits in one place, and the code examples include a screening function in JavaScript that treats unknown as "review" and a batch labeler in Python. Plan prices are on the pricing page.

Sources

Checked on 2026-11-06: