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

# getHistoricalTokenAccountsByOwner

> List the SPL Token and Token-2022 accounts a Solana wallet owned at a past slot or right after a specific transaction, with mint filters and pagination.

> [!NOTE]
>
> `getHistoricalTokenAccountsByOwner` is in Beta. Parameters, pricing, response formats, and data coverage may change.

## Overview

`getHistoricalTokenAccountsByOwner` returns the SPL Token and Token-2022 accounts a wallet owned at a past slot, or immediately after a specific transaction in that slot. It's a Helius-exclusive RPC method. Standard `getTokenAccountsByOwner` only returns current state.

With `jsonParsed` encoding, token amounts use each mint's decimals as of the requested position, so balances reflect what the wallet held at that point in time.

History is available from slot 444,959,999 (September 7, 2026) onward, which is the state at the start of epoch 1030.

`getHistoricalTokenAccountsByOwner` is available on mainnet for Business plans and above, and costs 0 credits per call during the beta period. Pricing is subject to change.

## How it differs from getTokenAccountsByOwner

* **The mint or program filter is optional.** With no filter, you get every token account the wallet owned. To narrow results, set either `mint` or `programId` in the configuration object (the third parameter), not both.
* **The second parameter is the query object** that selects the position in history, not a mint or program filter.
* **`result.value` is an object** with `accounts` and `paginationKey`, not an array.

## Choose a position in history

The second parameter is a query object:

* **Omitted or `{}`**: the latest indexed slot, capped at the requested commitment.
* **`{ "slot": 445000000 }`**: the end of slot 445,000,000.
* **`{ "slot": 445000000, "transactionIndex": 10 }`**: immediately after the transaction at index 10 in that slot executed.

See the [Historical Accounts Guide](https://www.helius.dev/docs/rpc/historical-accounts.md) for how positions work.

## Example request

This request returns the wallet's USDC token accounts at the end of slot 445,000,000:

```bash theme={"system"}
curl https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "getHistoricalTokenAccountsByOwner",
    "params": [
      "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
      { "slot": 445000000 },
      { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "encoding": "jsonParsed" }
    ]
  }'
```

## Paginate through all token accounts

Results are ordered by mint, then by token account address. Each response returns `value.accounts` and `value.paginationKey`, a cursor in the form `<mint>:<tokenAccount>`. Pass it back in the next request until it's `null`.

> [!WARNING]
>
> A page can be short, or even empty, and still include a `paginationKey`. Only a `null` `paginationKey` means you've reached the end.

Always pass an explicit `slot` when you paginate. If you omit it, each page reads the latest indexed slot, so pages can come from different points in time.

```typescript theme={"system"}
const url = `https://mainnet.helius-rpc.com/?api-key=${process.env.HELIUS_API_KEY}`;

async function getTokenAccountsAt(owner: string, slot: number) {
  const accounts = [];
  let paginationKey: string | null = null;

  do {
    const response = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        jsonrpc: "2.0",
        id: "1",
        method: "getHistoricalTokenAccountsByOwner",
        params: [
          owner,
          { slot },
          { encoding: "jsonParsed", limit: 1000, ...(paginationKey && { paginationKey }) },
        ],
      }),
    });
    const { result, error } = await response.json();
    if (error) throw new Error(`${error.code}: ${error.message}`);

    accounts.push(...result.value.accounts);
    paginationKey = result.value.paginationKey;
  } while (paginationKey);

  return accounts;
}

const tokenAccounts = await getTokenAccountsAt("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY", 445000000);
```

## Read the response

Each entry in `value.accounts` has the token account's `pubkey` and an `account` object. The account object has the same fields as `getAccountInfo`, plus `lastUpdatedAt`:

* **`lastUpdatedAt.slot`** and **`lastUpdatedAt.transactionIndex`** identify the write that produced this state.
* **`lastUpdatedAt.slot` of 444,959,999 with a `null` `transactionIndex`** means the token account hasn't changed since history coverage began.
* **`context.slot`** is the latest slot Helius had indexed when it served the request, not the slot you queried.

## Errors

| Code | Meaning |
| - | - |
| `-32018` | The slot is before history coverage begins (slot 444,959,999) |
| `-32004` | The slot is newer than the requested commitment allows. Use `confirmed` or query an older slot |
| `-32602` | Invalid parameters, such as both `mint` and `programId`, a `programId` that isn't a token program, or a `paginationKey` whose mint doesn't match `mint` |
| `-32601` | Method not found. Call your Helius mainnet or Gatekeeper endpoint; the method isn't available on devnet |

## Related methods

> [card] [Historical Accounts Guide](https://www.helius.dev/docs/rpc/historical-accounts.md)
>
> How positions, coverage, and lastUpdatedAt work for historical account methods

> [card] [getHistoricalAccountInfo](https://www.helius.dev/docs/api-reference/rpc/http/gethistoricalaccountinfo.md)
>
> Read a single account at a past slot

> [card] [getTransactionsForAddress](https://www.helius.dev/docs/rpc/gettransactionsforaddress.md)
>
> Find the slot and transactionIndex of the transactions you want to inspect

> [card] [getTokenAccountsByOwnerV2](https://www.helius.dev/docs/api-reference/rpc/http/gettokenaccountsbyownerv2.md)
>
> Paginate through a wallet's current token accounts

## Request Parameters

**owner** `string` *required*

Base-58 encoded address of the wallet that owned the token accounts. Pass the owner wallet, not a token account.

**slot** `number`

Slot to read state at. Returns the account as of the end of this slot. The earliest supported slot is 444959999, the state at the start of epoch 1030. When omitted, reads the latest indexed slot, capped at the requested commitment.

**transactionIndex** `number`

Position of a transaction within the slot. Returns the account state immediately after that transaction executed, instead of at the end of the slot. Requires slot.

**mint** `string`

Return only token accounts for this mint. Can't be combined with programId.

**programId** `string`

Return only token accounts owned by this token program. Can't be combined with mint.

* `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`
* `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`

**encoding** `string` (default: base64)

Encoding format for account data. With jsonParsed, token amounts use the mint's decimals as of the requested position. base58 and binary are not supported.

* `base64`
* `base64+zstd`
* `jsonParsed`

**dataSlice** `object`

Return only a slice of each account's data. Applies to base64 and base64+zstd encodings.

**dataSlice.offset** `number` *required*

Byte offset from which to start reading.

**dataSlice.length** `number` *required*

Number of bytes to return.

**limit** `number` (default: 5000)

Maximum number of token accounts to return (1-5,000).

**paginationKey** `string`

Cursor from the previous response's paginationKey, in the form `&lt;mint&gt;:&lt;tokenAccount&gt;`. When you also set mint, the cursor's mint must match it.

**commitment** `string` (default: finalized)

Commitment level. processed is not supported.

* `finalized`
* `confirmed`

**minContextSlot** `number`

The minimum slot that the request can be evaluated at.


## OpenAPI

````yaml openapi/rpc-http/getHistoricalTokenAccountsByOwner.yaml POST /
openapi: 3.1.0
info:
  title: Solana RPC API
  version: 1.0.0
  description: >-
    Historical Solana token account API for listing the SPL Token and Token-2022
    accounts a wallet owned at a past slot, with optional mint or token program
    filters and cursor-based pagination.
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
  - url: https://mainnet.helius-rpc.com
    description: Mainnet RPC endpoint
security: []
paths:
  /:
    post:
      tags:
        - RPC
      summary: getHistoricalTokenAccountsByOwner
      description: >
        **Beta.** Parameters, response formats, and data coverage may change.


        Returns the SPL Token and Token-2022 accounts a wallet owned at a past
        slot, or

        immediately after a specific transaction within that slot. This Helius
        RPC method

        returns every token account by default. Narrow the results with either a
        mint or a

        token programId in the configuration object.


        Results are ordered by mint, then by token account address. A page can
        be short or

        empty and still return a paginationKey;

        keep paging until paginationKey is null.
      operationId: getHistoricalTokenAccountsByOwner
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - jsonrpc
                - id
                - method
                - params
              properties:
                jsonrpc:
                  type: string
                  enum:
                    - '2.0'
                  example: '2.0'
                  description: The JSON-RPC protocol version.
                  default: '2.0'
                id:
                  type: string
                  example: '1'
                  description: A unique identifier for the request.
                  default: '1'
                method:
                  type: string
                  enum:
                    - getHistoricalTokenAccountsByOwner
                  example: getHistoricalTokenAccountsByOwner
                  description: The name of the RPC method to invoke.
                  default: getHistoricalTokenAccountsByOwner
                params:
                  type: array
                  description: >-
                    Array containing the owner wallet address, an optional query
                    object that selects the position in history, and an optional
                    configuration object.
                  minItems: 1
                  maxItems: 3
                  default:
                    - 86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY
                    - slot: 445000000
                    - encoding: jsonParsed
                      limit: 2
                  items:
                    oneOf:
                      - type: string
                        title: Owner
                        description: >-
                          Base-58 encoded address of the wallet that owned the
                          token accounts. Pass the owner wallet, not a token
                          account.
                        example: 86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY
                      - $ref: '#/components/schemas/HistoricalAccountQuery'
                        title: Query
                      - type: object
                        title: Configuration
                        description: >-
                          Optional configuration object. Set at most one of mint
                          or programId.
                        properties:
                          mint:
                            type: string
                            description: >-
                              Return only token accounts for this mint. Can't be
                              combined with programId.
                            example: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
                          programId:
                            type: string
                            description: >-
                              Return only token accounts owned by this token
                              program. Can't be combined with mint.
                            enum:
                              - TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
                              - TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
                            example: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
                          encoding:
                            type: string
                            description: >-
                              Encoding format for account data. With jsonParsed,
                              token amounts use the mint's decimals as of the
                              requested position. base58 and binary are not
                              supported.
                            enum:
                              - base64
                              - base64+zstd
                              - jsonParsed
                            default: base64
                            example: jsonParsed
                          dataSlice:
                            $ref: '#/components/schemas/DataSliceConfig'
                          limit:
                            type: integer
                            description: >-
                              Maximum number of token accounts to return
                              (1-5,000).
                            minimum: 1
                            maximum: 5000
                            default: 5000
                            example: 1000
                          paginationKey:
                            type: string
                            description: >-
                              Cursor from the previous response's paginationKey,
                              in the form `<mint>:<tokenAccount>`. When you also
                              set mint, the cursor's mint must match it.
                            example: >-
                              11112zAgXhc6hGfdfr5anSY91mq7Cs4HHpSVEQc4ASG:EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD
                          commitment:
                            type: string
                            description: Commitment level. processed is not supported.
                            enum:
                              - finalized
                              - confirmed
                            default: finalized
                            example: finalized
                          minContextSlot:
                            type: integer
                            description: >-
                              The minimum slot that the request can be evaluated
                              at.
                            example: 445000000
                        additionalProperties: false
      responses:
        '200':
          description: Successfully retrieved a page of historical token accounts.
          content:
            application/json:
              schema:
                type: object
                properties:
                  jsonrpc:
                    type: string
                    description: The JSON-RPC protocol version.
                    enum:
                      - '2.0'
                    example: '2.0'
                  id:
                    type: string
                    description: Identifier matching the request.
                    example: '1'
                  result:
                    type: object
                    properties:
                      context:
                        $ref: '#/components/schemas/HistoricalContext'
                      value:
                        type: object
                        properties:
                          accounts:
                            type: array
                            description: >-
                              Token accounts on this page, ordered by mint and
                              then by token account address.
                            items:
                              $ref: '#/components/schemas/HistoricalKeyedAccount'
                          paginationKey:
                            oneOf:
                              - type: string
                              - type: 'null'
                            description: >-
                              Cursor for the next page, in the form
                              `<mint>:<tokenAccount>`, or null once every
                              account has been returned. A short or empty page
                              with a paginationKey means the scan stopped early,
                              not that you've reached the end.
                            example: >-
                              11112zAgXhc6hGfdfr5anSY91mq7Cs4HHpSVEQc4ASG:EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD
        '400':
          description: Bad Request - Invalid request parameters or malformed request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32602
                  message: Invalid params
                id: '1'
        '401':
          description: Unauthorized - Invalid or missing API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32001
                  message: Unauthorized
                id: '1'
        '429':
          description: Too Many Requests - Rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32005
                  message: Too many requests
                id: '1'
        '500':
          description: Internal Server Error - An error occurred on the server.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32603
                  message: Internal error
                id: '1'
        '503':
          description: Service Unavailable - The service is temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32002
                  message: Service unavailable
                id: '1'
        '504':
          description: Gateway Timeout - The request timed out.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                jsonrpc: '2.0'
                error:
                  code: -32003
                  message: Gateway timeout
                id: '1'
      security:
        - ApiKeyQuery: []
components:
  schemas:
    HistoricalAccountQuery:
      type: object
      description: >-
        The position in history to read. Omit it, or send an empty object, to
        read the latest indexed slot.
      properties:
        slot:
          type: integer
          description: >-
            Slot to read state at. Returns the account as of the end of this
            slot. The earliest supported slot is 444959999, the state at the
            start of epoch 1030. When omitted, reads the latest indexed slot,
            capped at the requested commitment.
          minimum: 444959999
          example: 445000000
        transactionIndex:
          type: integer
          description: >-
            Position of a transaction within the slot. Returns the account state
            immediately after that transaction executed, instead of at the end
            of the slot. Requires slot.
          minimum: 0
          maximum: 16777214
          example: 10
      additionalProperties: false
    DataSliceConfig:
      type: object
      description: >-
        Return only a slice of each account's data. Applies to base64 and
        base64+zstd encodings.
      properties:
        offset:
          type: integer
          description: Byte offset from which to start reading.
          example: 0
        length:
          type: integer
          description: Number of bytes to return.
          example: 8
      required:
        - offset
        - length
    HistoricalContext:
      type: object
      description: Response metadata.
      properties:
        slot:
          type: integer
          description: >-
            The latest slot the history store had indexed when it served the
            request. This is not the slot you queried.
          example: 468129571
    HistoricalKeyedAccount:
      type: object
      properties:
        pubkey:
          type: string
          description: Base-58 encoded address of the token account.
          example: EKyGnXReqmmXyqBHmMjV2CKCLafJS47xyhXXZ5WuFMxD
        account:
          $ref: '#/components/schemas/HistoricalAccount'
      required:
        - pubkey
        - account
    ErrorResponse:
      type: object
      properties:
        jsonrpc:
          type: string
          description: The JSON-RPC protocol version.
          enum:
            - '2.0'
          example: '2.0'
        error:
          type: object
          properties:
            code:
              type: integer
              description: The error code.
              example: -32602
            message:
              type: string
              description: The error message.
            data:
              type: object
              description: Additional data about the error.
        id:
          type: string
          description: Identifier matching the request.
          example: '1'
    HistoricalAccount:
      type: object
      description: >-
        The account as it was at the requested position, plus where that state
        was last written.
      properties:
        lamports:
          type: integer
          description: Number of lamports assigned to this account.
          example: 531589475273
        owner:
          type: string
          description: Base-58 encoded pubkey of the program this account was assigned to.
          example: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
        data:
          description: >-
            Account data. With base64 or base64+zstd, a two-item array of the
            encoded data and the encoding. With jsonParsed, an object with
            program, parsed, and space. Accounts that can't be parsed fall back
            to the base64 array.
          oneOf:
            - type: array
              items:
                type: string
            - type: object
              properties:
                program:
                  type: string
                  description: Name of the program that owns the account.
                  example: spl-token
                parsed:
                  type: object
                  description: Program-specific parsed account state.
                space:
                  type: integer
                  description: Data size of the account.
                  example: 82
        executable:
          type: boolean
          description: Whether the account contains a program.
          example: false
        rentEpoch:
          type: integer
          description: >-
            The epoch at which this account will next owe rent. Rent-exempt
            accounts report the maximum u64 value.
        space:
          type: integer
          description: Data size of the account in bytes.
          example: 82
        lastUpdatedAt:
          $ref: '#/components/schemas/AccountWritePosition'
      required:
        - lamports
        - owner
        - data
        - executable
        - rentEpoch
        - space
        - lastUpdatedAt
    AccountWritePosition:
      type: object
      description: >-
        Where the returned state was last written, at or before the requested
        position.
      properties:
        slot:
          type: integer
          description: >-
            Slot of the last write. A value of 444959999 with a null
            transactionIndex means the account has not changed since history
            coverage began.
          example: 444999837
        transactionIndex:
          oneOf:
            - type: integer
            - type: 'null'
          description: >-
            Position of the transaction that made the last write. Null when the
            write happened outside a transaction (for example, epoch rewards),
            or when the account has not changed since history coverage began.
          example: 700
      required:
        - slot
        - transactionIndex
  securitySchemes:
    ApiKeyQuery:
      type: apiKey
      in: query
      name: api-key
      description: >-
        Your Helius API key. You can get one for free in the
        [dashboard](https://dashboard.helius.dev/api-keys).

````

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