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

# Wallet Activity

> Query deposit and withdrawal history for any wallet address.

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

## Overview

`GET /v2/wallets/activity/`

The Wallet Activity endpoint returns on-chain earn interactions (deposits and withdrawals) for one or more wallet addresses across all opportunities and distributors. Results are ordered by date descending.

This is a **wallet-scoped** endpoint. For distributor-scoped activity, see [Distributor Activity](/sdk/earn-api/deposits). To pick between the three views (positions, wallet activity, distributor activity), see the [Portfolio & Activity overview](/sdk/portfolio/overview).

## Endpoint

### Get Wallet Activity

<CodeGroup>
  ```bash curl theme={null}
  curl "https://earn.turtle.xyz/v2/wallets/activity/?addresses=0x3191F53d4d652F9cF37F74c554070d95e710c07f&page=1&limit=20" \
    -H "X-API-Key: pk_live_xxxxx"
  ```

  ```typescript TypeScript theme={null}
  const response = await fetch(
    'https://earn.turtle.xyz/v2/wallets/activity/?addresses=0x3191F53d4d652F9cF37F74c554070d95e710c07f&page=1&limit=20',
    { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
  );
  const data = await response.json();
  ```
</CodeGroup>

**Query Parameters**

<ParamField query="addresses" type="string" required>
  Comma-separated list of EVM wallet addresses. Maximum 1000 addresses per request. Addresses are case-insensitive.
</ParamField>

<ParamField query="page" type="integer" default="1">
  Page number for pagination.
</ParamField>

<ParamField query="limit" type="integer" default="20">
  Results per page (max: 100).
</ParamField>

<Note>
  This is a GET endpoint. Pass all parameters in the query string; do not send a request body.
</Note>

## Response Example

```json theme={null}
{
  "activity": [
    {
      "id": "uuid",
      "opportunityId": "uuid",
      "interaction": "deposit",
      "txHash": "0xabc...",
      "chainId": 1,
      "blockTimestamp": "2024-11-01T12:00:00Z",
      "walletAddress": "0xabc...",
      "amountToken": "100.00",
      "amountInUsd": "99.50",
      "tokenSymbol": "USDC",
      "tokenIconUrl": "https://...",
      "isSwap": false
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "totalPages": 3,
    "hasNext": true,
    "hasPrevious": false
  }
}
```

## Response Fields

<ResponseField name="activity" type="array">
  Array of activity items. Each item uses the same activity-item shape as the deposit items returned by [Distributor Activity](/sdk/earn-api/deposits), with one difference: `interaction` is `deposit` or `withdraw` here, where the distributor endpoint always returns `deposit`.
</ResponseField>

<ResponseField name="activity[].interaction" type="string">
  Type of interaction. One of `deposit` or `withdraw`.
</ResponseField>

<ResponseField name="pagination" type="object">
  Pagination metadata. Same shape as the pagination object on [Distributor Activity](/sdk/earn-api/deposits).
</ResponseField>

<ResponseField name="pagination.page" type="integer">
  Current page number.
</ResponseField>

<ResponseField name="pagination.limit" type="integer">
  Results per page.
</ResponseField>

<ResponseField name="pagination.total" type="integer">
  Total number of matching interactions.
</ResponseField>

<ResponseField name="pagination.totalPages" type="integer">
  Total number of pages.
</ResponseField>

<ResponseField name="pagination.hasNext" type="boolean">
  Whether a next page exists.
</ResponseField>

<ResponseField name="pagination.hasPrevious" type="boolean">
  Whether a previous page exists.
</ResponseField>

## Use Cases

### Display Wallet Transaction History

Build a transaction history view for a user's portfolio page.

```typescript theme={null}
const getWalletHistory = async (walletAddress: string) => {
  const response = await fetch(
    `https://earn.turtle.xyz/v2/wallets/activity/?addresses=${walletAddress}&limit=50`,
    { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
  );
  const { activity, pagination } = await response.json();

  return { activity, pagination };
};
```

### Query Multiple Wallets

Fetch activity across multiple wallets in a single request. Useful for users with multiple addresses or for building aggregate views.

```typescript theme={null}
const addresses = [
  '0x3191F53d4d652F9cF37F74c554070d95e710c07f',
  '0xa1E7Db8d88BEd2bA0bEFb9bda654b98631c4b305'
].join(',');

const response = await fetch(
  `https://earn.turtle.xyz/v2/wallets/activity/?addresses=${addresses}&page=1&limit=100`,
  { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
);
const { activity } = await response.json();
```

### Paginate Through All Results

```typescript theme={null}
const getAllActivity = async (walletAddress: string) => {
  let page = 1;
  let allActivity = [];

  while (true) {
    const response = await fetch(
      `https://earn.turtle.xyz/v2/wallets/activity/?addresses=${walletAddress}&page=${page}&limit=100`,
      { headers: { 'X-API-Key': 'pk_live_xxxxx' } }
    );
    const { activity, pagination } = await response.json();
    allActivity.push(...activity);

    if (!pagination.hasNext) break;
    page++;
  }

  return allActivity;
};
```

## Wallet Activity vs Distributor Activity

|                  | Wallet Activity                | [Distributor Activity](/sdk/earn-api/deposits) |
| ---------------- | ------------------------------ | ---------------------------------------------- |
| **Endpoint**     | `GET /v2/wallets/activity/`    | `GET /v2/deposit/{distributorId}`              |
| **Scoped by**    | Wallet address(es)             | Distributor ID                                 |
| **Interactions** | Deposits + withdrawals         | Deposits only                                  |
| **Best for**     | Portfolio UIs, user dashboards | Distributor attribution tracking               |
| **Pagination**   | Page-based (`page`, `limit`)   | Page-based (`page`, `limit`)                   |

## Error Handling

<AccordionGroup>
  <Accordion title="Missing Addresses">
    **Status Code:** 400 Bad Request

    ```json theme={null}
    {
      "error": {
        "status": "INVALID_ARGUMENT",
        "error": "addresses parameter is required"
      }
    }
    ```

    **Solution:** Include at least one valid EVM address in the `addresses` query parameter.
  </Accordion>

  <Accordion title="Too Many Addresses">
    **Status Code:** 400 Bad Request

    ```json theme={null}
    {
      "error": {
        "status": "INVALID_ARGUMENT",
        "error": "maximum 1000 addresses per request"
      }
    }
    ```

    **Solution:** Split your request into batches of 1000 addresses or fewer.
  </Accordion>

  <Accordion title="Request Body Sent">
    **Status Code:** 400 Bad Request

    **Solution:** This is a GET endpoint. Remove any request body and pass parameters via the query string only.
  </Accordion>
</AccordionGroup>
