Search contacts
POST
/api/v3/contacts/search
const url = 'https://api.tryletterhead.com/api/v3/contacts/search';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.tryletterhead.com/api/v3/contacts/search \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \Searches your company-level contacts by keyword, tag, or subscription filters.
Request body
query— free-text search against the contact’s identifying fields.tags— restrict to contacts carrying any of these tags.channel— a channel slug, orchannelId(numeric, legacy) — restrict to contacts subscribed on that channel. When both are supplied,channeltakes precedence.status— restrict to subscriptions with this status. RequireschannelId(orchannel) to be meaningful.searchAfter— the cursor from a previous response’ssearchAfter, to fetch the next page.pageSize— results per page (1-100, default 25).
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ” Media type application/json
object
api
Required. Set to true to authenticate with an API key.
boolean
tags
Array<string>
query
string
channel
A channel slug. Takes precedence over channelId when both are supplied.
string
channelId
A channel’s numeric id (legacy alternative to channel).
integer
status
integer
searchAfter
Pagination cursor from a previous response’s searchAfter.
string
pageSize
integer
Example
{ "api": true, "tags": [ "engaged" ],}Responses
Section titled “ Responses ”200 OK
Media type application/json
object
items
object
contacts
Array<object>
object
email
string
firstName
string
lastName
string
tags
Array<string>
customFields
object
__lh.engagementRefreshedAt
string
__lh.mailboxProvider
string
__lh.roleAddress
boolean
lastClickDate
string
lastOpenDate
string
endpoints
Array<object>
object
channelConsents
Array<object>
object
consents
Array<object>
object
createdAt
string
updatedAt
string
subscriptions
Array<object>
object
channel
object
slug
string
name
string
status
integer
createdAt
string
updatedAt
string
searchAfter
Pass back as the request’s searchAfter to fetch the next page. Absent on the last page.
string
totalRelation
Whether total is an exact count or a lower bound (large result sets).
string
message
string
total
integer
Example
{ "items": { "contacts": [ { "firstName": "Avery", "lastName": "Chen", "tags": [ "engaged-readers", "the-north" ], "customFields": { "__lh.engagementRefreshedAt": "2026-06-18T04:20:28+00:00", "__lh.mailboxProvider": "gmail", "__lh.roleAddress": false, "lastClickDate": "2026-06-17 06:18:18", "lastOpenDate": "2026-06-18 05:11:33" }, "endpoints": [], "channelConsents": [], "consents": [], "createdAt": "2026-05-23T11:43:15+00:00", "updatedAt": "2026-06-18T09:12:04+00:00", "subscriptions": [ { "channel": { "slug": "the-daily", "name": "The Daily" }, "status": 1, "createdAt": "2026-04-30T15:22:41+00:00", "updatedAt": "2026-06-12T20:43:14+00:00" } ] }, { "firstName": "Jordan", "lastName": "Reyes", "tags": [ "engaged-readers" ], "customFields": { "__lh.engagementRefreshedAt": "2026-06-18T04:20:28+00:00", "__lh.mailboxProvider": "other", "__lh.roleAddress": false, "lastOpenDate": "2026-06-15 11:42:02" }, "endpoints": [], "channelConsents": [], "consents": [], "createdAt": "2026-05-23T11:43:15+00:00", "updatedAt": "2026-06-18T09:12:04+00:00", "subscriptions": [] } ], "searchAfter": "WzE3NTAyMzQ1NjcwMDBd", "totalRelation": "eq" }, "message": "Contacts retrieved.", "total": 2}Still can’t find what you need? Contact support.