# 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.

Source: https://docs.crius.sh/use-cases/wallets-and-portfolio-apps/ · Updated 2026-10-28

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}`](https://docs.crius.sh/reference/wallets/wallet-profile/) holdings with USD value and `price_confidence`, native ETH balance, realized and unrealized PnL over a window, win rate, gas spent and wallet tags. `min_value_usd` hides dust.
-   [GET`/wallet/{address}/trades`](https://docs.crius.sh/reference/wallets/wallet-trades/) every trade the wallet made across all tokens, newest first, filterable by `token`, `side`, `min_usd` and time.
-   [GET`/prices`](https://docs.crius.sh/reference/tokens/batch-prices/) USD and ETH prices with 24h change for up to 100 tokens, when you have the balances already.
-   [POST`/tokens/batch`](https://docs.crius.sh/reference/tokens/batch-token-profiles/) names, logos and market data for the tokens in a portfolio, trimmed to the fields you show.
-   [GET`/token/{address}/candles`](https://docs.crius.sh/reference/trades/ohlcv-candles/) price charts for a token detail screen.
-   [GET`/token/{address}/security`](https://docs.crius.sh/reference/security/security-checks/) a warning before the user sends, swaps or trusts a token.
-   The `wallet:<address>` [stream channel](https://docs.crius.sh/reference/stream/): the wallet’s trades and transfers as they happen, so you refresh only when something changed.

## Suggested architecture

1.  **Balances you already have: price them in batches.** `POST /prices` with up to 100 token addresses costs 1 credit and needs no key. A wallet with 300 tokens is three calls.
    
2.  **Full portfolio: one profile call.** `/wallet/{address}` (Starter, 5 credits) returns holdings, values and PnL together. Cache it per user and refresh when the `wallet:<address>` channel reports activity, not on every screen view.
    
3.  **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.
    
4.  **Load history page by page.** `/wallet/{address}/trades` with `limit` and `cursor` (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

Example [Starter plan · 5 credits](https://docs.crius.sh/reference/wallets/wallet-profile/)

### A smart account holding ETH and two fake USDG tokens

What does wallet 0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca hold, and what is it really worth?

GET/v1/robinhood/wallet/0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca

 

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/wallet/0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca" \
  -H "x-api-key: $CRIUS_API_KEY"
```

**JavaScript**

```js
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();
```

**Python**

```python
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)**

```json
{
  "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"` with `delegate: "0x63c0c19a282a1b52b07dd5a65b58948a07dae32b"`: an EIP-7702 wallet. `profile.tags` are `dev` and `smart_account`.
-   `native_balance: 0.71473787532832551` ETH, worth `native_value_usd: 1683.56`. Almost all the value is ETH.
-   Both token holdings have `symbol: "USDG"` and `balance: 25`, but their addresses are `0xfaaf8ffa8a29ceb6c85aff8d3961f65ae1bfc775` and `0x06993ae1230d3755b54f25022028daa66772bc3d`, not the real USDG `0x5fc5360d0400a0fd4f2af552add042d716f1d168`. Each is valued at `value_usd: 0.0117789` with `price_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_by` is a Relay solver (`label: "bridge:Relay solver"`): the wallet’s first ETH was bridged in.

[Wallet profile reference](https://docs.crius.sh/reference/wallets/wallet-profile/) [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20A%20smart%20account%20holding%20ETH%20and%20two%20fake%20USDG%20tokens&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fuse-cases%2Fwallets-and-portfolio-apps%2F%23portfolio%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Fwallet%2F0x3ac82d45ff9e4963cefbc3f74dbe293f34c927ca%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

## Prices for balances you already know

Example [Anonymous · no key · 1 credit](https://docs.crius.sh/reference/tokens/batch-prices/)

### Batch prices for a watchlist or a wallet's tokens

What are CHARGE (0x7b8892cea949bc60d494681d1bc3ea96071ab0b8) and WETH (0x0bd7d308f8e1639fab988df18a8011f41eacad73) worth right now?

GET/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73

  

**cURL**

```bash
curl "https://api.crius.sh/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73"
```

**JavaScript**

```js
const res = await fetch("https://api.crius.sh/v1/robinhood/prices?tokens=0x7b8892cea949bc60d494681d1bc3ea96071ab0b8,0x0bd7d308f8e1639fab988df18a8011f41eacad73");
const { data, meta } = await res.json();
```

**Python**

```python
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)**

```json
{
  "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.49` with `confidence: "high"` and `liquidity_usd: 9953382`; CHARGE has `usd: 0.00000388948` with `confidence: "medium"`.
-   `change_24h_pct` is ready for the green or red number next to each row (0.286017 for WETH, −0.171971 for CHARGE).
-   `logo` is a ready-to-use image URL for CHARGE and `null` for 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.

[Batch prices reference](https://docs.crius.sh/reference/tokens/batch-prices/) Runs from your browser on the anonymous plan [Data looks wrong? Report it](mailto:support@crius.sh?subject=Wrong%20data%20in%20docs%20example%3A%20Batch%20prices%20for%20a%20watchlist%20or%20a%20wallet's%20tokens&body=Page%3A%20https%3A%2F%2Fdocs.crius.sh%2Fuse-cases%2Fwallets-and-portfolio-apps%2F%23batch-prices%0ARequest%3A%20GET%20%2Fv1%2Frobinhood%2Fprices%3Ftokens%3D0x7b8892cea949bc60d494681d1bc3ea96071ab0b8%2C0x0bd7d308f8e1639fab988df18a8011f41eacad73%0A%0AWhat's%20wrong%20or%20missing%3F%0A%0A)

```js
// 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](https://docs.crius.sh/concepts/pnl/), and the guides cover [holdings and PnL](https://docs.crius.sh/guides/get-wallet-pnl-and-holdings/) and [trade history](https://docs.crius.sh/guides/get-wallet-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

[Guide **Wallet holdings & PnL** Get a Robinhood Chain wallet's tokens with USD value, ETH balance, realized and unrealized PnL, win rate, gas spent and wallet tags in one call. Real example. Read](https://docs.crius.sh/guides/get-wallet-pnl-and-holdings/) [Guide **Wallet trade history** List every trade a Robinhood Chain wallet made across all tokens, with USD value at trade time, market cap, DEX and gas. Filter by token, side, size, time. Read](https://docs.crius.sh/guides/get-wallet-trade-history/) [Guide **Prices for many tokens** Price up to 100 Robinhood Chain tokens in one request with the batch prices API, or get chosen profile fields for many tokens. Real responses, no key needed. Read](https://docs.crius.sh/guides/get-prices-for-many-tokens/) [Concept **PnL** How the Crius API computes realized and unrealized PnL, ROI, cost basis and win rate for Robinhood Chain traders and wallets, worked through on real trades. Read](https://docs.crius.sh/concepts/pnl/) [Concept **Token prices** How the Crius API prices Robinhood Chain tokens from on-chain pools, how the price pool is picked, and what confidence and thin\_liquidity mean. Read](https://docs.crius.sh/concepts/token-prices/) [API reference **Wallet profile API** Holdings with USD value, realized and unrealized PnL over a window (1d, 7d, 30d, all), win rate and wallet tags. Read](https://docs.crius.sh/reference/wallets/wallet-profile/)
