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

# Get Stream Wallets

> List the wallets participating in a stream, including each wallet's latest snapshot and pagination metadata

<Note>
  All requests require an API key via the `X-API-Key` header.
  See [Authentication](/sdk/authentication/api-keys) for details.
</Note>

## Overview

`GET /v1/streams/{id}/wallets` returns the wallets that currently have snapshot data for a specific stream, scoped to the organization that owns the API key.

Each returned wallet includes only its latest available snapshot for that stream. This makes the endpoint suitable for leaderboard views, partner dashboards, stream monitoring UIs, CSV exports, and paginated reporting workflows where you need a compact wallet-level summary instead of the full historical timeline.

<Info>
  Results are ordered by `lastSnapshot.rewardsAccumulated` in descending order, so the first wallets in the response are the ones with the highest accumulated rewards.
</Info>

## Endpoint

<CodeGroup>
  ```bash curl theme={null}
  curl -X GET "https://earn.turtle.xyz/v1/streams/550e8400-e29b-41d4-a716-446655440000/wallets?page=1&limit=20" \
    -H "X-API-Key: pk_live_xxxxx"
  ```

  ```typescript TypeScript theme={null}
  const streamId = '550e8400-e29b-41d4-a716-446655440000';
  const page = 1;
  const limit = 20;

  const response = await fetch(
    `https://earn.turtle.xyz/v1/streams/${streamId}/wallets?page=${page}&limit=${limit}`,
    {
      headers: { 'X-API-Key': process.env.TURTLE_SECRET_KEY! },
    }
  );

  const data = await response.json();
  ```
</CodeGroup>

## Parameters

**Path Parameters**

<ParamField path="id" type="uuid" required>
  Stream identifier. This is the unique UUID of the stream whose participant wallets you want to inspect. The API first verifies that this stream belongs to the organization associated with the API key, so a valid UUID alone is not enough: the stream must also be in your organization scope.
</ParamField>

**Query Parameters**

<ParamField query="page" type="integer" default={1}>
  Page number for the paginated result set. Use this to move through the wallet list in stable chunks. Values lower than `1` are normalized by the backend to `1`.
</ParamField>

<ParamField query="limit" type="integer" default={20}>
  Number of wallets to return per page. This is useful when building dashboards, tables, or exports. Values lower than `1` are normalized to `20`, and values above `100` are capped to `100` by the backend.
</ParamField>

## Response Example

```json theme={null}
{
  "data": [
    {
      "userAddress": "0x1111111111111111111111111111111111111111",
      "lastSnapshot": {
        "timestamp": "2026-03-21T00:00:00Z",
        "rewardsAccumulated": "8345000000000000000",
        "rewardsAccumulatedBase": "8345000000000000000",
        "createdAt": "2026-03-21T00:05:00Z",
        "updatedAt": "2026-03-21T00:05:00Z",
        "tvl": "152340.12",
        "baseTvl": "152340.12",
        "netTvl": "149100.20",
        "turtleTvl": "152340.12",
        "turtleNetTvl": "149100.20",
        "baseApr": "0.105",
        "apr": "0.12",
        "customMetrics": {
          "source": "vault-balance",
          "weight": "1.00"
        }
      }
    },
    {
      "userAddress": "0x2222222222222222222222222222222222222222",
      "lastSnapshot": {
        "timestamp": "2026-03-21T00:00:00Z",
        "rewardsAccumulated": "4123000000000000000",
        "rewardsAccumulatedBase": "4123000000000000000",
        "createdAt": "2026-03-21T00:05:00Z",
        "updatedAt": "2026-03-21T00:05:00Z",
        "tvl": "97340.55",
        "baseTvl": "97340.55",
        "netTvl": "95110.40",
        "turtleTvl": "97340.55",
        "turtleNetTvl": "95110.40",
        "baseApr": "0.105",
        "apr": "0.12",
        "customMetrics": {}
      }
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "totalPages": 3
  }
}
```

## Response Semantics

<AccordionGroup>
  <Accordion title="Each row contains the latest snapshot only">
    This endpoint does not return full wallet history. Instead, each wallet entry contains a `lastSnapshot` object representing the most recent snapshot currently available for that wallet in the stream.
  </Accordion>

  <Accordion title="An empty page is a valid response">
    If the stream exists but there are no wallet snapshots yet, or if you request a page beyond the available data, the endpoint returns `data: []` together with pagination metadata instead of failing.
  </Accordion>

  <Accordion title="The stream is organization-scoped">
    Even if you know a valid stream UUID, the API only returns data when that stream belongs to the organization associated with the API key.
  </Accordion>
</AccordionGroup>

## Response Fields

```typescript theme={null}
data: WalletWithLastSnapshot[]
pagination: PaginationResponse
```

<ResponseField name="data" type="WalletWithLastSnapshot[]" required>
  Paginated list of wallets that have snapshot data for the requested stream.
</ResponseField>

<ResponseField name="pagination" type="PaginationResponse" required>
  Pagination metadata describing the current page and the total size of the result set.
</ResponseField>

### `WalletWithLastSnapshot`

<ResponseField name="userAddress" type="string">
  Wallet address that participated in the stream. This is the address whose balances or positions were tracked during snapshot computation. It is returned as an EVM address string.
</ResponseField>

<ResponseField name="lastSnapshot" type="WalletSnapshot">
  Most recent snapshot recorded for that wallet in this stream. This object summarizes the wallet's latest reward accumulation and TVL metrics.
</ResponseField>

### `WalletSnapshot`

APR-related wallet snapshot fields are only populated for token-based streams. For point-based streams, `baseApr` and `apr` are omitted from the snapshot.

<ResponseField name="timestamp" type="datetime">
  Effective timestamp of the snapshot. This is the time bucket the metrics correspond to, not necessarily the exact database write time.
</ResponseField>

<ResponseField name="rewardsAccumulated" type="string">
  Total rewards accumulated by the wallet at this snapshot, expressed in base units. For token streams, that means token wei-like units according to the reward asset decimals. For point streams, this is the accumulated point amount in the point's base precision. This field represents the reward amount after adapters have been applied (post-adapter).
</ResponseField>

<ResponseField name="rewardsAccumulatedBase" type="string">
  Base accumulation value used by Turtle's internal reward accounting. This value reflects the accumulated rewards before adapters are applied (pre-adapter).
</ResponseField>

<ResponseField name="createdAt" type="datetime">
  Timestamp when this wallet snapshot row was first created in Turtle's backend.
</ResponseField>

<ResponseField name="updatedAt" type="datetime">
  Timestamp of the latest update applied to this wallet snapshot row.
</ResponseField>

<ResponseField name="tvl" type="decimal | null">
  Time-weighted-average (TWA) USD Total Value Locked (TVL) for the wallet after adapters have been applied.
</ResponseField>

<ResponseField name="baseTvl" type="decimal | null">
  TWA USD TVL for the wallet before adapters are applied.
</ResponseField>

<ResponseField name="netTvl" type="decimal | null">
  TWA USD TVL of the wallet's net position. Calculated as TWA of min(0, tokenBalance - startBalance) \* priceUSD, where `startBalance` is the user's token balance at the stream's `startTimestamp`. Both `priceUSD` and `tokenBalance` are time-weighted averages (TWA).
</ResponseField>

<ResponseField name="turtleTvl" type="decimal | null">
  TWA USD TVL restricted to Turtle users and windowed to each user's sign-up timestamp. This measures the portion of the wallet's TVL that should be considered for Turtle-specific user eligibility and reward rules.
</ResponseField>

<ResponseField name="turtleNetTvl" type="decimal | null">
  Turtle-equivalent of `netTvl`: a TWA net position calculated using the user's token balance at their sign-up timestamp as the reference instead of the stream `startTimestamp`.
</ResponseField>

<ResponseField name="baseApr" type="decimal | null">
  Base APR computed for the wallet snapshot before adapter adjustments. This is only populated for token-based streams.
</ResponseField>

<ResponseField name="apr" type="decimal | null">
  Effective APR computed for the wallet snapshot after adapter adjustments. This is only populated for token-based streams.
</ResponseField>

<ResponseField name="customMetrics" type="object | null">
  Strategy-specific metrics captured for the wallet snapshot. Treat this field as extensible JSON. Currently, it contains the wallet's TWA token balance for the snapshot.
</ResponseField>

### `PaginationResponse`

<ResponseField name="page" type="integer">
  Current page returned by the backend after normalization.
</ResponseField>

<ResponseField name="limit" type="integer">
  Number of items returned per page after normalization or capping.
</ResponseField>

<ResponseField name="total" type="integer">
  Total number of records available for the stream across all pages.
</ResponseField>

<ResponseField name="totalPages" type="integer">
  Total number of available pages for the current `limit`.
</ResponseField>

## Integration Notes

<AccordionGroup>
  <Accordion title="Use this endpoint for tables and leaderboards">
    Because this endpoint returns one row per wallet with only the latest snapshot, it is the best choice for ranking views, summary widgets, CSV exports, and admin pages where full historical data would be too heavy.
  </Accordion>

  <Accordion title="Amounts are returned as strings on purpose">
    Reward amounts are serialized as strings to avoid precision loss in JavaScript and other environments that cannot safely represent very large integers. Keep them as strings in transit and convert them with a big-number library only when you need arithmetic.
  </Accordion>

  <Accordion title="Use the single-wallet endpoint for history">
    If you need the full timeline of snapshots for one wallet, call [Get Wallet Data](/sdk/streams/get-wallet) instead of this paginated summary endpoint.
  </Accordion>
</AccordionGroup>

## Error Handling

<AccordionGroup>
  <Accordion title="Missing or invalid API key">
    **Status Code:** 401 Unauthorized

    ```json theme={null}
    {
      "error": "Invalid API key"
    }
    ```

    **Solution:** Pass a valid `X-API-Key` header belonging to an organization-scoped API key.
  </Accordion>

  <Accordion title="Stream not found in your organization scope">
    **Status Code:** 404 Not Found

    This happens when the `id` path parameter does not correspond to a stream owned by the organization associated with the API key.
  </Accordion>

  <Accordion title="Unexpected internal error">
    **Status Code:** 500 Internal Server Error

    **Solution:** Retry the request and contact Turtle if the issue persists.
  </Accordion>
</AccordionGroup>
