Contacts
Filter contacts
List contacts with filters sent in the request body. Accepts a Prisma-shaped `where` clause, an optional geographic `near` radius, and pagination. Returns the same shape as `GET /v2/contacts/` with an
POST /v2/contacts/filter
Building a
where filter? See the Filtering contacts guide for every key, its value shapes, and end-to-end examples.Request body
Content-Type: application/json
take
integer
skip
integer
cursor
string (uuid)
where
object
where.in
string (uuid)
where.not_in
string (uuid)
where.ignore_merge
boolean
Filter by the
ignore_merge flag (excluded from merge suggestions).where.is_starred
boolean
Match starred (true) or non-starred (false) contacts.
where.is_archived
boolean
Match archived (true) or active (false) contacts. Defaults to false when omitted.
where.has_priority_tier
integer
where.has_linkedin
string
where.has_instagram
string
where.has_twitter
string
where.has_source
string
where.has_name
string
where.has_groups
object
where.has_groups.not
string
where.has_user_created_groups
boolean
Non-system group membership: true for at least one user-created group; false for no user-created groups, including contacts with zero memberships or only Dex system-group memberships.
where.has_grouping_signal
boolean enum
Internal organize prefilter: title, company, location, or LinkedIn summary is non-null and non-empty. Whitespace-only values are removed by the organize serializer.Possible values:
truewhere.has_groups_all
array<array>
Array of group-id rows: AND across rows, OR within each row (contact must be in at least one group from every row).
where.has_frequency
string
where.has_location
string
where.has_location_exact
string
Location: exact string match (not fuzzy).
where.has_job_title
string
where.has_never_keep_in_touch
boolean
Filter by the
never_keep_in_touch flag.where.has_created_at
object
Creation-date range:
{ gte?, lte? } ISO 8601 datetimes (at least one bound required).where.has_created_at.gte
string (date-time)
where.has_created_at.lte
string (date-time)
where.has_updated_at
object
Last-updated-date range:
{ gte?, lte? } ISO 8601 datetimes (at least one bound required).where.has_updated_at.gte
string (date-time)
where.has_updated_at.lte
string (date-time)
where.has_birthday
string (date-time)
where.has_tag
string (uuid)
Match contacts carrying this single tag id.
where.has_tags
array<string (uuid)>
where.has_tags_all
array<array>
Array of tag-id rows: AND across rows, OR within each row (contact must carry at least one tag from every row).
where.has_company
string
where.has_education
string
where.has_description
string
where.has_linkedin_companies
string
where.has_linkedin_education
string
where.has_email
boolean
Match contacts that have (true) or lack (false) at least one email.
where.has_phone_number
boolean
Match contacts that have (true) or lack (false) at least one phone number.
where.not_has_name
string
where.not_has_company
string
where.not_has_job_title
string
where.not_has_education
string
where.not_has_description
string
where.not_has_linkedin_companies
string
where.not_has_linkedin_education
string
where.has_linkedin_last_message_at
boolean
where.has_last_seen_at
boolean
where.has_distance
object
Geo radius filter: contacts within
meters of { lat, lon } (PostGIS ST_DWithin on geocoded coordinates). label is an optional display name for the point.where.has_distance.lat
number
where.has_distance.lon
number
where.has_distance.meters
number
where.has_distance.label
string
where.has_interaction
boolean
where.has_next_reminder
boolean
where.custom_fields
array<object>
User-defined custom-field filters. Each clause is
{ field_id, operator, value? }; multiple clauses AND together. Operators: contains, eq, in, not_in, present, absent, gte, lte.where.custom_fields[].field_id
string (uuid)
where.custom_fields[].operator
string enum
Possible values:
"contains", "eq", "in", "not_in", "present", "absent", "gte", "lte"where.custom_fields[].value
string
where._or
array<object>
Compound-OR escape hatch: an array of filter branches combined with OR, each ANDed with the top-level keys. One level deep — branches cannot themselves contain
_or.where._or[].in
string (uuid)
where._or[].not_in
string (uuid)
where._or[].ignore_merge
boolean
Filter by the
ignore_merge flag (excluded from merge suggestions).where._or[].is_starred
boolean
Match starred (true) or non-starred (false) contacts.
where._or[].is_archived
boolean
Match archived (true) or active (false) contacts. Defaults to false when omitted.
where._or[].has_priority_tier
integer
where._or[].has_linkedin
string
where._or[].has_instagram
string
where._or[].has_twitter
string
where._or[].has_source
string
where._or[].has_name
string
where._or[].has_groups
object
where._or[].has_groups.not
string
where._or[].has_user_created_groups
boolean
Non-system group membership: true for at least one user-created group; false for no user-created groups, including contacts with zero memberships or only Dex system-group memberships.
where._or[].has_grouping_signal
boolean enum
Internal organize prefilter: title, company, location, or LinkedIn summary is non-null and non-empty. Whitespace-only values are removed by the organize serializer.Possible values:
truewhere._or[].has_groups_all
array<array>
Array of group-id rows: AND across rows, OR within each row (contact must be in at least one group from every row).
where._or[].has_frequency
string
where._or[].has_location
string
where._or[].has_location_exact
string
Location: exact string match (not fuzzy).
where._or[].has_job_title
string
where._or[].has_never_keep_in_touch
boolean
Filter by the
never_keep_in_touch flag.where._or[].has_created_at
object
Creation-date range:
{ gte?, lte? } ISO 8601 datetimes (at least one bound required).where._or[].has_created_at.gte
string (date-time)
where._or[].has_created_at.lte
string (date-time)
where._or[].has_updated_at
object
Last-updated-date range:
{ gte?, lte? } ISO 8601 datetimes (at least one bound required).where._or[].has_updated_at.gte
string (date-time)
where._or[].has_updated_at.lte
string (date-time)
where._or[].has_birthday
string (date-time)
where._or[].has_tag
string (uuid)
Match contacts carrying this single tag id.
where._or[].has_tags
array<string (uuid)>
where._or[].has_tags_all
array<array>
Array of tag-id rows: AND across rows, OR within each row (contact must carry at least one tag from every row).
where._or[].has_company
string
where._or[].has_education
string
where._or[].has_description
string
where._or[].has_linkedin_companies
string
where._or[].has_linkedin_education
string
where._or[].has_email
boolean
Match contacts that have (true) or lack (false) at least one email.
where._or[].has_phone_number
boolean
Match contacts that have (true) or lack (false) at least one phone number.
where._or[].not_has_name
string
where._or[].not_has_company
string
where._or[].not_has_job_title
string
where._or[].not_has_education
string
where._or[].not_has_description
string
where._or[].not_has_linkedin_companies
string
where._or[].not_has_linkedin_education
string
where._or[].has_linkedin_last_message_at
boolean
where._or[].has_last_seen_at
boolean
where._or[].has_distance
object
Geo radius filter: contacts within
meters of { lat, lon } (PostGIS ST_DWithin on geocoded coordinates). label is an optional display name for the point.where._or[].has_distance.lat
number
where._or[].has_distance.lon
number
where._or[].has_distance.meters
number
where._or[].has_distance.label
string
where._or[].has_interaction
boolean
where._or[].has_next_reminder
boolean
where._or[].custom_fields
array<object>
User-defined custom-field filters. Each clause is
{ field_id, operator, value? }; multiple clauses AND together. Operators: contains, eq, in, not_in, present, absent, gte, lte.where._or[].custom_fields[].field_id
string (uuid)
where._or[].custom_fields[].operator
string enum
Possible values:
"contains", "eq", "in", "not_in", "present", "absent", "gte", "lte"where._or[].custom_fields[].value
string
orderBy
any
include
object
include.linkedin_data
boolean
include.web_search_summary
boolean
include.groups_count
boolean
include.coordinates
boolean
include.last_note
boolean
select
object
select.linkedin_data
boolean
select.web_search_summary
boolean
select.groups_count
boolean
select.coordinates
boolean
select.last_note
boolean
near
string
radiusKm
number
Example
{
"take": 0,
"skip": 0
}
Responses
200 — Successful response
Content-Type: application/json
data
object required
data.contacts
array<object> required
data.contacts[].id
string (uuid) required
data.contacts[].user_id
string
data.contacts[].first_name
string | null
data.contacts[].last_name
string | null
data.contacts[].full_name
string | null
data.contacts[].description
string | null
data.contacts[].job_title
string | null
data.contacts[].company
string | null
data.contacts[].education
string | null
data.contacts[].legacy_location
string | null
data.contacts[].image_url
string | null
data.contacts[].business_card_url
string | null
data.contacts[].website
string | null
data.contacts[].image_source
string | null
data.contacts[].birthday
string (date-time)
data.contacts[].birthday_year
integer | null
data.contacts[].linkedin
string | null
data.contacts[].twitter
string | null
data.contacts[].facebook
string | null
data.contacts[].instagram
string | null
data.contacts[].telegram
string | null
data.contacts[].tiktok
string | null
data.contacts[].youtube
string | null
data.contacts[].starred
boolean
data.contacts[].is_archived
boolean
data.contacts[].ignore_merge
boolean
data.contacts[].never_keep_in_touch
boolean
data.contacts[].source
string
data.contacts[].priority_tier
integer | null
data.contacts[].frequency
string | null
data.contacts[].frequency_text
string | null
data.contacts[].last_seen_at
string (date-time)
data.contacts[].last_reminder_at
string (date-time)
data.contacts[].next_reminder_at
string (date-time)
data.contacts[].first_met_at
string (date-time)
data.contacts[].first_interaction_at
string (date-time)
data.contacts[].linkedin_companies
string | null
data.contacts[].linkedin_education
string | null
data.contacts[].linkedin_enhance_date
string (date-time)
data.contacts[].linkedin_last_message_at
string (date-time)
data.contacts[].linkedin_last_message_snippet
string | null
data.contacts[].linkedin_message_link
string | null
data.contacts[].linkedin_urn
string | null
data.contacts[].linkedin_headline
string | null
data.contacts[].whatsapp_message_link
string | null
data.contacts[].whatsapp_message_snippet
string | null
data.contacts[].whatsapp_last_message_at
string (date-time)
data.contacts[].imessage_message_link
string | null
data.contacts[].imessage_message_snippet
string | null
data.contacts[].imessage_last_message_at
string (date-time)
data.contacts[].instagram_message_link
string | null
data.contacts[].instagram_message_snippet
string | null
data.contacts[].instagram_last_message_at
string (date-time)
data.contacts[].gmail_last_interaction_at
string (date-time)
data.contacts[].gmail_last_interaction_provider
string enum
Possible values:
"GOOGLE", "OFFICE365"data.contacts[].gmail_last_interaction_provider_id
string | null
data.contacts[].gmail_last_interaction_subject
string | null
data.contacts[].gcal_last_interaction_at
string (date-time)
data.contacts[].gcal_last_interaction_provider
string enum
Possible values:
"GOOGLE", "OFFICE365"data.contacts[].gcal_last_interaction_provider_id
string | null
data.contacts[].gcal_last_interaction_title
string | null
data.contacts[].phone_call_interaction_snippet
string | null
data.contacts[].phone_call_last_interaction_at
string (date-time)
data.contacts[].web_search_summary
any | null
data.contacts[].created_at
string (date-time)
data.contacts[].updated_at
string (date-time)
data.contacts[].geocode_attempts
integer
data.contacts[].geocode_failed_at
string (date-time)
data.contacts[]._count
object
data.contacts[]._count.groups_contacts
integer
data.contacts[].frequency_interval
any
data.contacts[].linkedin_data
object | null
data.contacts[].latitude
number | null
data.contacts[].longitude
number | null
data.contacts[].last_note
object | null
data.contacts[].last_note.id
string (uuid)
data.contacts[].last_note.preview
string
data.contacts[].last_note.event_time
string (date-time)
data.contacts[].last_note.emoji
string | null
data.contacts[].last_note.meeting_type
string | null
data.contacts[].contact_emails
array<object>
data.contacts[].contact_phone_numbers
array<object>
data.contacts[].contact_birthdays
object | null
data.contacts[].contact_locations
array<object>
data.contacts[].contacts_custom_fields
array<object>
data.contacts[].legacy_contact_addresses
array<object>
data.contacts[].groups_contacts
array<object>
data.contacts[].tags_contacts
array<object>
data.contacts[].timeline_items_contacts
array<object>
data.contacts[].reminders_contacts
array<object>
data.contacts[].contact_relations_contact_relations_sourceTocontacts
array<object>
data.contacts[].contact_relations_contact_relations_destinationTocontacts
array<object>
data.contacts[].feed_items
array<object>
data.contacts[].keep_in_touch_reminders
object | null
data.pagination
object
data.pagination.nextCursor
string | null
data.pagination.count
integer
data.filterHash
string required
Example
{
"data": {
"contacts": [
{
"id": "00000000-0000-0000-0000-000000000000"
}
],
"filterHash": "string"
}
}
400 — Request body failed validation.
Content-Type: application/json
(body)
any
401 — Missing or invalid API key.
Content-Type: application/json
(body)
any
403 — Valid key, insufficient permission.
Content-Type: application/json
(body)
any
404 — Resource does not exist.
Content-Type: application/json
(body)
any
409 — Request conflicts with the current state of the resource.
Content-Type: application/json
(body)
any
429 — Rate limit exceeded.
Content-Type: application/json
(body)
any
500 — Unexpected server error.
Content-Type: application/json
(body)
any
Code samples
curl https://api.prod.getdex.com/v2/contacts/filter \
--request POST \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"take": 0,
"skip": 0
}'
fetch('https://api.prod.getdex.com/v2/contacts/filter', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
take: 0,
skip: 0
})
})
requests.post(
"https://api.prod.getdex.com/v2/contacts/filter",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
json={
"take": 0,
"skip": 0
}
)
Count contacts
Return the count of contacts matching the optional `where` filter. Returns `{ data: { count } }`.
Search contacts by name
Name-only typeahead. Matches the contact's full name accent-insensitively (`f_unaccent`) and returns full contact rows in the list envelope `{ data: { contacts: [...] } }`. `query` is required — send

