List People

Page through a workspace's people. Filtering and sorting (including across related objects) is done through the records query.

get/v1/people

Returns a paginated list of people in the caller's workspace with their relationships. Read-only; no side effects. Includes both platform users (with memberships) and CRM contacts. ## Filtering & sorting Filter via `POST /v1/records/query` (root `people`) or the `filters` model; operators are gated by each field's data type. See [Filtering & sorting](../filtering-and-sorting). **Filterable fields** | Field | Type | Allowed operators | |---|---|---| | `composite_accounts_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_avatar_fullname` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_cards_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_checks_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_emails_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_locations_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_media_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_memberships_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_payment_means_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_phones_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_routed_to` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_sourced_from` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_web_links_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `composite_workspace_connectors_list` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `created_at` | date | `eq` `lt` `gt` `is_null` `is_not_null` | | `deleted_at` | date | `eq` `lt` `gt` `is_null` `is_not_null` | | `external_person_id` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `first_name` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `full_name` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `job_title` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `last_name` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `person_id` | text | `contains` `eq` `neq` `starts_with` `ends_with` `is_null` `is_not_null` | | `pk` | number | `eq` `neq` `gt` `gte` `lt` `lte` `is_null` `is_not_null` | | `updated_at` | date | `eq` `lt` `gt` `is_null` `is_not_null` | **Sortable fields:** `composite_accounts_list`, `composite_avatar_fullname`, `composite_cards_list`, `composite_checks_list`, `composite_emails_list`, `composite_locations_list`, `composite_media_list`, `composite_memberships_list`, `composite_payment_means_list`, `composite_phones_list`, `composite_routed_to`, `composite_sourced_from`, `composite_web_links_list`, `composite_workspace_connectors_list`, `created_at`, `deleted_at`, `external_person_id`, `first_name`, `full_name`, `job_title`, `last_name`, `person_id`, `pk`, `updated_at` (via `orderBy` / `sort`, `asc`|`desc`).

Requires a bearer token: Authorization: Bearer <token>.

Query parameters

NameTypeRequiredDescription
pagestringNo1-based page number for offset pagination.e.g. 1
limitstringNoPage size, 1 to 100.e.g. 25

Request

cURL
curl -X GET https://api.wellapp.ai/v1/people \
  -H "Authorization: Bearer $WELL_API_TOKEN"

Responses

200A page of people with pagination metadata.

{
  "data": [
    {
      "type": "people",
      "id": "c4d5e6f7-8a9b-40c1-92d3-e4f5a6b7c8d9",
      "attributes": {
        "full_name": "Remy Okafor",
        "first_name": "Remy",
        "last_name": "Okafor",
        "job_title": "Founder and CEO",
        "created_at": "2026-01-12T09:31:00.000Z",
        "updated_at": "2026-05-18T11:22:09.000Z"
      },
      "relationships": {
        "companies": {
          "data": [
            {
              "type": "companies",
              "id": "b2c3d4e5-6f70-4812-93a4-b5c6d7e8f9a0"
            }
          ]
        }
      }
    }
  ],
  "meta": {
    "pagination": {
      "page": 1,
      "limit": 25,
      "total": 4
    }
  }
}

401Unauthorized

{
  "code": "UNAUTHORIZED",
  "status": 401,
  "title": "Unauthorized",
  "message": "See title.",
  "meta": {
    "trace_id": "a1b2c3",
    "log_id": "a1b2c3"
  }
}

403Forbidden

{
  "code": "FORBIDDEN",
  "status": 403,
  "title": "Forbidden",
  "message": "See title.",
  "meta": {
    "trace_id": "a1b2c3",
    "log_id": "a1b2c3"
  }
}

GET /v1/people returns the workspace's people (contacts), page-paginated with page and limit (max 100). It does not accept inline filtering or sorting — those query params are ignored.

To filter or sort people — including across related objects — use the records query: POST /v1/records/query with root: "people". It exposes the full filters / raw whereClause and orderBy model. For the operator set and pagination notes see Filtering & sorting.

This resource's related objects (the ones you can include) and how to filter or sort on each:

RelationshipCardinalityFilter on a fieldSort by a field
workspaceto-one (workspace){ "workspace": { "name": { "_eq": … } } }"field": "workspace.name"
source_workspace_connectorto-one (workspaceconnector){ "source_workspace_connector": { "field_name": { "_eq": … } } }"field": "source_workspace_connector.field_name"
mediato-one (media){ "media": { "file_name": { "_eq": … } } }"field": "media.file_name"
emailsto-many (personemail){ "emails": { "_some": { "address": { "_eq": … } } } }aggregate proxy only ⚠️
phonesto-many (personphone){ "phones": { "_some": { "number": { "_eq": … } } } }aggregate proxy only ⚠️
locationsto-many (personlocation){ "locations": { "_some": { "city": { "_eq": … } } } }aggregate proxy only ⚠️
web_linksto-many (personweblink){ "web_links": { "_some": { "field_name": { "_eq": … } } } }aggregate proxy only ⚠️
companiesto-many (companyperson){ "companies": { "_some": { "field_name": { "_eq": … } } } }aggregate proxy only ⚠️
membershipsto-many (membership){ "memberships": { "_some": { "role": { "_eq": … } } } }aggregate proxy only ⚠️
collectto-many (collect){ "collect": { "_some": { "field_name": { "_eq": … } } } }aggregate proxy only ⚠️
workspace_connectorsto-many (workspaceconnector){ "workspace_connectors": { "_some": { "field_name": { "_eq": … } } } }aggregate proxy only ⚠️
people_workspace_connectorsto-many (peopleworkspaceconnector){ "people_workspace_connectors": { "_some": { "field_name": { "_eq": … } } } }aggregate proxy only ⚠️

Replace field_name with any field of the related object. See its object-reference page for the full field list.

Filter by a to-one relation (and sort by it):

{
  "root": "people",
  "whereClause": { "workspace": { "name": { "_ilike": "%acme%" } } },
  "orderBy": { "field": "workspace.name", "direction": "asc" }
}

Filter by a to-many relation (quantified — bare nesting is invalid):

{
  "root": "people",
  "whereClause": { "emails": { "_some": { "address": { "_ilike": "%@acme.com" } } } }
}