> For the complete documentation index, see [llms.txt](https://api.circle.so/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://api.circle.so/apis/headless/member-api/community-member-search.md).

# Community Member Search

This documentation describes using the member filters endpoint to search for community members.

### API Endpoint

```bash
POST /api/headless/v1/search/community_members
```

### Request Parameters

| Parameter            | Type    | Required | Description                                            |
| -------------------- | ------- | -------- | ------------------------------------------------------ |
| `filters`            | Array   | No       | Array of filter objects                                |
| `per_page`           | Integer | No       | Number of results per page                             |
| `search_after`       | Array   | No       | Cursor for pagination beyond 10K records               |
| `order`              | String  | No       | Sort order: "oldest", "alphabetical", "latest", "role" |
| `exclude_empty_name` | Boolean | No       | When true, excludes profiles with no name              |

### Building Filters

Each filter in the `filters` array follows this structure:

```json
{
  "key": "string",              // Required
  "filter_type": "string",      // Required for string keys (name, email, headline, bio, location, name_and_email) and range keys (joined_community_days_ago, last_logged_in_days_ago)
  "profile_field_type": "string", // Optional, for custom fields
  "profile_field_id": "string", // Optional, for custom fields
  "value": "string",           // Optional
  "gte": "integer",            // Optional, for range queries
  "lte": "integer"             // Optional, for range queries
}
```

#### Available Filter Types

* `"is"` - Exact match
* `"is_not"` - Exclude exact match
* `"contains"` - Partial match
* `"does_not_contain"` - Exclude partial match
* `"gt"` - Greater than
* `"lt"` - Less than
* `"eq"` - Equals to

{% hint style="info" %}
The `email` and `activity_score` filters only apply when the authenticated member is an admin. For other members, these filters are ignored.
{% endhint %}

### Filter Examples

#### Basic Profile Fields

```json
{
  "filters": [
    {
      "key": "name",
      "filter_type": "is",
      "value": "John Doe"
    },
    {
      "key": "email",
      "filter_type": "is",
      "value": "john@example.com"
    },
    {
      "key": "headline",
      "filter_type": "contains",
      "value": "developer"
    }
  ]
}
```

#### Custom Profile Fields

```json
{
  "filters": [
    {
      "key": "profile_field",
      "filter_type": "is",
      "profile_field_type": "text",
      "profile_field_id": "123",
      "value": "Software Engineer"
    },
    {
      "key": "profile_field",
      "profile_field_type": "checkbox",
      "profile_field_id": "456",
      "value": "true"
    }
  ]
}
```

#### Activity Score Range (admins only)

```json
{
  "filters": [
    {
      "key": "activity_score",
      "gte": 5,
      "lte": 7
    }
  ]
}
```

### Cursor-based Pagination

For datasets larger than 10K records, use cursor-based pagination with `search_after`.

#### Initial Request

```json
{
  "filters": [
    {
      "key": "role",
      "value": "Member"
    }
  ],
  "per_page": 20
}
```

#### Response

```json
{
  "page": 1,
  "per_page": 20,
  "has_next_page": true,
  "count": 15000,
  "page_count": 20,
  "records": [...],
  "next_search_after": ["1463538857"]
}
```

`next_search_after` is only included when there is a next cursor.

#### Next Page Request

```json
{
  "filters": [
    {
      "key": "role",
      "value": "Member"
    }
  ],
  "per_page": 20,
  "search_after": ["1463538857"]
}
```

### Combining Filters with Pagination

```json
{
  "filters": [
    {
      "key": "name",
      "filter_type": "contains",
      "value": "John"
    },
    {
      "key": "profile_field",
      "filter_type": "is",
      "profile_field_type": "text",
      "profile_field_id": "123",
      "value": "Engineer"
    }
  ],
  "per_page": 20,
  "search_after": ["1463538857"]
}
```

### Best Practices

1. **Filter Combinations**
   * Combine multiple filters to create precise queries
   * Use text filters (`contains`) for broader matches
   * Use exact matches (`is`) for specific fields like email
2. **Pagination**
   * Use `search_after` for datasets larger than 10K records
   * Keep track of the `next_search_after` value for subsequent requests
   * Start a new query without `search_after` if filters change
3. **Performance**
   * Keep filter combinations reasonable
   * Specify exact fields when possible for better performance

### Common Issues

1. **Invalid Search After**
   * If `search_after` becomes invalid, start a new query without it
   * Always use the most recent `next_search_after` value
2. **No More Results**
   * When `next_search_after` is not in the response, you've reached the end
   * Start a new query if you need to change filters
3. **Filter Combinations**
   * Some filter types may not be available for all fields
   * Check the field type before applying specific filters
