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

# Tracking balances

> Fetch a user's positions, group them for display, and execute the pending actions balances expose.

Show a user what they hold across one or many yields, tell them what's earning versus cooling down, and let them act on whatever a position is ready for next: claiming, withdrawing, or restaking.

## Prerequisites

* A yield.xyz API key, sent as `x-api-key` on every request.
* At least one yield enabled for your project. See [Discover yields](/guides/earn/discover-yields).

<Steps>
  <Step title="Fetch balances for one yield">
    Once you know the `yieldId` a user is positioned in, read every balance for it with `POST /v1/yields/{yieldId}/balances`:

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
        --url https://api.yield.xyz/v1/yields/base-usdc-aave-v3-lending/balances \
        --header "x-api-key: $YIELD_API_KEY" \
        --header 'content-type: application/json' \
        --data '{ "address": "0xYOUR_WALLET_ADDRESS" }'
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch('https://api.yield.xyz/v1/yields/base-usdc-aave-v3-lending/balances', {
        method: 'POST',
        headers: {
          'x-api-key': process.env.YIELD_API_KEY!,
          'content-type': 'application/json',
        },
        body: JSON.stringify({ address: '0xYOUR_WALLET_ADDRESS' }),
      });
      const { balances, outputTokenBalance, rewardRate } = await res.json();
      ```
    </CodeGroup>

    The response is a `YieldBalancesDto`: `balances[]` for this yield, plus an optional `outputTokenBalance` (share-token yields) and `rewardRate`. See [Balances and positions](/documentation/earn/core-concepts/balances-positions) for every field on a `BalanceDto`.
  </Step>

  <Step title="Fetch a portfolio across yields and networks">
    To show every position a user holds instead of one yield at a time, call `POST /v1/yields/balances` with up to 25 queries in one request:

    <CodeGroup>
      ```bash cURL theme={null}
      curl --request POST \
        --url https://api.yield.xyz/v1/yields/balances \
        --header "x-api-key: $YIELD_API_KEY" \
        --header 'content-type: application/json' \
        --data '{
          "queries": [
            { "address": "0xYOUR_WALLET_ADDRESS", "network": "base" },
            { "address": "0xYOUR_WALLET_ADDRESS", "network": "ethereum" }
          ]
        }'
      ```

      ```typescript TypeScript theme={null}
      const res = await fetch('https://api.yield.xyz/v1/yields/balances', {
        method: 'POST',
        headers: {
          'x-api-key': process.env.YIELD_API_KEY!,
          'content-type': 'application/json',
        },
        body: JSON.stringify({
          queries: [
            { address: '0xYOUR_WALLET_ADDRESS', network: 'base' },
            { address: '0xYOUR_WALLET_ADDRESS', network: 'ethereum' },
          ],
        }),
      });
      const { items, errors } = await res.json();
      ```
    </CodeGroup>

    Each query's `yieldId` is optional. Omit it to scan the network, which only checks yields that address has already used through yield.xyz, plus a small built-in set, not the whole network's catalog. When you need a specific position with certainty, for example right after an enter action, name its `yieldId` explicitly: a named query always comes back, even at zero balance, while a scan surfaces only non-zero results.

    Read `items` (balances grouped by yield) separately from `errors` (per-yield failures): a failure on one yield doesn't drop the rest of the response.
  </Step>

  <Step title="Group balances for display">
    Split each yield's `balances[]` by `type` so your UI can show active, cooling-down, and claimable amounts separately instead of one flat list. See [Balances and positions](/documentation/earn/core-concepts/balances-positions#balance-types) for what each `type` means.

    ```typescript theme={null}
    const byType = balances.reduce<Record<string, typeof balances>>((acc, balance) => {
      (acc[balance.type] ??= []).push(balance);
      return acc;
    }, {});
    ```

    Use `isEarning`, not `type`, to decide whether a balance is currently generating yield. A yield's mechanics decide which type earns; do not assume `active` always does or that other types never do.
  </Step>

  <Step title="Surface and execute pending actions">
    Each `BalanceDto` carries `pendingActions[]`: the manage or exit steps available on it right now, for example claiming matured rewards or completing a withdrawal after cooldown. Show these to the user as calls to action.

    To execute one, send its `type` as `action` and its `passthrough` unchanged to `POST /v1/actions/manage`, along with any `arguments` its own schema requires:

    ```bash cURL theme={null}
    curl --request POST \
      --url https://api.yield.xyz/v1/actions/manage \
      --header "x-api-key: $YIELD_API_KEY" \
      --header 'content-type: application/json' \
      --data '{
        "yieldId": "ethena-usde-staking",
        "address": "0xYOUR_WALLET_ADDRESS",
        "action": "CLAIM_UNSTAKED",
        "passthrough": "PASSTHROUGH_FROM_THE_BALANCE"
      }'
    ```

    `ethena-usde-staking` holds an exited position as an `exiting` balance with no pending actions through its 7-day cooldown; once the cooldown ends, it is returned as `withdrawable` with a `CLAIM_UNSTAKED` pending action. Copy its `passthrough` from the balances response; never construct one. The response is an `ActionDto` with its own `transactions[]`: sign, submit, and poll it the same way as any enter or exit action. See [Enter and exit flows](/guides/earn/enter-exit-flows) for that loop, and [Actions](/documentation/earn/core-concepts/actions#manage-actions) for the `manage` request shape.

    Once the manage action's transactions confirm, re-fetch balances (Step 1 or 2) rather than assuming the old response is still current: the pending action you executed should be gone, and a new one may already have taken its place.
  </Step>
</Steps>

<Note>
  Treat `amountUsd` as display-only. It is a price-derived estimate of `amount`, not an accounting source of truth, and depends on price data being available for that token at query time.
</Note>

For what a position actually earned over time, rather than what it holds right now, see [Rewards and history](/documentation/earn/core-concepts/rewards-history).

## Next steps

<Columns cols={2}>
  <Card title="Enter and exit flows" icon="arrow-right-arrow-left" href="/guides/earn/enter-exit-flows">
    Sign, submit, and poll the transactions an action returns, including manage actions.
  </Card>

  <Card title="Monitoring and alerting" icon="chart-line" href="/guides/earn/monitoring-alerting">
    Keep balances and action status current after the first fetch, and alert on what needs attention.
  </Card>

  <Card title="Balances and positions" icon="wallet" href="/documentation/earn/core-concepts/balances-positions">
    Every balance type and field, and how pending actions are structured.
  </Card>

  <Card title="API reference" icon="book" href="/api-reference/YieldsController_getYieldBalances">
    Full request and response schemas for both balance endpoints.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.