curl --request GET \
--url https://api.lemlist.com/api/v2/tasks \
--header 'Authorization: Basic <encoded-value>'import requests
url = "https://api.lemlist.com/api/v2/tasks"
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/v2/tasks', 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/v2/tasks")
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/v2/tasks",
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;
}{
"results": [
{
"_id": "opp_A1B2C3D4E5F6G7H8I",
"objectType": "contact",
"recordId": "ctc_A1B2C3D4E5F6G7H8I",
"contactId": "ctc_A1B2C3D4E5F6G7H8I",
"companyId": "cmp_A1B2C3D4E5F6G7H8I",
"leadId": "lea_A1B2C3D4E5F6G7H8I",
"campaignId": "cam_A1B2C3D4E5F6G7H8I",
"assignedTo": "usr_A1B2C3D4E5F6G7H8I",
"title": "Call John Doe",
"message": "Ask about the new pricing",
"text": null,
"type": "phone",
"channel": "aircall",
"status": "due",
"priority": 2,
"dueDate": "2026-01-12T09:00:00.000Z",
"completedAt": null,
"manual": true,
"ownerName": "Jane Smith",
"campaign": {
"id": "cam_A1B2C3D4E5F6G7H8I",
"name": "Q1 outbound",
"sequenceId": "seq_A1B2C3D4E5F6G7H8I"
},
"leadFirstName": "John",
"leadLastName": "Doe",
"leadCompanyName": "Acme Inc"
}
],
"total": 1,
"limit": 50,
"page": 1
}{
"success": false,
"error": {
"code": "UNKNOWN_FIELD",
"message": "Unknown filter field: contactFoo"
}
}{
"success": false,
"error": {
"code": "ROUTE_UNAUTHORIZED",
"message": "Unauthorized"
}
}{
"error": "Method not allowed"
}{
"success": false,
"error": {
"code": "SEARCH_FAILED",
"message": "Failed to search tasks"
}
}Search Tasks
Searches your team’s tasks with the filters of the Tasks page, and returns every status.
curl --request GET \
--url https://api.lemlist.com/api/v2/tasks \
--header 'Authorization: Basic <encoded-value>'import requests
url = "https://api.lemlist.com/api/v2/tasks"
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/v2/tasks', 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/v2/tasks")
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/v2/tasks",
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;
}{
"results": [
{
"_id": "opp_A1B2C3D4E5F6G7H8I",
"objectType": "contact",
"recordId": "ctc_A1B2C3D4E5F6G7H8I",
"contactId": "ctc_A1B2C3D4E5F6G7H8I",
"companyId": "cmp_A1B2C3D4E5F6G7H8I",
"leadId": "lea_A1B2C3D4E5F6G7H8I",
"campaignId": "cam_A1B2C3D4E5F6G7H8I",
"assignedTo": "usr_A1B2C3D4E5F6G7H8I",
"title": "Call John Doe",
"message": "Ask about the new pricing",
"text": null,
"type": "phone",
"channel": "aircall",
"status": "due",
"priority": 2,
"dueDate": "2026-01-12T09:00:00.000Z",
"completedAt": null,
"manual": true,
"ownerName": "Jane Smith",
"campaign": {
"id": "cam_A1B2C3D4E5F6G7H8I",
"name": "Q1 outbound",
"sequenceId": "seq_A1B2C3D4E5F6G7H8I"
},
"leadFirstName": "John",
"leadLastName": "Doe",
"leadCompanyName": "Acme Inc"
}
],
"total": 1,
"limit": 50,
"page": 1
}{
"success": false,
"error": {
"code": "UNKNOWN_FIELD",
"message": "Unknown filter field: contactFoo"
}
}{
"success": false,
"error": {
"code": "ROUTE_UNAUTHORIZED",
"message": "Unauthorized"
}
}{
"error": "Method not allowed"
}{
"success": false,
"error": {
"code": "SEARCH_FAILED",
"message": "Failed to search tasks"
}
}- Flat query parameters for the common cases —
status=due&assignedTo=usr_... advancedFilters, a JSON tree, for everything else, including your custom fields. List the available fields to discover them.
due, upcoming
and paused tasks; v2 returns every status unless status narrows it.Filtering
Any list parameter takes a single value, a comma-separated list, or the repeatedkey[]= notation — the three are equivalent. Values are OR-ed inside a parameter,
AND-ed across parameters. taskId, contactId, companyId, leadId,
campaignId, assignedTo and type each take a …Not counterpart for exclusion.
| Parameter | Narrows to |
|---|---|
taskId | These task ids (100 max) |
objectType | Contact tasks, or company tasks |
contactId | The contact’s tasks, its leads’ tasks included |
companyId | The company’s tasks, and the tasks of its contacts |
leadId, campaignId, assignedTo | The given ids |
type, channel | The step type, or the coarser channel |
status, priority | Task status and priority |
title, contactLinkedinUrl | Substring match |
dueDateFrom / dueDateTo | Due-date range, inclusive, ISO-8601 |
completedAtFrom / completedAtTo | Completion-date range (done or ignored) |
hasCampaign, hasDueDate | Presence of a campaign, of a due date |
search | Free text over the title and the contact / company fields |
advancedFilters | Anything else — see below |
Statuses
due, upcoming, paused, done, ignored. pending is an alias for
due,upcoming,paused.
upcoming is maintained by a background job, not computed when you read: a task
crossing its due date flips to due on the next sweep, not at the exact instant.
Filter on dueDate when you need a read-time-exact answer.Advanced filters
advancedFilters takes a filter tree encoded as JSON. A node is either a
group (connector and / or, plus children) or a condition
(property, operator, value). The tree is bounded: depth 5, 50 conditions.
{
"type": "group",
"id": "root",
"connector": "and",
"children": [
{
"type": "condition",
"id": "c1",
"property": "contactLeadStatus",
"operator": "is_any_of",
"value": ["Email sent"]
},
{
"type": "group",
"id": "g1",
"connector": "or",
"children": [
{
"type": "condition",
"id": "c2",
"property": "companyIndustry",
"operator": "contains",
"value": "software"
},
{
"type": "condition",
"id": "c3",
"property": "cf_contact_tier",
"operator": "is",
"value": "A"
}
]
}
]
}
property must be a field returned by
List Task Filters, and every
operator must be one that field’s type allows. An unknown field or a wrong
operator is a 400 — never a silently ignored condition.
Sorting and pagination
sortBy accepts dueDate (default), status, priority, assignedTo,
campaignId, score, handledOn and contactJobTitle; sortOrder is asc or
desc (default desc).
Pagination is offset-based and 1-based: page (default 1) and limit
(default 50, max 100). page * limit must not exceed 10 000 — past that the
request returns 400 PAGE_OUT_OF_RANGE rather than silently serving another page.
Coming from v1
| v1 filter | v2 | Note |
|---|---|---|
fullName | advancedFilters on contactName | |
email | advancedFilters on contactEmail | |
phone | advancedFilters on contactPhone | |
campaignId | campaignId / campaignIdNot | |
assignedTo | assignedTo / assignedToNot | User ids, same values |
type | type / typeNot | Same raw vocabulary |
dueDate | dueDateFrom / dueDateTo | ISO-8601 instead of YYYY-MM-DD |
linkedin | contactLinkedinUrl | Matches the contact’s URL, where v1 matched the lead’s |
campaignState | — | No equivalent, see below |
pageis 1-based here, where v1 is 0-indexed.- The response is
{ results, total, limit, page }, and every task key is always present —nullrather than omitted. - Dates are ISO-8601 instants.
Limits
- No
createdAt/updatedAt. A task’s real creation timestamp only exists on part of the data, and no update timestamp is indexed — so neither can be filtered nor sorted on.dueDateandcompletedAtare the reliable ones. - No
campaignState. v1 could filter tasks by the state of their campaign; the task document does not carry it. Fetch the campaigns and filter on your side. - No cursor pagination. Offset only, capped at 10 000 rows: narrow with a date range to walk a larger set.
sourceis not available. The nearest signals aremanualin the response and thehasCampaignparameter.
Examples
curl --request GET \
--url 'https://api.lemlist.com/api/v2/tasks?status=due&assignedTo=usr_A1B2C3D4E5F6G7H8I&limit=50' \
--header 'Authorization: Basic <encoded-value>'
curl --request GET \
--url 'https://api.lemlist.com/api/v2/tasks?companyId=cmp_A1B2C3D4E5F6G7H8I&sortBy=dueDate&sortOrder=asc' \
--header 'Authorization: Basic <encoded-value>'
curl --request GET \
--url 'https://api.lemlist.com/api/v2/tasks?status=done&completedAtFrom=2026-01-01T00:00:00.000Z&completedAtTo=2026-01-31T23:59:59.999Z' \
--header 'Authorization: Basic <encoded-value>'
curl --request GET \
--url 'https://api.lemlist.com/api/v2/tasks?include=contact' \
--data-urlencode 'advancedFilters={"type":"condition","id":"c1","property":"contactLeadStatus","operator":"is_any_of","value":["Email sent"]}' \
--get \
--header 'Authorization: Basic <encoded-value>'
Authorizations
Basic authentication header of the form Basic <encoded-value>, where <encoded-value> is the base64-encoded string username:password.
Query Parameters
Task ids. At most 100. Several values (comma-separated or repeated) are OR-ed.
Contact ids. A single id also matches the tasks of that contact's leads, exactly like the contact panel does. Several values (comma-separated or repeated) are OR-ed.
Excludes the given contactId values.
Company ids. Matches company-level tasks AND tasks on that company's contacts. Several values (comma-separated or repeated) are OR-ed.
Excludes the given companyId values.
Lead ids. Several values (comma-separated or repeated) are OR-ed.
Excludes the given leadId values.
Campaign ids. Several values (comma-separated or repeated) are OR-ed.
Excludes the given campaignId values.
Ids of the users the task is assigned to. Several values (comma-separated or repeated) are OR-ed.
Excludes the given assignedTo values.
Restricts to the tasks hanging off a contact (a contactId or a leadId is present) or off a company (a companyId with no contact and no lead). Derived from the ids, never stored.
contact, company Raw step types, comma-separated. This is the same vocabulary as v1 type.
Excludes the given type values.
Channel the task belongs to — the coarser nomenclature shown in the app as "Task type".
aircall, email, linkedin, whatsapp, sms, manual Task statuses, comma-separated. pending is an alias for due,upcoming,paused. Unlike v1, completed tasks are returned unless you filter them out.
due, upcoming, paused, done, ignored, pending Task priorities (integers), comma-separated.
Matches tasks whose title contains this text.
Matches tasks whose contact's LinkedIn URL contains this text. v1's linkedin filter matched the lead's URL instead.
Lower bound of the due date, inclusive. ISO-8601.
Upper bound of the due date, inclusive. ISO-8601.
Lower bound of the completion date (done or ignored), inclusive. ISO-8601.
Upper bound of the completion date (done or ignored), inclusive. ISO-8601.
Restricts to the tasks attached to a campaign (true) or to the standalone ones (false).
Restricts to the tasks carrying a due date (true) or to those without one (false).
Free-text search over the task title and the contact / company text fields.
A filter tree encoded as JSON, addressing any field returned by GET /v2/tasks/filters. Max depth 5, max 50 conditions.
Embeds the denormalized objects already carried by the task. Comma-separated.
contact, company, contact,company Field to sort on.
dueDate, status, priority, assignedTo, campaignId, score, handledOn, contactJobTitle Sort direction.
asc, desc Page number, 1-based. page * limit must not exceed 10000.
x >= 1Page size.
1 <= x <= 100Was this page helpful?