> ## Documentation Index
> Fetch the complete documentation index at: https://developers.zerion.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a Wallet's DeFi Positions

> Retrieve lending, staking, and liquidity positions across DeFi protocols for any wallet.

**What you'll build:**

* Fetch all DeFi positions (staked, deposited, LP, locked, rewards)
* Filter by position type and chain
* Group positions by protocol and calculate per-protocol totals
* Build a complete runnable DeFi dashboard

```
Position                  | Protocol     | Module         | Amount    | Value
Supplied USDC             | Aave V3      | lending        | 5,000.00  | $5,000.00
Staked ETH                | Lido         | staked         | 1.20      | $2,543.88
ETH/USDC LP              | Uniswap V3   | liquidity_pool | 0.85      | $1,801.15
Locked CRV                | Curve        | locked         | 10,000.00 | $450.00
Unclaimed ARB             | Arbitrum     | rewards        | 200.00    | $230.00
```

**Time:** \~10 minutes

## Prerequisites

* A Zerion API key ([get one here](https://dashboard.zerion.io))
* A wallet address to query

## Steps

<Steps>
  ### Fetch DeFi positions

  Call the [positions endpoint](/api-reference/wallets/get-wallet-fungible-positions) with `filter[positions]=only_complex` to get only DeFi protocol positions, excluding regular wallet tokens.

  <CodeGroup>
    ```javascript JavaScript theme={null}
    const API_KEY = process.env.ZERION_API_KEY;
    const address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
    const headers = {
      accept: "application/json",
      authorization: `Basic ${btoa(API_KEY + ":")}`,
    };

    const response = await fetch(
      `https://api.zerion.io/v1/wallets/${address}/positions/?currency=usd&filter[positions]=only_complex&sort=-value`,
      { headers }
    );
    if (!response.ok) throw new Error(`API error: ${response.status}`);

    const { data } = await response.json();

    for (const position of data) {
      const { name, protocol, protocol_module, quantity, value } = position.attributes;
      console.log(
        `${name} | ${protocol} (${protocol_module}) | ${quantity?.float} | ${value != null ? `$${value.toFixed(2)}` : "N/A"}`
      );
    }
    ```

    ```python Python theme={null}
    import os, requests

    api_key = os.environ["ZERION_API_KEY"]
    address = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"

    response = requests.get(
        f"https://api.zerion.io/v1/wallets/{address}/positions/",
        params={
            "currency": "usd",
            "filter[positions]": "only_complex",
            "sort": "-value",
        },
        auth=(api_key, ""),
    )

    for position in response.json()["data"]:
        attrs = position["attributes"]
        print(
            f"{attrs['name']} | "
            f"{attrs.get('protocol', 'N/A')} ({attrs.get('protocol_module', 'N/A')}) | "
            f"{attrs['quantity']['float']} | "
            f"{'${:.2f}'.format(attrs['value']) if attrs.get('value') is not None else 'N/A'}"
        )
    ```

    ```bash cURL theme={null}
    curl -u "YOUR_API_KEY:" \
      "https://api.zerion.io/v1/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/positions/?currency=usd&filter[positions]=only_complex&sort=-value"
    ```
  </CodeGroup>

  <Tip>
    **Key parameters:** `filter[positions]=only_complex` (DeFi positions only), `sort=-value` (highest value first), `currency=usd` (also supports `eur`, `gbp`, etc.)
  </Tip>

  ### Filter by position type (optional)

  Use `filter[position_types]` to narrow results to specific DeFi categories.

  <CodeGroup>
    ```javascript JavaScript theme={null}
    const response = await fetch(
      `https://api.zerion.io/v1/wallets/${address}/positions/?currency=usd&filter[positions]=only_complex&filter[position_types]=deposit,staked`,
      { headers }
    );

    const { data } = await response.json();
    ```

    ```python Python theme={null}
    response = requests.get(
        f"https://api.zerion.io/v1/wallets/{address}/positions/",
        params={
            "currency": "usd",
            "filter[positions]": "only_complex",
            "filter[position_types]": "deposit,staked",
        },
        auth=(api_key, ""),
    )
    ```

    ```bash cURL theme={null}
    curl -u "YOUR_API_KEY:" \
      "https://api.zerion.io/v1/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/positions/?currency=usd&filter[positions]=only_complex&filter[position_types]=deposit,staked"
    ```
  </CodeGroup>

  Available position types:

  | Type      | Description                                                     |
  | --------- | --------------------------------------------------------------- |
  | `deposit` | Assets deposited into lending pools, vaults, or liquidity pools |
  | `staked`  | Assets staked for rewards, governance, or consensus             |
  | `reward`  | Unclaimed rewards earned from protocols                         |
  | `locked`  | Vote-escrowed or time-locked positions                          |
  | `wallet`  | Regular wallet assets (excluded by `only_complex`)              |

  ### Filter by chain (optional)

  To get DeFi positions on specific chains only, add `filter[chain_ids]`.

  ```bash theme={null}
  curl -u "YOUR_API_KEY:" \
    "https://api.zerion.io/v1/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/positions/?currency=usd&filter[positions]=only_complex&filter[chain_ids]=ethereum,arbitrum"
  ```

  ### Full working example

  Save as `defi-dashboard.mjs` and run with `node defi-dashboard.mjs`:

  ```javascript theme={null}
  const API_KEY = process.env.ZERION_API_KEY;
  const BASE_URL = "https://api.zerion.io/v1";
  const headers = {
    accept: "application/json",
    authorization: `Basic ${btoa(API_KEY + ":")}`,
  };

  async function getAllDeFiPositions(address) {
    const allPositions = [];
    let url = `${BASE_URL}/wallets/${address}/positions/?currency=usd&filter[positions]=only_complex&sort=-value`;

    while (url) {
      const res = await fetch(url, { headers });
      const { data, links } = await res.json();
      allPositions.push(...data);
      url = links.next || null;
    }

    return allPositions;
  }

  async function displayDeFiDashboard(address) {
    const positions = await getAllDeFiPositions(address);

    // Group by protocol
    const byProtocol = {};
    for (const pos of positions) {
      const protocol = pos.attributes.protocol || "Unknown";
      if (!byProtocol[protocol]) byProtocol[protocol] = { total: 0, positions: [] };
      byProtocol[protocol].total += pos.attributes.value || 0;
      byProtocol[protocol].positions.push(pos);
    }

    // Sort protocols by total value
    const sorted = Object.entries(byProtocol).sort((a, b) => b[1].total - a[1].total);

    const grandTotal = positions.reduce((sum, p) => sum + (p.attributes.value || 0), 0);
    console.log(`=== DeFi OVERVIEW ===`);
    console.log(`Total DeFi value: $${grandTotal.toFixed(2)}`);
    console.log(`Protocols: ${sorted.length}`);
    console.log(`Positions: ${positions.length}\n`);

    for (const [protocol, data] of sorted) {
      console.log(`--- ${protocol} ($${data.total.toFixed(2)}) ---`);
      for (const pos of data.positions) {
        const { name, position_type, value, quantity } = pos.attributes;
        const chain = pos.relationships.chain.data.id;
        console.log(
          `  [${position_type}] ${name} on ${chain}: ${quantity.float} (${value != null ? `$${value.toFixed(2)}` : "N/A"})`
        );
      }
      console.log();
    }
  }

  displayDeFiDashboard("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
  ```
</Steps>

## Response fields reference

Each DeFi position includes:

| Field                 | Description                                                                                                           |
| --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `name`                | Human-readable position name                                                                                          |
| `protocol`            | Protocol name (e.g., "Aave V3", "Lido")                                                                               |
| `protocol_module`     | Type of DeFi interaction: `lending`, `staked`, `liquidity_pool`, `locked`, `rewards`, `farming`, `vesting`, `deposit` |
| `position_type`       | Position category (`deposit`, `staked`, `reward`, `locked`)                                                           |
| `quantity.float`      | Token amount                                                                                                          |
| `value`               | USD value of the position                                                                                             |
| `group_id`            | ID to group related positions (e.g., both sides of an LP)                                                             |
| `relationships.chain` | Which blockchain the position is on                                                                                   |

## Next steps

* Use `filter[positions]=no_filter` to get both DeFi and wallet positions in a single call
* Combine with the [portfolio endpoint](/api-reference/wallets/get-wallet-portfolio) to see total value distribution by type
* Implement [pagination](/pagination-and-filtering) to handle wallets with many DeFi positions
