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

# Cara Menggunakan getTokenAccountsByOwner

> Pelajari kasus penggunaan getTokenAccountsByOwner, contoh kode, parameter permintaan, struktur respons, dan tips.

Metode RPC [`getTokenAccountsByOwner`](https://www.helius.dev/docs/api-reference/rpc/http/gettokenaccountsbyowner) digunakan untuk mengambil semua [akun token](https://www.helius.dev/blog/how-to-get-token-holders-on-solana) SPL yang dimiliki oleh kunci publik tertentu. Metode ini sangat penting bagi dompet dan aplikasi yang perlu menampilkan kepemilikan token pengguna atau berinteraksi dengan berbagai akun token mereka.

Anda harus memfilter kueri berdasarkan token `mint` tertentu atau `programId` (misalnya, Program Token SPL atau Program Token-2022).

Untuk dompet dengan portofolio token yang besar, pertimbangkan untuk menggunakan [`getTokenAccountsByOwnerV2`](/docs/id/api-reference/rpc/http/gettokenaccountsbyownerv2), yang menyediakan dukungan paginasi berbasis kursor dengan ukuran halaman yang dapat dikonfigurasi hingga 10.000 akun per permintaan.

## Kasus Penggunaan Umum

* **Menampilkan Portofolio Pengguna:** Mengambil semua akun token (dan dengan demikian saldonya) untuk alamat dompet pengguna tertentu guna menampilkan portofolio token lengkap mereka.
* **Logika Aplikasi:** Mengidentifikasi akun token tertentu milik pengguna untuk mint tertentu sebelum memulai transfer atau interaksi lainnya.
* **Verifikasi:** Memeriksa akun token yang dimiliki oleh seorang pemilik untuk jenis token tertentu.
* **Mengindeks Pemilik Token:** Meskipun kurang efisien untuk pengindeksan global dibandingkan metode lain, metode ini dapat digunakan untuk menemukan akun bagi sekumpulan pemilik yang diketahui.

## Parameter Permintaan

1. **`ownerPubkey`** (string, wajib): Kunci publik pemilik akun yang dikodekan dengan base-58, yang akun tokennya ingin Anda ambil.

2. **`filter`** (object, wajib): Object JSON yang **harus** menentukan `mint` atau `programId`:
   * **`mint`** (string): Kunci publik mint token tertentu yang dikodekan dengan base-58. Jika diberikan, hanya akun token untuk mint ini yang dimiliki oleh `ownerPubkey` yang akan dikembalikan.
   * **`programId`** (string): Kunci publik Program Token yang mengatur akun, yang dikodekan dengan base-58. Nilai yang umum adalah:
     * Program Token SPL: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`
     * Program Token-2022: `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`

3. **`options`** (object, opsional): Object konfigurasi opsional yang dapat mencakup:
   * **`commitment`** (string, opsional): Menentukan [tingkat komitmen](https://www.helius.dev/blog/solana-commitment-levels).
   * **`encoding`** (string, opsional): Pengodean untuk data akun. `"jsonParsed"` sangat direkomendasikan. Opsi lainnya: `"base64"`, `"base64+zstd"`. Nilai defaultnya adalah `"base64"`.
   * **`dataSlice`** (object, opsional): Untuk mengambil potongan tertentu dari data akun (`offset`: usize, `length`: usize). Hanya untuk pengodean `base58`, `base64`, atau `base64+zstd`.
   * **`minContextSlot`** (u64, opsional): Slot minimum untuk kueri.

## Struktur Respons

Kolom `result.value` dalam respons JSON-RPC adalah array object. Setiap object sesuai dengan akun Token SPL yang dimiliki oleh `ownerPubkey` dan cocok dengan `filter`.

Setiap object dalam array `value` berisi:

* **`pubkey`** (string): Kunci publik akun token itu sendiri yang dikodekan dengan base-58.
* **`account`** (object): Informasi mendetail tentang akun token:
  * **`lamports`** (u64): Saldo lamport untuk pembebasan biaya sewa.
  * **`owner`** (string): Program pemilik (misalnya, kunci publik Program Token).
  * **`data`**: Data akun. Jika pengodean `"jsonParsed"` digunakan, bagian ini berisi:
    * **`program`** (string): misalnya, `"spl-token"`.
    * **`parsed`**: Object dengan informasi terstruktur:
      * **`info`**: Detail seperti:
        * **`mint`** (string): Alamat mint token.
        * **`owner`** (string): Pemilik akun token (harus cocok dengan `ownerPubkey` dari permintaan).
        * **`tokenAmount`** (object): Saldo token (`amount`, `decimals`, `uiAmount`, `uiAmountString`).
        * **`state`** (string): Status akun token (misalnya, `"initialized"`).
        * **`isNative`** (boolean): Menunjukkan apakah akun menyimpan SOL terbungkus.
        * **`delegate`** (string, opsional): Alamat delegasi jika ditetapkan.
        * **`delegatedAmount`** (object, opsional): Jumlah yang didelegasikan jika delegasi ditetapkan.
      * **`type`** (string): misalnya, `"account"`.
  * **`executable`** (boolean): Menunjukkan apakah akun dapat dieksekusi.
  * **`rentEpoch`** (u64): Epoch berikutnya saat biaya sewa jatuh tempo.
  * **`space`** (u64, jika bukan `jsonParsed`): Panjang data mentah akun dalam byte.

**Contoh Respons (dengan pengodean `jsonParsed`, difilter berdasarkan `programId`):**

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 183459000
    },
    "value": [
      {
        "pubkey": "AssociatedTokenAccountPubkey1...",
        "account": {
          "data": {
            "program": "spl-token",
            "parsed": {
              "info": {
                "isNative": false,
                "mint": "SomeTokenMintPubkey...",
                "owner": "OwnerPubkeyProvidedInRequest...",
                "state": "initialized",
                "tokenAmount": {
                  "amount": "1000000000", // 1 token if decimals is 9
                  "decimals": 9,
                  "uiAmount": 1.0,
                  "uiAmountString": "1.0"
                }
              },
              "type": "account"
            },
            "space": 165
          },
          "executable": false,
          "lamports": 2039280,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 380
        }
      },
      {
        "pubkey": "AnotherAssociatedTokenAccountPubkey...",
        "account": {
          // ... similar structure for another token owned by the same owner
        }
      }
    ]
  },
  "id": 1
}
```

## Contoh Kode

<CodeGroup>
  ```bash cURL theme={"system"}
  # Replace <OWNER_PUBKEY> and <TOKEN_MINT_PUBKEY> or <TOKEN_PROGRAM_ID>

  # Example filtering by programId (SPL Token Program)
  curl -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getTokenAccountsByOwner",
      "params": [
        "<OWNER_PUBKEY>",
        { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
        { "encoding": "jsonParsed" }
      ]
    }' \
    <YOUR_RPC_URL>

  # Example filtering by a specific mint
  curl -X POST -H "Content-Type: application/json" -d \
    '{
      "jsonrpc": "2.0",
      "id": 1,
      "method": "getTokenAccountsByOwner",
      "params": [
        "<OWNER_PUBKEY>",
        { "mint": "<SPECIFIC_TOKEN_MINT_PUBKEY>" },
        { "encoding": "jsonParsed", "commitment": "confirmed" }
      ]
    }' \
    <YOUR_RPC_URL>
  ```

  ```javascript JavaScript (using @solana/web3.js) theme={"system"}
  const { Connection, PublicKey } = require('@solana/web3.js');

  async function findOwnerTokenAccounts(ownerAddress, filter, encoding = 'jsonParsed') {
    // Replace with your RPC endpoint
    const connection = new Connection('https://mainnet.helius-rpc.com/?api-key=<api-key>');
    const ownerPubKey = new PublicKey(ownerAddress);

    try {
      let actualFilter;
      if (filter.mint) {
        actualFilter = { mint: new PublicKey(filter.mint) };
      } else if (filter.programId) {
        actualFilter = { programId: new PublicKey(filter.programId) };
      } else {
        console.error("Filter must contain either 'mint' or 'programId'");
        return;
      }

      const accounts = await connection.getTokenAccountsByOwner(
        ownerPubKey,
        actualFilter,
        { encoding }
      );

      console.log(`Found ${accounts.value.length} token accounts for owner ${ownerAddress}:`);
      accounts.value.forEach(accInfo => {
        console.log(`  Token Account: ${accInfo.pubkey.toBase58()}`);
        if (encoding === 'jsonParsed' && accInfo.account.data.parsed) {
          console.log(`    Mint: ${accInfo.account.data.parsed.info.mint}`);
          console.log(`    Balance: ${accInfo.account.data.parsed.info.tokenAmount.uiAmountString}`);
        }
        // console.log(JSON.stringify(accInfo, null, 2)); // For full details
      });

    } catch (error) {
      console.error(`Error fetching token accounts for owner ${ownerAddress}:`, error);
    }
  }

  // Replace with an actual owner's public key
  const exampleOwner = 'HXtBm8XZbxaTt41uqaKhwUAa6Z1aPyvJdsZVENiWsetg'; // Example wallet address

  // Example 1: Find all SPL Token Program accounts owned by `exampleOwner`
  findOwnerTokenAccounts(exampleOwner, { programId: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' });

  // Example 2: Find USDC token accounts owned by `exampleOwner`
  // const usdcMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
  // findOwnerTokenAccounts(exampleOwner, { mint: usdcMint });

  // Example 3: Find Token-2022 Program accounts owned by `exampleOwner`
  // findOwnerTokenAccounts(exampleOwner, { programId: 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb' });
  ```
</CodeGroup>

## Tips untuk Developer

* **Persyaratan Filter:** Anda *harus* memberikan `mint` atau `programId` dalam filter. Anda tidak dapat mengueri semua akun token milik seorang pemilik di seluruh jenis token tanpa salah satu filter utama ini.
* **Akun Token Terkait:** Metode ini akan mengembalikan semua akun token yang dimiliki oleh kunci publik tersebut, termasuk Associated Token Account (ATA) standar dan akun token SPL lain yang mungkin dimilikinya (misalnya, dari implementasi dompet lama atau konfigurasi khusus).
* **Pengodean:** Penggunaan `"jsonParsed"` untuk opsi `encoding` sangat direkomendasikan. Opsi ini mendekode data akun biner menjadi struktur JSON yang lebih mudah digunakan.
* **Performa:** Jika seorang pemilik memiliki akun token dalam jumlah sangat besar (terutama saat hanya memfilter berdasarkan `programId`), responsnya dapat berukuran besar. Untuk kasus seperti ini, gunakan [`getTokenAccountsByOwnerV2`](/docs/id/api-reference/rpc/http/gettokenaccountsbyownerv2), yang menyediakan dukungan paginasi bawaan.
* **Token-2022 (Ekstensi Token):** Jika Anda menggunakan token yang dibuat dengan program Token-2022 (yang mendukung ekstensi seperti biaya transfer, bunga, dan sebagainya), pastikan Anda menggunakan `programId` yang benar: `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`.

Panduan ini memberikan pemahaman menyeluruh tentang metode RPC `getTokenAccountsByOwner` sehingga Anda dapat mengambil informasi akun token untuk alamat Solana apa pun secara efisien.

## Paginasi untuk Portofolio Token Besar

Untuk dompet dengan kepemilikan token yang besar, gunakan [`getTokenAccountsByOwnerV2`](/docs/id/api-reference/rpc/http/gettokenaccountsbyownerv2), yang menyediakan:

* **Paginasi berbasis kursor**: Atur `limit` (1–10.000) dan gunakan `paginationKey` untuk menavigasi hasil
* **Pembaruan inkremental**: Gunakan `changedSinceSlot` untuk hanya mengambil akun token yang diubah sejak slot tertentu
* **Performa lebih baik**: Mencegah timeout dan memungkinkan pelacakan portofolio secara real-time
* **Perilaku paginasi**: Akhir paginasi hanya ditunjukkan ketika tidak ada akun token yang dikembalikan. Jumlah akun yang dikembalikan mungkin lebih sedikit daripada batas karena pemfilteran—lanjutkan paginasi hingga `paginationKey` bernilai null

```typescript theme={"system"}
// Example: Paginated query for all token accounts
const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "1",
    method: "getTokenAccountsByOwnerV2",
    params: [
      "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      {
        encoding: "jsonParsed",
        limit: 1000
      }
    ]
  })
});

const data = await response.json();
console.log(`Found ${data.result.value.length} token accounts`);
if (data.result.paginationKey) {
  console.log("More results available, use paginationKey for next page");
  // Continue pagination even if fewer than limit accounts were returned
} else {
  console.log("End of pagination - no more token accounts available");
}
```

## Metode Terkait

<CardGroup cols={2}>
  <Card title="getTokenAccountsByOwnerV2" href="/docs/id/api-reference/rpc/http/gettokenaccountsbyownerv2">
    Versi dengan paginasi dan navigasi berbasis kursor untuk portofolio besar
  </Card>

  <Card title="getTokenAccountBalance" href="/docs/id/api-reference/rpc/http/gettokenaccountbalance">
    Dapatkan saldo akun token tertentu
  </Card>
</CardGroup>
