> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cách lấy số dư ví

> Truy xuất toàn bộ số dư token và NFT của bất kỳ ví Solana nào, kèm theo giá trị USD, logo và siêu dữ liệu. Được sắp xếp theo giá trị để dễ dàng theo dõi danh mục đầu tư.

<Note>
  Wallet API đang ở giai đoạn Beta. Các endpoint và định dạng phản hồi có thể thay đổi.
</Note>

## Tổng quan

Endpoint Wallet Balances truy xuất toàn bộ token và NFT mà một ví Solana nắm giữ — SOL, token SPL, Token-2022 và NFT — kèm theo giá USD, logo và siêu dữ liệu. Kết quả được sắp xếp theo giá trị USD giảm dần: token có dữ liệu giá xuất hiện trước, sau đó là token không có giá.

Endpoint trả về tối đa 100 token cho mỗi yêu cầu, vì vậy bạn cần phân trang thủ công. Sử dụng tham số `page` để lấy các trang bổ sung và đọc `pagination.hasMore` để biết khi nào còn kết quả. Mỗi yêu cầu là một lệnh gọi API và tốn 100 credit.

<Note>
  Giá USD được lấy từ DAS và cập nhật mỗi giờ, bao phủ 10.000 token hàng đầu theo vốn hóa thị trường. `pricePerToken` và `usdValue` là `null` đối với các token không được hỗ trợ. Giá chỉ là ước tính, không phải giá thị trường theo thời gian thực.
</Note>

## Khi nào nên sử dụng

Sử dụng Wallet Balances API khi cần:

* **Hiển thị tài sản trong danh mục đầu tư**: cho người dùng xem toàn bộ token và NFT họ đang nắm giữ.
* **Tính giá trị USD**: lấy định giá danh mục đầu tư với dữ liệu giá được cập nhật mỗi giờ.
* **Xây dựng giao diện ví**: cung cấp dữ liệu cho bảng điều khiển ví và danh sách tài sản.
* **Theo dõi lượng token nắm giữ**: giám sát số dư của các token cụ thể trên nhiều ví.
* **Phân tích danh mục đầu tư**: phân tích mức độ phân bổ và tập trung tài sản.
* **Báo cáo thuế**: tạo bản chụp tài sản nắm giữ phục vụ mục đích thuế.

## Bắt đầu nhanh

### Truy vấn số dư cơ bản

Lấy toàn bộ số dư token của một ví kèm theo giá trị USD:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"}
    const getWalletBalances = async (address) => {
      const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY`;

      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      const data = await response.json();

      const solBalance = data.balances[0]; // SOL is always first when showNative=true
      console.log(`SOL Balance: ${solBalance.balance} SOL ($${solBalance.usdValue})`);
      console.log(`Page ${data.pagination.page} Total Value: $${data.totalUsdValue}`);
      console.log(`Token Count (this page): ${data.balances.length}`);

      // Display top holdings
      data.balances.slice(0, 5).forEach(token => {
        console.log(`${token.symbol}: ${token.balance} ($${token.usdValue || 'N/A'})`);
      });

      return data;
    };

    getWalletBalances("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"system"}
    import requests

    def get_wallet_balances(address: str):
        url = f"https://api.helius.xyz/v1/wallet/{address}/balances"
        headers = {"X-Api-Key": "YOUR_API_KEY"}

        response = requests.get(url, headers=headers)
        response.raise_for_status()

        data = response.json()

        sol_balance = data['balances'][0]  # SOL is always first when showNative=true
        print(f"SOL Balance: {sol_balance['balance']} SOL (${sol_balance['usdValue']})")
        print(f"Page {data['pagination']['page']} Total Value: ${data['totalUsdValue']}")
        print(f"Token Count (this page): {len(data['balances'])}")

        # Display top holdings
        for token in data['balances'][:5]:
            usd_value = token.get('usdValue', 'N/A')
            print(f"{token['symbol']}: {token['balance']} (${usd_value})")

        return data

    get_wallet_balances("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY")
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={"system"}
    curl "https://api.helius.xyz/v1/wallet/86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY/balances?api-key=YOUR_API_KEY"
    ```
  </Tab>
</Tabs>

### Bao gồm NFT trong kết quả

Lấy cả token và NFT trong một yêu cầu bằng `showNfts=true`:

<Tabs>
  <Tab title="JavaScript">
    ```javascript theme={"system"}
    const getWalletWithNfts = async (address) => {
      const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY&showNfts=true`;

      const response = await fetch(url);
      const data = await response.json();

      console.log(`Tokens: ${data.balances.length}`);
      console.log(`NFTs: ${data.nfts?.length || 0}`);

      // Display NFTs
      data.nfts?.forEach(nft => {
        console.log(`NFT: ${nft.name || 'Unnamed'} (${nft.collectionName || 'Unknown Collection'})`);
      });

      return data;
    };

    getWalletWithNfts("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"system"}
    def get_wallet_with_nfts(address: str):
        url = f"https://api.helius.xyz/v1/wallet/{address}/balances"
        params = {
            "api-key": "YOUR_API_KEY",
            "showNfts": "true"
        }

        response = requests.get(url, params=params)
        response.raise_for_status()

        data = response.json()

        print(f"Tokens: {len(data['balances'])}")
        print(f"NFTs: {len(data.get('nfts', []))}")

        # Display NFTs
        for nft in data.get('nfts', []):
            name = nft.get('name', 'Unnamed')
            collection = nft.get('collectionName', 'Unknown Collection')
            print(f"NFT: {name} ({collection})")

        return data

    get_wallet_with_nfts("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY")
    ```
  </Tab>
</Tabs>

### Lọc kết quả

Sử dụng các tham số truy vấn để thu hẹp dữ liệu trả về:

```javascript theme={"system"}
// Only show tokens with non-zero balances
const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY&showZeroBalance=false`;

// Exclude native SOL from results
const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY&showNative=false`;

// Get only the top 50 tokens by value
const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY&limit=50`;
```

## Tham số truy vấn

| Tham số           | Kiểu    | Mặc định | Mô tả                                                        |
| ----------------- | ------- | -------- | ------------------------------------------------------------ |
| `page`            | integer | 1        | Số trang dùng để phân trang (bắt đầu từ 1)                   |
| `limit`           | integer | 100      | Số lượng token tối đa trên mỗi trang (1-100)                 |
| `showZeroBalance` | boolean | false    | Bao gồm các token có số dư bằng 0                            |
| `showNative`      | boolean | true     | Bao gồm SOL gốc trong kết quả                                |
| `showNfts`        | boolean | false    | Bao gồm NFT trong kết quả (tối đa 100, chỉ ở trang đầu tiên) |

## Định dạng phản hồi

```json theme={"system"}
{
  "balances": [
    {
      "mint": "So11111111111111111111111111111111111111111",
      "symbol": "SOL",
      "name": "Solana",
      "balance": 1.5,
      "decimals": 9,
      "pricePerToken": 145.32,
      "usdValue": 217.98,
      "logoUri": "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png",
      "tokenProgram": "spl-token"
    },
    {
      "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "symbol": "USDC",
      "name": "USD Coin",
      "balance": 1000.5,
      "decimals": 6,
      "pricePerToken": 1.0,
      "usdValue": 1000.5,
      "logoUri": "https://example.com/usdc-logo.png",
      "tokenProgram": "spl-token"
    }
  ],
  "nfts": [
    {
      "mint": "7Xq8wXyXVqfBPPqVJjPDwG9zN5wCVxBYZ6z7vPYBzr6F",
      "name": "Degen Ape #1234",
      "imageUri": "https://example.com/nft.png",
      "collectionName": "Degen Ape Academy",
      "collectionAddress": "DegN1dXmU2uYa4n7U9qTh7YNYpK4u8L9qXx7XqYqJfGH",
      "compressed": false
    }
  ],
  "totalUsdValue": 1218.48,
  "pagination": {
    "page": 1,
    "limit": 100,
    "hasMore": true
  }
}
```

### Ghi chú về trường

* **`balance`**: số lượng dễ đọc, đã được điều chỉnh theo số chữ số thập phân — `1.5` có nghĩa là 1,5 SOL và `1000.5` có nghĩa là 1000,5 USDC. Không cần chuyển đổi lamport. Endpoint này không cung cấp trường `amountRaw` thô; nếu cần giá trị số nguyên chính xác, hãy tính giá trị đó dưới dạng `Math.round(balance * 10 ** decimals)`.
* **`decimals`**: chỉ được cung cấp để tham khảo.
* **`pricePerToken` / `usdValue`**: `null` đối với các token không có dữ liệu giá từ DAS (xem ghi chú về giá ở trên).
* **`totalUsdValue`**: tổng giá trị USD chỉ dành cho trang phản hồi hiện tại. Để tính giá trị của toàn bộ danh mục đầu tư, hãy duyệt qua tất cả các trang và cộng `usdValue` của từng số dư.
* **`tokenProgram`**: tiêu chuẩn token mà mỗi token sử dụng — `spl-token` (SPL Token cũ) hoặc `token-2022` (Token Extensions). Cả hai đều được hỗ trợ đầy đủ.

## Trường hợp sử dụng

### Xây dựng bảng điều khiển danh mục đầu tư

Hiển thị tài sản người dùng nắm giữ kèm theo giá trị USD:

```javascript theme={"system"}
const renderPortfolio = async (address) => {
  const { balances, totalUsdValue } = await getWalletBalances(address);

  console.log(`Current Page Value: $${totalUsdValue.toLocaleString()}`);
  console.log(`\nTop Holdings:`);

  // totalUsdValue is page-scoped; paginate before computing full portfolio value.
  balances.slice(0, 10).forEach((token, i) => {
    if (token.usdValue) {
      console.log(`${i + 1}. ${token.symbol}: ${token.balance.toFixed(4)} ($${token.usdValue.toFixed(2)})`);
    }
  });
};
```

### Tính mức độ tập trung token

Phân tích mức độ đa dạng hóa danh mục đầu tư:

```javascript theme={"system"}
const analyzeConcentration = async (address) => {
  const { balances, totalUsdValue } = await getWalletBalances(address);

  const tokensWithValue = balances.filter(t => t.usdValue);

  if (tokensWithValue.length === 0) {
    console.log('No tokens with USD pricing data available');
    return null;
  }

  const topToken = tokensWithValue[0];
  const pageConcentration = (topToken.usdValue / totalUsdValue) * 100;

  console.log(`Largest Position on Current Page: ${topToken.symbol} (${pageConcentration.toFixed(1)}%)`);

  if (pageConcentration > 50) {
    console.log(`Warning: Current page is highly concentrated in ${topToken.symbol}`);
  }

  return { topToken, pageConcentration };
};
```

### Theo dõi số dư của một token cụ thể

Giám sát một token cụ thể trên nhiều ví:

```javascript theme={"system"}
const getTokenBalance = async (address, tokenMint) => {
  const { balances } = await getWalletBalances(address);

  const token = balances.find(t => t.mint === tokenMint);

  if (!token) {
    console.log(`Token not found in wallet`);
    return null;
  }

  console.log(`${token.symbol} Balance: ${token.balance}`);
  console.log(`USD Value: $${token.usdValue || 'N/A'}`);

  return token;
};

// Example: Check USDC balance
getTokenBalance(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC mint
);
```

### Xuất dữ liệu tài sản nắm giữ để báo cáo thuế

Tạo bản chụp tài sản nắm giữ:

```javascript theme={"system"}
const exportHoldingsSnapshot = async (address) => {
  const { balances, totalUsdValue } = await getWalletBalances(address);

  const snapshot = {
    date: new Date().toISOString(),
    address,
    pageValueUSD: totalUsdValue,
    holdings: balances
      .filter(t => t.usdValue)
      .map(t => ({
        symbol: t.symbol,
        mint: t.mint,
        balance: t.balance,
        pricePerToken: t.pricePerToken,
        usdValue: t.usdValue
      }))
  };

  console.log(JSON.stringify(snapshot, null, 2));
  return snapshot;
};
```

## Phân trang

Đối với ví có hơn 100 token, hãy duyệt qua các trang kết quả bằng tham số `page` và `pagination.hasMore`:

```javascript theme={"system"}
const getAllBalances = async (address) => {
  let allBalances = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const url = `https://api.helius.xyz/v1/wallet/${address}/balances?api-key=YOUR_API_KEY&page=${page}&limit=100`;

    const response = await fetch(url);
    const data = await response.json();

    allBalances = allBalances.concat(data.balances);
    hasMore = data.pagination.hasMore;
    page++;

    console.log(`Fetched page ${data.pagination.page}, total tokens so far: ${allBalances.length}`);
  }

  console.log(`Total tokens: ${allBalances.length}`);
  return allBalances;
};
```

NFT chỉ được trả về ở trang đầu tiên (tối đa 100), bất kể cách phân trang token.

## Phương pháp hay nhất

* **Lọc số dư bằng 0 để giao diện gọn gàng hơn.** Sử dụng `showZeroBalance=false` để ẩn các token mà ví không còn nắm giữ.
* **Chỉ bao gồm NFT khi cần.** NFT bị loại trừ theo mặc định để tối ưu hiệu suất; chỉ đặt `showNfts=true` khi cần hiển thị chúng.
* **Xử lý trường hợp thiếu dữ liệu giá.** Luôn kiểm tra xem `pricePerToken` và `usdValue` có phải là `null` hay không trước khi hiển thị. Đây là các giá trị ước tính được cập nhật mỗi giờ từ DAS, không phải giá thị trường theo thời gian thực.
* **Lưu phản hồi vào bộ nhớ đệm.** Dữ liệu số dư có thể được lưu vào bộ nhớ đệm trong vài giây để giảm số lệnh gọi API.
* **Phân trang cho ví lớn.** Một số ví nắm giữ hàng nghìn token; hãy triển khai tính năng phân trang để xử lý hiệu quả.

## Lỗi thường gặp

| Mã lỗi | Mô tả                                     | Giải pháp                                              |
| ------ | ----------------------------------------- | ------------------------------------------------------ |
| 400    | Định dạng địa chỉ ví không hợp lệ         | Xác minh địa chỉ là địa chỉ Solana base58 hợp lệ       |
| 401    | Thiếu khóa API hoặc khóa API không hợp lệ | Kiểm tra xem khóa API đã được đưa vào yêu cầu hay chưa |
| 429    | Vượt quá giới hạn tốc độ                  | Giảm tần suất yêu cầu hoặc nâng cấp gói dịch vụ        |

## Các bước tiếp theo

<CardGroup cols={3}>
  <Card title="Historical Balance" icon="clock" href="/docs/vi/wallet-api/balance-at">
    Lấy số dư token hoặc SOL tại một dấu thời gian, ngày giờ hoặc slot trong quá khứ.
  </Card>

  <Card title="Wallet API Overview" icon="wallet" href="/docs/vi/wallet-api/overview">
    Tất cả các endpoint của Wallet API và các quy ước dùng chung.
  </Card>

  <Card title="API Reference" icon="code" href="/docs/vi/api-reference/wallet-api/balances">
    Lược đồ yêu cầu và phản hồi cho số dư ví.
  </Card>
</CardGroup>
