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

# Filtering and Pagination

> Page through PrimeVault list endpoints with opaque cursors and resource-specific query filters for transactions, vaults, contacts, and bank accounts.

List endpoints use cursor pagination and resource-specific query filters. The same rules apply to transactions, vaults, contacts, and bank accounts.

## Supported list endpoints

| Resource | Endpoint | JavaScript SDK |
| - | - | - |
| Transactions | `GET /api/external/transactions/` | `getTransactions()` |
| Vaults | `GET /api/external/vaults/` | `getVaults()` |
| Contacts | `GET /api/external/contacts/` | `getContacts()` |
| Bank accounts | `GET /api/external/bank_accounts/` | `getBankAccounts()` |
| Sub-orgs | `GET /api/external/sub_orgs/` | `getSubOrgs()` |

## Query parameters

<ParamField query="limit" type="number">
  Requested page size. The JavaScript SDK default is `20`.
</ParamField>

<ParamField query="cursor" type="string | null">
  Opaque cursor returned by the preceding page. Omit it or send an empty value for the first page.
</ParamField>

<ParamField query="Resource filters" type="string">
  Endpoint-specific filters supplied through `Record<string, string>`.
</ParamField>

Filters are query-string values. Preserve the same filters and page size while following a cursor chain.

## First-page request

The JSON below is a documentation representation of URL parameters; it is not sent as a request body.

<CodeGroup>
  ```http HTTP theme={null}
  GET /api/external/vaults/?limit=20&cursor=&vaultName=Treasury
  ```

  ```json Query parameters theme={null}
  {
    "query": {
      "limit": 20,
      "cursor": null,
      "vaultName": "Treasury"
    }
  }
  ```
</CodeGroup>

## Cursor response

<ResponseField name="results" type="T[]" required>
  Records on the current page.
</ResponseField>

<ResponseField name="nextCursor" type="string | null">
  Opaque cursor to pass as `cursor` when requesting the next page.
</ResponseField>

<ResponseField name="hasNext" type="boolean">
  `true` when another page is available.
</ResponseField>

<CodeGroup>
  ```typescript Type theme={null}
  interface CursorListResponse<T> {
    results: T[];
    nextCursor?: string | null;
    hasNext?: boolean;
  }
  ```

  ```json Example theme={null}
  {
    "results": [
      {
        "id": "vault_123",
        "vaultName": "Treasury Vault"
      }
    ],
    "nextCursor": "eyJpZCI6InZhdWx0XzEyMyJ9",
    "hasNext": true
  }
  ```
</CodeGroup>

<Warning>
  Treat `nextCursor` as opaque. Do not decode it, edit it, construct it, or infer record ordering from it.
</Warning>

## JavaScript SDK example

```typescript theme={null}
let cursor: string | null | undefined = null;

do {
  const page = await apiClient.getVaults(
    { vaultName: "Treasury" },
    20,
    cursor,
  );

  for (const vault of page.results) {
    console.log(vault.id, vault.vaultName);
  }

  cursor = page.hasNext ? page.nextCursor : null;
} while (cursor);
```

## Pagination rules

<Steps>
  <Step title="Request the first page">
    Start with a null or empty cursor.
  </Step>

  <Step title="Check for another page">
    Continue only when `hasNext === true` and `nextCursor` is present.
  </Step>

  <Step title="Request the next page">
    Reuse the preceding `nextCursor` exactly. Keep filters and page size stable across the cursor chain.
  </Step>

  <Step title="Stop">
    Stop when `hasNext` is not `true`.
  </Step>
</Steps>

<Warning>
  * Do not mix cursor responses with legacy page-number fields such as `count`, `next`, or `previous`.
  * Restart from the first page when filters or sort inputs change.
  * Do not assume an empty `results` array means there can never be another page; follow `hasNext`.
</Warning>

## Filtering rules

* Send only filters documented by the resource page.
* Encode every filter value as a string when using the SDK filter map.
* Treat IDs as opaque and organization-scoped.
* Never use a filter to bypass the API user's organization or sub-org permissions.
* When a value is optional, omit the filter instead of sending the string `"undefined"` or `"null"`.


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