curl --request GET \
--url https://api.lemlist.com/api/contacts \
--header 'Authorization: Basic <encoded-value>'import requests
url = "https://api.lemlist.com/api/contacts"
headers = {"Authorization": "Basic <encoded-value>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Basic <encoded-value>'}};
fetch('https://api.lemlist.com/api/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));require 'uri'
require 'net/http'
url = URI("https://api.lemlist.com/api/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic <encoded-value>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.lemlist.com/api/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}Get Many Contacts
Retrieves contacts from your CRM. Use idsOrEmails to fetch specific contacts by ID or email in a single request (max 100), crmIds to find them from their record id in your connected CRM, or omit them to search/list contacts by name, email, contact list, or campaign membership.
curl --request GET \
--url https://api.lemlist.com/api/contacts \
--header 'Authorization: Basic <encoded-value>'import requests
url = "https://api.lemlist.com/api/contacts"
headers = {"Authorization": "Basic <encoded-value>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Basic <encoded-value>'}};
fetch('https://api.lemlist.com/api/contacts', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));require 'uri'
require 'net/http'
url = URI("https://api.lemlist.com/api/contacts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Basic <encoded-value>'
response = http.request(request)
puts response.read_body<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.lemlist.com/api/contacts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}Query modes
This endpoint supports the following query modes:| Mode | Parameters | Response format |
|---|---|---|
| By IDs/emails | idsOrEmails | Array of Contact |
| By CRM record ids | crmIds | Array of Contact, the ones found |
| Search/filter | search, email, listId, and/or notInAnyCampaign | Paginated object with data, total, limit, offset, where data holds ContactListItem objects |
idsOrEmails takes precedence over crmIds. A lookup ignores the search filters and the pagination.
Response shapes
- A lookup (
idsOrEmails,crmIds) returns fullContactobjects: fields underfields, campaigns with their lead id, andcrmSyncwhen the contact has a record in the connected CRM. - The list returns
ContactListItemobjects.
idsOrEmails answers 404 and crmIds answers 200 with an empty array.
Finding a contact from your CRM
UsecrmIds (up to 100, comma-separated) with the record ids of your connected CRM, for example GET /contacts?crmIds=123456789 with a HubSpot contact id; for Salesforce, pass the 18-character Contact or Lead id. Each contact found carries the matched id under crmSync.crmRecordId; ids that match nothing are skipped.
Filtering by contact list
Use thelistId parameter to retrieve contacts belonging to a specific list. Get valid list IDs from GET /contacts/lists.
You can combine listId with search or email to further narrow results within a list.
Filtering contacts not in any campaign
UsenotInAnyCampaign=true to find contacts that are not part of any campaign (orphan contacts). This can be used alone or combined with other filters like search, email, or listId.
Filtering by CRM sync state
UsecrmSyncStatus to list the contacts in a given sync state on your connected CRM: for example GET /contacts?crmSyncStatus=error for every contact the CRM sync refused, or crmSyncStatus=contact_blocked_by_company_without_name for one root cause. A CRM must be connected, otherwise the request answers 400 NO_CRM_CONNECTED. It can be combined with the other filters.Authorizations
Query Parameters
Comma-separated record ids of contacts in the CRM connected to the team (HubSpot, Salesforce, or Pipedrive); for Salesforce, the 18-character Contact or Lead id. Returns an array of the contacts found, each with the matched id under crmSync.crmRecordId; ids that match nothing are skipped, and the array is empty when no CRM is connected. Duplicates are removed; an empty value is ignored. Maximum 100 values (TOO_MANY_CRM_IDS); a value over 25 characters answers INVALID_CRM_ID. Ignored when idsOrEmails is provided.
Filter contacts by attached company ID (cpn_xxx format). Use this when you already know the lemlist company id (for example after fetching GET /companies?crmSyncStatus=unique_index_error_company). Mutually exclusive with companyDomain, companyLinkedinUrl, and companySalesnavUrl.
^cpn_[a-zA-Z0-9]+$Filter contacts to those carrying a field rejection with this reason — a value lemlist refused to write, prefixed by its origin (enrichment_* while enriching, crm_sync_* during CRM sync). Returns an empty list (total: 0) when no contact matches. Each returned contact exposes the full detail under fieldRejections[] (which field, why, and conflictingRecordId for duplicates). Only applies to the paginated list — ignored when idsOrEmails is provided (that path returns the exact contacts requested, unfiltered).
enrichment_duplicate_linkedin_url, enrichment_duplicate_linkedin_url_sales_nav, enrichment_duplicate_email, crm_sync_duplicate_linkedin_url, crm_sync_duplicate_linkedin_url_sales_nav, crm_sync_invalid_linkedin_url, crm_sync_invalid_url, crm_sync_invalid_email, crm_sync_invalid_phone, crm_sync_linkedin_url_not_contact, crm_sync_duplicate_contact_blocked, crm_sync_duplicate_company_blocked, crm_sync_company_data_rejected, crm_sync_unsub_state_protected, crm_sync_unsub_channel_empty, crm_sync_value_oscillating, crm_sync_owner_sync_loop, crm_sync_unmapped_user, crm_sync_value_incompatible, crm_sync_unknown_error Filter contacts by their CRM sync state against the team's active CRM provider. Requires a CRM (Hubspot, Salesforce, or Pipedrive) to be connected — otherwise the request returns 400 NO_CRM_CONNECTED. Values:
synced— the contact has a CRM record and no sync errors.not_synced— the contact has no CRM record yet.searching— a CRM search (Search & connect, Create in CRM) is queued or running for the contact.not_found— the last CRM search found no record for the contact.error— at least one sync error is currently raised, whatever its reason.- A specific error reason (lowercase form), to filter by root cause:
invalid_email— the CRM refused the contact's email.property_doesnt_exist— a mapped property does not exist in the CRM.required_field_missing— a field the CRM requires is missing.unique_index_error_contact— the CRM record is already synced with another lemlist contact.contact_already_exists_with_name,contact_already_exists_with_linkedin_url,contact_already_exists_with_email— a CRM contact already exists with the same first and last name, LinkedIn URL or email.contact_blocked_by_company— contact not created: its company already exists in the CRM.contact_blocked_by_company_search— contact not created: the company search is incomplete, retried later.contact_blocked_by_company_without_name— contact not created: its company needs a name to be found in the CRM.contact_blocked_by_company_without_key— contact not created: its company needs a domain or LinkedIn URL to be found in the CRM.contact_blocked_by_company_already_synced— contact not created: its company is already synced with another lemlist company.
Only applies to the paginated list — ignored when idsOrEmails or crmIds is provided.
synced, not_synced, error, searching, not_found, invalid_email, property_doesnt_exist, required_field_missing, unique_index_error_contact, contact_already_exists_with_name, contact_already_exists_with_linkedin_url, contact_already_exists_with_email, contact_blocked_by_company, contact_blocked_by_company_search, contact_blocked_by_company_without_name, contact_blocked_by_company_without_key, contact_blocked_by_company_already_synced Response
Success. When using idsOrEmails or crmIds, returns an array of contacts (empty when no crmIds value matches). Otherwise, returns a paginated object with data (ContactListItem items), total, limit, and offset.
- Lookup by idsOrEmails or crmIds · object[]
- List · object
A contact record in your CRM, as the lookups (GET /contacts?idsOrEmails=, GET /contacts?crmIds=, GET /contacts/{idOrEmail}) return it. Not to be confused with a lead which is a contact specifically added to a campaign.
Was this page helpful?