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

# List Recipients

> Page through a mailing list's recipients, with status filter and search

Returns a mailing list's recipients oldest first, 100 per page by default. Each recipient carries the fields your sync wrote (`name`, `external_id`, `attributes`) plus its lifecycle `status`.

Recipient statuses:

| Status | Meaning | Reactivated by upsert? |
| - | - | - |
| `active` | Receives release emails | — |
| `removed` | You removed them (API or dashboard) | Yes |
| `unsubscribed` | They clicked unsubscribe in an email | Never |

## Authentication

This endpoint requires an API token passed as a Bearer token in the `Authorization` header.

```bash theme={null}
Authorization: Bearer YOUR_API_TOKEN
```

## Path Parameters

<ParamField path="list_id" type="string" required>
  The mailing list's unique identifier (UUID).
</ParamField>

## Query Parameters

<ParamField query="status" type="string">
  Only recipients in this status: `active`, `removed` or `unsubscribed`.
</ParamField>

<ParamField query="q" type="string">
  Case-insensitive search across email, name and external\_id.
</ParamField>

<ParamField query="limit" type="integer" default="100">
  Page size, 1–500.
</ParamField>

<ParamField query="cursor" type="string">
  The `next_cursor` from the previous page. Omit for the first page.
</ParamField>

## Request

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.shipstar.ai/api/v1/email/lists/a1b2c3d4-e5f6-7890-abcd-ef1234567890/recipients?status=active&limit=200" \
    -H "Authorization: Bearer YOUR_API_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const listId = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
  const all = [];
  let cursor = null;
  do {
    const url = new URL(`https://api.shipstar.ai/api/v1/email/lists/${listId}/recipients`);
    url.searchParams.set('limit', '500');
    if (cursor) url.searchParams.set('cursor', cursor);
    const page = await (await fetch(url, {
      headers: { Authorization: 'Bearer YOUR_API_TOKEN' }
    })).json();
    all.push(...page.items);
    cursor = page.next_cursor;
  } while (cursor);
  ```

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

  list_id = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
  url = f'https://api.shipstar.ai/api/v1/email/lists/{list_id}/recipients'
  headers = {'Authorization': 'Bearer YOUR_API_TOKEN'}

  recipients, cursor = [], None
  while True:
      params = {'limit': 500, **({'cursor': cursor} if cursor else {})}
      page = requests.get(url, headers=headers, params=params).json()
      recipients += page['items']
      cursor = page['next_cursor']
      if not cursor:
          break
  ```
</CodeGroup>

## Response

<ResponseField name="items" type="object[]" required>
  Recipients in this page.

  <Expandable title="Recipient">
    <ResponseField name="id" type="string" required>Recipient id (UUID)</ResponseField>
    <ResponseField name="email" type="string" required>Lowercased email address</ResponseField>
    <ResponseField name="name" type="string">Display name, if set</ResponseField>
    <ResponseField name="external_id" type="string">Your identifier for this person, if set</ResponseField>
    <ResponseField name="attributes" type="object" required>Free-form key/value map (strings, numbers, booleans)</ResponseField>
    <ResponseField name="status" type="string" required>`active`, `removed` or `unsubscribed`</ResponseField>
    <ResponseField name="status_changed_at" type="string">When the status last changed; null while never changed</ResponseField>
    <ResponseField name="is_active" type="boolean" required>Shorthand for `status == "active"`</ResponseField>
    <ResponseField name="created_at" type="string" required>ISO 8601 timestamp</ResponseField>
    <ResponseField name="updated_at" type="string" required>ISO 8601 timestamp</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="next_cursor" type="string">
  Opaque cursor for the next page; `null` on the last page.
</ResponseField>

```json 200 theme={null}
{
  "items": [
    {
      "id": "5e0b1c1e-6d2b-4a1f-9a3d-1c2b3a4d5e6f",
      "email": "sam@example.com",
      "name": "Sam Lee",
      "external_id": "usr_42",
      "attributes": {"plan": "pro"},
      "status": "active",
      "status_changed_at": null,
      "is_active": true,
      "created_at": "2026-09-01T08:00:00Z",
      "updated_at": "2026-09-20T08:00:00Z"
    }
  ],
  "next_cursor": "MjAyNi0wOS0wMVQwODowMDowMCswMDowMHw1ZTBiMWMxZS0..."
}
```

## Errors

| Status | Description |
| - | - |
| 400 | Unknown `status` value or malformed `cursor` |
| 401 | Invalid or expired API token |
| 404 | Mailing list not found in the token's project |

## Rate Limits

This endpoint is limited to 100 requests per minute per IP.
