Robinhood Chain API for wallets and portfolio apps
What a Robinhood Chain wallet or portfolio app needs from the Crius API: holdings, USD values, PnL, trade history and warnings about spam tokens.
A wallet or portfolio app shows a user what they own, what it is worth and how they did: balances in ETH and tokens, USD values that don’t count spam as money, realized and unrealized PnL, and a trade history that names the token rather than the router. The Crius API returns the whole portfolio in one call, priced from on-chain pools, with a confidence level on each value. Apps that already read balances can use batch prices alone.
Endpoints a portfolio app uses
- GET
/wallet/{address}holdings with USD value andprice_confidence, native ETH balance, realized and unrealized PnL over a window, win rate, gas spent and wallet tags.min_value_usdhides dust. - GET
/wallet/{address}/tradesevery trade the wallet made across all tokens, newest first, filterable bytoken,side,min_usdand time. - GET
/pricesUSD and ETH prices with 24h change for up to 100 tokens, when you have the balances already. - POST
/tokens/batchnames, logos and market data for the tokens in a portfolio, trimmed to the fields you show. - GET
/token/{address}/candlesprice charts for a token detail screen. - GET
/token/{address}/securitya warning before the user sends, swaps or trusts a token. - The
wallet:<address>stream channel: the wallet’s trades and transfers as they happen, so you refresh only when something changed.
Suggested architecture
-
Balances you already have: price them in batches.
POST /priceswith up to 100 token addresses costs 1 credit and needs no key. A wallet with 300 tokens is three calls. -
Full portfolio: one profile call.
/wallet/{address}(Starter, 5 credits) returns holdings, values and PnL together. Cache it per user and refresh when thewallet:<address>channel reports activity, not on every screen view. -
Value only what can be sold. Leave holdings with
price_confidence: "low"out of the headline total, or show them under “unpriced”. Values are already capped at what each token’s price pool could pay out. -
Load history page by page.
/wallet/{address}/tradeswithlimitandcursor(5 credits per page). Each trade carries the USD value at trade time, so history never needs re-pricing.
As a budget: 10,000 users who each open the app three times a day, with one profile call per open, is 150,000 credits a day, about 4.5 million a month, which fits Starter’s 10,000,000. Refreshing on stream events instead of every open lowers that further.
A portfolio in one call
A smart account holding ETH and two fake USDG tokens
What does wallet 0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca hold, and what is it really worth?
curl "https://api.crius.sh/v1/robinhood/wallet/0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca" \ -H "x-api-key: $CRIUS_API_KEY"const res = await fetch("https://api.crius.sh/v1/robinhood/wallet/0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca", { headers: { "x-api-key": process.env.CRIUS_API_KEY },});const { data, meta } = await res.json();import os, requests
r = requests.get( "https://api.crius.sh/v1/robinhood/wallet/0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca", headers={"x-api-key": os.environ["CRIUS_API_KEY"]},)body = r.json()print(body["data"])Real response 200 Captured Oct 28, 2026 · 84 lines (arrays trimmed)
{ "data": { "account_type": "smart_account", "address": "0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca", "delegate": "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b", "holdings": [ { "balance": 25, "pnl": null, "price_confidence": "low", "token": { "address": "0xfaaf8ffa8a29ceb6c85aff8d3961f65ae1bfc775", "logo": null, "symbol": "USDG" }, "value_eth": 0.00000500064, "value_usd": 0.0117789 }, { "balance": 25, "pnl": null, "price_confidence": "low", "token": { "address": "0x06993ae1230d3755b54f25022028daa66772bc3d", "logo": null, "symbol": "USDG" }, "value_eth": 0.00000500061, "value_usd": 0.0117789 } ], "holdings_truncated": false, "holdings_value_usd": 0.0235578, "is_contract": false, "label": null, "native_balance": 0.71473787532832551, "native_value_usd": 1683.56, "pnl": { "avg_hold_time_s": null, "best_trade": null, "gas_scope": "all transactions sent by the wallet in the window", "gas_spent_usd": 0.198772, "realized_usd": 0, "tokens_traded": 0, "tokens_with_known_cost": 0, "total_usd": 0, "trades": 0, "unrealized_usd": 0, "volume_usd": 0, "win_rate_pct": null, "window": "30d", "worst_trade": null }, "profile": { "first_seen_block": 91351250, "first_seen_ts": 1792283372000, "fresh": false, "funded_by": { "address": "0xd782268f600403843484b70710daee6846fc0db8", "amount_eth": 0.008148386337868892, "block": 87601233, "label": "bridge:Relay solver", "ts": 1791903516300 }, "history": "complete", "tags": [ "dev", "smart_account" ], "tx_count": 14, "wallet_age_days": 10.8994 } }, "meta": { "balances_block": 100406864, "block": 100406864, "block_age_ms": 1301, "block_ts": 1793225084000, "chain": "robinhood", "finalized_block": 100397649, "lag_ms": 59, "safe_block": 100401329 }}What this tells you
account_type: "smart_account"withdelegate: "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b": an EIP-7702 wallet.profile.tagsaredevandsmart_account.native_balance: 0.71473787532832551ETH, worthnative_value_usd: 1683.56. Almost all the value is ETH.- Both token holdings have
symbol: "USDG"andbalance: 25, but their addresses are0xfaaf8ffa8a29ceb6c85aff8d3961f65ae1bfc775and0x06993ae1230d3755b54f25022028daa66772bc3d, not the real USDG0x5fc5360d0400a0fd4f2af552add042d716f1d168. Each is valued atvalue_usd: 0.0117789withprice_confidence: "low". - An app that matched by symbol would show $50 of stablecoins here. The API values both at about a cent each:
holdings_value_usd: 0.0235578. profile.funded_byis a Relay solver (label: "bridge:Relay solver"): the wallet’s first ETH was bridged in.
Prices for balances you already know
Batch prices for a watchlist or a wallet's tokens
What are CHARGE (0x7b8892cea949bc60d494681d1bc3ea96071ab0b8) and WETH (0x0bd7d308f8e1639fab988df18a8011f41eacad73) worth right now?
curl "https://api.crius.sh/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73"const res = await fetch("https://api.crius.sh/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73");const { data, meta } = await res.json();import requests
r = requests.get( "https://api.crius.sh/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73",)body = r.json()print(body["data"])Real response 200 Captured Oct 28, 2026 · 34 lines (arrays trimmed)
{ "data": { "0x0bd7d308f8e1639fab988df18a8011f41eacad73": { "change_24h_pct": 0.286017, "confidence": "high", "eth": 1, "liquidity_usd": 9953382, "logo": null, "source_pool": "0xbac3aa3b91584a53a579b3c999a56756e954e59247e497bad1d25a4334bde551", "symbol": "WETH", "usd": 2355.49 }, "0x7b8892cea949bc60d494681d1bc3ea96071ab0b8": { "change_24h_pct": -0.171971, "confidence": "medium", "eth": 0.00000000165124, "liquidity_usd": 5604.57, "logo": "https://api.crius.sh/v1/robinhood/logo/0x7b8892cea949bc60d494681d1bc3ea96071ab0b8.png?size=128", "source_pool": "0x871b166182fd708d5d16a4daa9a42f05a653fa51ee2b195097f425e0d9ca4913", "symbol": "CHARGE", "usd": 0.00000388948 } }, "meta": { "block": 100406775, "block_age_ms": 907, "block_ts": 1793225075000, "chain": "robinhood", "finalized_block": 100397649, "lag_ms": 35, "missing": [], "safe_block": 100401329 }}What this tells you
- Results are keyed by address: WETH has
usd: 2355.49withconfidence: "high"andliquidity_usd: 9953382; CHARGE hasusd: 0.00000388948withconfidence: "medium". change_24h_pctis ready for the green or red number next to each row (0.286017 for WETH, −0.171971 for CHARGE).logois a ready-to-use image URL for CHARGE andnullfor WETH: keep your own icons for the chain’s base assets.meta.missing: []: an address without a price would be listed there rather than failing the call.
// Value a wallet from balances you already read over RPC (anonymous: no key needed).async function valuePortfolio(balances /* { [tokenAddress]: amount } */) { const res = await fetch("https://api.crius.sh/v1/robinhood/prices", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ tokens: Object.keys(balances).slice(0, 100) }), }); const { data } = await res.json(); let total = 0; const unpriced = []; for (const [token, amount] of Object.entries(balances)) { const p = data[token.toLowerCase()]; if (!p || p.confidence === "low") unpriced.push(token); else total += amount * p.usd; } return { totalUsd: total, unpriced };}The balance × price above isn’t capped by pool depth, so a very large holding of a small token can still look worth more than its market could pay: use /wallet/{address} when that matters. How PnL is worked out is on the PnL page, and the guides cover holdings and PnL and trade history.
Frequently asked questions
How do I spot fake USDG and spam tokens in a wallet?
Match tokens by address, never by symbol: the real USDG is 0x5fc5360d0400a0fd4f2af552add042d716f1d168. Then use price_confidence on each holding (low means the token has no real market behind its price) and the /security check (risk, flags) before you count a token in the total or offer a swap.
Does the wallet API work with EIP-7702 smart accounts?
Yes. The wallet profile reports account_type (eoa, smart_account or contract) and, for smart accounts, the delegate contract. Trades made through the account's delegate are attributed to the account itself.
Which plan does a portfolio app need?
If your app already knows the balances (a wallet reads them from its own RPC), batch prices are enough: anonymous, 1 credit per 100 tokens. The wallet profile and wallet trades (holdings, PnL, history) need a Starter key and cost 5 credits per call.
Can I get a wallet's portfolio value over time?
There is no single portfolio-history call. Rebuild it from the wallet's trades (/wallet/{address}/trades) and each token's candles (/token/{address}/candles), or store the profile's holdings_value_usd yourself each day.
Related
Get your free Crius API key
Every example on this page works with a free key: higher rate limits than the anonymous plan, holders, wallets and the WebSocket stream. No card needed.
- Robinhood Chain (4663) only, from our own archive nodes
- REST + WebSocket
- Pay on-chain or by card