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

# Pagination

> Cursor-based pagination for CDP API list endpoints.

All list endpoints in the CDP API use **cursor-based pagination**. Instead of page numbers, each response returns a `nextPageToken` that you pass back to fetch the next page. This approach is stable across inserts and deletes and scales to arbitrarily large result sets.

## Request parameters

List endpoints accept two query parameters:

| Parameter   | Type    | Default  | Description                                                                 |
| ----------- | ------- | -------- | --------------------------------------------------------------------------- |
| `pageSize`  | integer | `20`     | Number of resources to return per page. Most endpoints cap at `100`.        |
| `pageToken` | string  | *(none)* | Opaque cursor returned by the previous response. Omit on the first request. |

## Response field

Every paginated response includes a top-level `nextPageToken`:

```json theme={null}
{
  "transfers": [
    { "transferId": "transfer_..." },
    { "transferId": "transfer_..." }
  ],
  "nextPageToken": "eyJsYXN0X2lkIjogImFiYzEyMyIsICJ0aW1lc3RhbXAiOiAxNzA3ODIzNzAxfQ=="
}
```

When you reach the end of the result set, `nextPageToken` is omitted or returned as an empty string. That is the signal to stop iterating.

<Note>
  The collection field name is resource-specific, not a generic `data`. For example, `GET /v2/transfers` returns `transfers`, `GET /v2/accounts` returns `accounts`, and `GET /v2/deposit-destinations` returns `depositDestinations`. Check the endpoint's response schema for the exact field name.
</Note>

<Tip>
  Treat `nextPageToken` as an opaque string. Don't try to decode, parse, or construct it — the format is internal and may change.
</Tip>

## Example: fetch the first page

```http theme={null}
GET /v2/transfers?pageSize=25
```

## Example: fetch the next page

```http theme={null}
GET /v2/transfers?pageSize=25&pageToken=eyJsYXN0X2lkIjogImFiYzEyMyJ9
```

## Iterating through all results

A typical pattern: keep calling the endpoint with the previous response's `nextPageToken` until it stops coming back.

<CodeGroup>
  ```typescript TypeScript lines wrap theme={null}
  async function listAllTransfers() {
    const results = [];
    let pageToken: string | undefined;

    do {
      const url = new URL("https://api.cdp.coinbase.com/platform/v2/transfers");
      url.searchParams.set("pageSize", "100");
      if (pageToken) url.searchParams.set("pageToken", pageToken);

      const res = await fetch(url, {
        headers: { Authorization: `Bearer ${jwt}` },
      });
      const body = await res.json();

      results.push(...body.transfers);
      pageToken = body.nextPageToken || undefined;
    } while (pageToken);

    return results;
  }
  ```

  ```python Python lines wrap theme={null}
  import requests

  def list_all_transfers(jwt: str):
      results = []
      page_token = None

      while True:
          params = {"pageSize": 100}
          if page_token:
              params["pageToken"] = page_token

          res = requests.get(
              "https://api.cdp.coinbase.com/platform/v2/transfers",
              headers={"Authorization": f"Bearer {jwt}"},
              params=params,
          )
          body = res.json()

          results.extend(body["transfers"])
          page_token = body.get("nextPageToken")
          if not page_token:
              break

      return results
  ```

  ```go Go lines wrap theme={null}
  func listAllTransfers(jwt string) ([]Transfer, error) {
      var results []Transfer
      pageToken := ""

      for {
          req, _ := http.NewRequest("GET", "https://api.cdp.coinbase.com/platform/v2/transfers", nil)
          req.Header.Set("Authorization", "Bearer "+jwt)

          q := req.URL.Query()
          q.Set("pageSize", "100")
          if pageToken != "" {
              q.Set("pageToken", pageToken)
          }
          req.URL.RawQuery = q.Encode()

          res, err := http.DefaultClient.Do(req)
          if err != nil {
              return nil, err
          }

          var body struct {
              Transfers     []Transfer `json:"transfers"`
              NextPageToken string     `json:"nextPageToken"`
          }
          if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
              res.Body.Close()
              return nil, err
          }
          res.Body.Close()

          results = append(results, body.Transfers...)
          if body.NextPageToken == "" {
              break
          }
          pageToken = body.NextPageToken
      }

      return results, nil
  }
  ```
</CodeGroup>

## Best practices

* **Use the largest `pageSize` your workload can handle** to reduce the number of round-trips. For bulk reads, prefer `100` over the default `20`.
* **Persist the `nextPageToken`** if you need to resume iteration across processes or sessions.
* **Don't reorder results between requests.** Cursors encode the result set's ordering at the time of the first request; sorting client-side after each page is safe, but changing query filters mid-iteration is not.
* **Stop on missing or empty `nextPageToken`** — that's the end-of-results signal, not an error.
* **Combine with [rate limits](/api-reference/v2/rate-limits)** in mind: pull pages serially rather than in parallel.

## What to read next

<CardGroup cols={2}>
  <Card title="Conventions" icon="book" href="/api-reference/v2/conventions">
    Shared formatting standards (IDs, amounts, timestamps)
  </Card>

  <Card title="Rate limits" icon="gauge-high" href="/api-reference/v2/rate-limits">
    Per-window limits and backoff guidance
  </Card>
</CardGroup>
