first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,136 @@
import { capitalCase } from 'change-case';
import type {
IExecuteFunctions,
IHookFunctions,
IDataObject,
ILoadOptionsFunctions,
IHttpRequestMethods,
IRequestOptions,
} from 'n8n-workflow';
/**
* Make an authenticated API request to Lemlist.
*/
export async function lemlistApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
endpoint: string,
body: IDataObject = {},
qs: IDataObject = {},
option: IDataObject = {},
) {
const options: IRequestOptions = {
headers: {},
method,
uri: `https://api.lemlist.com/api${endpoint}`,
qs,
body,
json: true,
};
if (!Object.keys(body).length) {
delete options.body;
}
if (!Object.keys(qs).length) {
delete options.qs;
}
if (Object.keys(option)) {
Object.assign(options, option);
}
return await this.helpers.requestWithAuthentication.call(this, 'lemlistApi', options);
}
/**
* Make an authenticated API request to Lemlist and return all results.
*/
export async function lemlistApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
method: IHttpRequestMethods,
endpoint: string,
qs: IDataObject = {},
) {
const returnData: IDataObject[] = [];
let responseData;
qs.limit = 100;
qs.offset = 0;
//when using v2, the pagination is different
if (qs.version && qs.version === 'v2') {
qs.page = 1;
do {
responseData = await lemlistApiRequest.call(this, method, endpoint, {}, qs);
returnData.push(...(responseData as IDataObject[]));
qs.page++;
} while (responseData.totalPage && qs.page < responseData.totalPage);
return returnData;
} else {
do {
responseData = await lemlistApiRequest.call(this, method, endpoint, {}, qs);
returnData.push(...(responseData as IDataObject[]));
qs.offset += qs.limit;
} while (responseData.length !== 0);
return returnData;
}
}
export function getEvents() {
const events = [
'*',
'contacted',
'hooked',
'attracted',
'warmed',
'interested',
'skipped',
'notInterested',
'emailsSent',
'emailsOpened',
'emailsClicked',
'emailsReplied',
'emailsBounced',
'emailsSendFailed',
'emailsFailed',
'emailsUnsubscribed',
'emailsInterested',
'emailsNotInterested',
'opportunitiesDone',
'aircallCreated',
'aircallEnded',
'aircallDone',
'aircallInterested',
'aircallNotInterested',
'apiDone',
'apiInterested',
'apiNotInterested',
'apiFailed',
'linkedinVisitDone',
'linkedinVisitFailed',
'linkedinInviteDone',
'linkedinInviteFailed',
'linkedinInviteAccepted',
'linkedinReplied',
'linkedinSent',
'linkedinVoiceNoteDone',
'linkedinVoiceNoteFailed',
'linkedinInterested',
'linkedinNotInterested',
'linkedinSendFailed',
'manualInterested',
'manualNotInterested',
'paused',
'resumed',
'customDomainErrors',
'connectionIssue',
'sendLimitReached',
'lemwarmPaused',
];
return events.map((event: string) => ({
name: event === '*' ? '*' : capitalCase(event).replace('Linkedin', 'LinkedIn'),
value: event,
}));
}
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.lemlist",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Communication", "Marketing"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/lemlist/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.lemlist/"
}
]
}
}
@@ -0,0 +1,25 @@
import type { INodeTypeBaseDescription, IVersionedNodeType } from 'n8n-workflow';
import { VersionedNodeType } from 'n8n-workflow';
import { LemlistV1 } from './v1/LemlistV1.node';
import { LemlistV2 } from './v2/LemlistV2.node';
export class Lemlist extends VersionedNodeType {
constructor() {
const baseDescription: INodeTypeBaseDescription = {
displayName: 'Lemlist',
name: 'lemlist',
icon: 'file:lemlist.svg',
group: ['transform'],
defaultVersion: 2,
description: 'Consume the Lemlist API',
};
const nodeVersions: IVersionedNodeType['nodeVersions'] = {
1: new LemlistV1(baseDescription),
2: new LemlistV2(baseDescription),
};
super(nodeVersions, baseDescription);
}
}
@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.lemlistTrigger",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Communication", "Marketing"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/lemlist/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.lemlisttrigger/"
}
]
}
}
@@ -0,0 +1,143 @@
import type {
IHookFunctions,
IWebhookFunctions,
IDataObject,
ILoadOptionsFunctions,
INodeType,
INodeTypeDescription,
IWebhookResponseData,
} from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { getEvents, lemlistApiRequest } from './GenericFunctions';
export class LemlistTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Lemlist Trigger',
name: 'lemlistTrigger',
icon: 'file:lemlist.svg',
group: ['trigger'],
version: 1,
subtitle: '={{$parameter["event"]}}',
description: 'Handle Lemlist events via webhooks',
defaults: {
name: 'Lemlist Trigger',
},
inputs: [],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'lemlistApi',
required: true,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'Event',
name: 'event',
type: 'options',
required: true,
default: '',
options: [...getEvents()],
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
default: '',
description:
'We\'ll call this hook only for this campaignId. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Is First',
name: 'isFirst',
type: 'boolean',
default: false,
description: 'Whether to call this hook only the first time this activity happened',
},
],
},
],
};
methods = {
loadOptions: {
async getCampaigns(this: ILoadOptionsFunctions) {
const campaigns = await lemlistApiRequest.call(this, 'GET', '/campaigns');
return campaigns.map(({ _id, name }: { _id: string; name: string }) => ({
name,
value: _id,
}));
},
},
};
webhookMethods = {
default: {
async checkExists(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
const webhookUrl = this.getNodeWebhookUrl('default');
const webhooks = await lemlistApiRequest.call(this, 'GET', '/hooks');
for (const webhook of webhooks) {
if (webhook.targetUrl === webhookUrl) {
await lemlistApiRequest.call(this, 'DELETE', `/hooks/${webhookData.webhookId}`);
return false;
}
}
return false;
},
async create(this: IHookFunctions): Promise<boolean> {
const webhookUrl = this.getNodeWebhookUrl('default');
const webhookData = this.getWorkflowStaticData('node');
const options = this.getNodeParameter('options') as IDataObject;
const event = this.getNodeParameter('event') as string[];
const body: IDataObject = {
targetUrl: webhookUrl,
type: event,
};
if (event.includes('*')) {
delete body.type;
}
Object.assign(body, options);
const webhook = await lemlistApiRequest.call(this, 'POST', '/hooks', body);
webhookData.webhookId = webhook._id;
return true;
},
async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
try {
await lemlistApiRequest.call(this, 'DELETE', `/hooks/${webhookData.webhookId}`);
} catch (error) {
return false;
}
delete webhookData.webhookId;
return true;
},
},
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const req = this.getRequestObject();
return {
workflowData: [this.helpers.returnJsonArray(req.body as IDataObject)],
};
}
}
@@ -0,0 +1,125 @@
{
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"bot": {
"type": "boolean"
},
"campaignId": {
"type": "string"
},
"campaignName": {
"type": "string"
},
"companyName": {
"type": "string"
},
"contactId": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"createdBy": {
"type": "string"
},
"email": {
"type": "string"
},
"emailTemplateId": {
"type": "string"
},
"emailTemplateName": {
"type": "string"
},
"firstName": {
"type": "string"
},
"isFirst": {
"type": "boolean"
},
"lastName": {
"type": "string"
},
"leadCompanyName": {
"type": "string"
},
"leadEmail": {
"type": "string"
},
"leadFirstName": {
"type": "string"
},
"leadId": {
"type": "string"
},
"leadLastName": {
"type": "string"
},
"leadPhone": {
"type": "string"
},
"linkedinUrl": {
"type": "string"
},
"metaData": {
"type": "object",
"properties": {
"campaignId": {
"type": "string"
},
"createdBy": {
"type": "string"
},
"leadId": {
"type": "string"
},
"taskId": {
"type": "string"
},
"teamId": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"name": {
"type": "string"
},
"phone": {
"type": "string"
},
"relatedSentAt": {
"type": "string"
},
"sendUserName": {
"type": "string"
},
"sequenceId": {
"type": "string"
},
"sequenceStep": {
"type": "integer"
},
"sequenceTested": {
"type": "string"
},
"stopped": {
"type": "boolean"
},
"teamId": {
"type": "string"
},
"totalSequenceStep": {
"type": "integer"
},
"type": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1,21 @@
{
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"createdBy": {
"type": "string"
},
"name": {
"type": "string"
},
"status": {
"type": "string"
}
},
"version": 2
}
@@ -0,0 +1,39 @@
{
"type": "object",
"properties": {
"clickedCount": {
"type": "integer"
},
"deliveredCount": {
"type": "integer"
},
"interestedCount": {
"type": "integer"
},
"leadCompleted": {
"type": "integer"
},
"leadInProgress": {
"type": "integer"
},
"leadReadyToSend": {
"type": "integer"
},
"leadToLaunch": {
"type": "integer"
},
"leadTotal": {
"type": "integer"
},
"openedCount": {
"type": "integer"
},
"repliedCount": {
"type": "integer"
},
"sentCount": {
"type": "integer"
}
},
"version": 1
}
@@ -0,0 +1,9 @@
{
"type": "object",
"properties": {
"id": {
"type": "string"
}
},
"version": 1
}
@@ -0,0 +1,272 @@
{
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"email": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"notFound": {
"type": "boolean"
},
"status": {
"type": "string"
}
}
},
"linkedin": {
"type": "object",
"properties": {
"companyDescription": {
"type": "string"
},
"companyDomain": {
"type": "string"
},
"companyEmployeesOnLinkedin": {
"type": "integer"
},
"companyFoundedOn": {
"type": "integer"
},
"companyHeadQuarter": {
"type": "string"
},
"companyId": {
"type": "integer"
},
"companyIndustry": {
"type": "string"
},
"companyLinkedinUrl": {
"type": "string"
},
"companyLogo": {
"type": "string"
},
"companyName": {
"type": "string"
},
"companySize": {
"type": "string"
},
"companySpecialities": {
"type": "string"
},
"companyTagline": {
"type": "string"
},
"companyType": {
"type": "string"
},
"companyWebsite": {
"type": "string"
},
"firstName": {
"type": "string"
},
"industry": {
"type": "string"
},
"languages": {
"type": "string"
},
"lastName": {
"type": "string"
},
"linkedinClassicId": {
"type": "string"
},
"linkedinMemberId": {
"type": "integer"
},
"linkedinUrl": {
"type": "string"
},
"locationName": {
"type": "string"
},
"occupation": {
"type": "string"
},
"picture": {
"type": "string"
},
"positionGroups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"company": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"domain": {
"type": "string"
},
"employeesOnLinkedin": {
"type": "integer"
},
"foundedOn": {
"type": "integer"
},
"headQuarter": {
"type": "string"
},
"id": {
"type": "integer"
},
"industry": {
"type": "string"
},
"linkedinUrl": {
"type": "string"
},
"linkedinUrlSalesNav": {
"type": "string"
},
"logo": {
"type": "string"
},
"name": {
"type": "string"
},
"size": {
"type": "string"
},
"specialities": {
"type": "string"
},
"tagline": {
"type": "string"
},
"type": {
"type": "string"
},
"website": {
"type": "string"
}
}
},
"date": {
"type": "object",
"properties": {
"end": {
"type": "object",
"properties": {
"month": {
"type": "integer"
},
"year": {
"type": "integer"
}
}
},
"start": {
"type": "object",
"properties": {
"month": {
"type": "integer"
},
"year": {
"type": "integer"
}
}
}
}
},
"profilePositions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"date": {
"type": "object",
"properties": {
"end": {
"type": "object",
"properties": {
"month": {
"type": "integer"
},
"year": {
"type": "integer"
}
}
},
"start": {
"type": "object",
"properties": {
"month": {
"type": "integer"
},
"year": {
"type": "integer"
}
}
}
}
},
"title": {
"type": "string"
}
}
}
}
}
}
},
"project": {
"type": "string"
},
"skills": {
"type": "string"
},
"summary": {
"type": "string"
},
"tagline": {
"type": "string"
}
}
}
}
},
"enrichmentId": {
"type": "string"
},
"enrichmentStatus": {
"type": "string"
},
"input": {
"type": "object",
"properties": {
"companyDomain": {
"type": "string"
},
"companyName": {
"type": "string"
},
"email": {
"type": "string"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"linkedinUrl": {
"type": "string"
}
}
}
},
"version": 5
}
@@ -0,0 +1,36 @@
{
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"campaignId": {
"type": "string"
},
"campaignName": {
"type": "string"
},
"companyName": {
"type": "string"
},
"contactId": {
"type": "string"
},
"email": {
"type": "string"
},
"firstName": {
"type": "string"
},
"isPaused": {
"type": "boolean"
},
"lastName": {
"type": "string"
},
"linkedinUrl": {
"type": "string"
}
},
"version": 5
}
@@ -0,0 +1,33 @@
{
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"campaignId": {
"type": "string"
},
"companyName": {
"type": "string"
},
"contactId": {
"type": "string"
},
"email": {
"type": "string"
},
"firstName": {
"type": "string"
},
"isPaused": {
"type": "boolean"
},
"lastName": {
"type": "string"
},
"linkedinUrl": {
"type": "string"
}
},
"version": 3
}
@@ -0,0 +1,6 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.12275 0H32.8772C36.811 0 40 3.18896 40 7.12274V32.8772C40 36.8109 36.811 39.9999 32.8772 39.9999H7.12275C3.18896 39.9999 0 36.8109 0 32.8772V7.12274C0 3.18896 3.18896 0 7.12275 0ZM28.2356 10.7144H18.9073C18.3273 10.7144 17.8573 11.1844 17.8573 11.7643V13.2358C17.8573 13.8157 18.3273 14.2858 18.9073 14.2858H28.2356C28.8155 14.2858 29.2856 13.8157 29.2856 13.2358V11.7643C29.2856 11.1844 28.8155 10.7144 28.2356 10.7144ZM18.9073 18.2151H26.5693C27.1491 18.2151 27.6191 18.6851 27.6191 19.2649V20.7366C27.6191 21.3165 27.1491 21.7865 26.5693 21.7865H18.9073C18.3273 21.7865 17.8573 21.3165 17.8573 20.7366V19.2649C17.8573 18.6851 18.3273 18.2151 18.9073 18.2151ZM29.2856 28.2357V26.764C29.2856 26.1845 28.8152 25.7141 28.2356 25.7141H17.0156C15.5072 25.7141 14.2858 24.4928 14.2858 22.9843V11.7643C14.2858 11.1847 13.8154 10.7144 13.2359 10.7144H11.7643C11.1847 10.7144 10.7144 11.1847 10.7144 11.7643V25.1732C10.8555 27.3805 12.6194 29.1444 14.8267 29.2855H28.2356C28.8152 29.2855 29.2856 28.8151 29.2856 28.2357Z" fill="#316BFF"/>
<path d="M18.9069 10.7141H28.2353C28.8151 10.7141 29.2853 11.1842 29.2853 11.764V13.2356C29.2853 13.8155 28.8151 14.2856 28.2353 14.2856H18.9069C18.3269 14.2856 17.8569 13.8155 17.8569 13.2356V11.764C17.8569 11.1842 18.3269 10.7141 18.9069 10.7141Z" fill="white"/>
<path d="M18.9069 18.2151H26.5689C27.1488 18.2151 27.6188 18.6851 27.6188 19.2649V20.7366C27.6188 21.3165 27.1488 21.7865 26.5689 21.7865H18.9069C18.3269 21.7865 17.8569 21.3165 17.8569 20.7366V19.2649C17.8569 18.6851 18.3269 18.2151 18.9069 18.2151Z" fill="white"/>
<path d="M29.2856 26.7638V28.2354C29.2856 28.8149 28.8152 29.2853 28.2356 29.2853H14.8267C12.6194 29.1442 10.8555 27.3803 10.7144 25.173V11.764C10.7144 11.1845 11.1847 10.7141 11.7643 10.7141H13.2359C13.8154 10.7141 14.2858 11.1845 14.2858 11.764V22.9841C14.2858 24.4925 15.5072 25.7139 17.0156 25.7139H28.2356C28.8152 25.7139 29.2856 26.1843 29.2856 26.7638Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,116 @@
import type {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IDataObject,
IHttpRequestMethods,
} from 'n8n-workflow';
import { lemlistApiRequest, lemlistApiRequestAllItems, getEvents } from '../GenericFunctions';
describe('GenericFunctions', () => {
describe('lemlistApiRequest', () => {
const mockThis = {
helpers: {
requestWithAuthentication: jest.fn(),
},
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
it('should make an authenticated API request to Lemlist', async () => {
const method: IHttpRequestMethods = 'GET';
const endpoint = '/test-endpoint';
const body: IDataObject = { key: 'value' };
const qs: IDataObject = { query: 'value' };
const option: IDataObject = { headers: {} };
await lemlistApiRequest.call(mockThis, method, endpoint, body, qs, option);
expect(mockThis.helpers.requestWithAuthentication).toHaveBeenCalledWith('lemlistApi', {
headers: {},
method: 'GET',
uri: 'https://api.lemlist.com/api/test-endpoint',
qs: { query: 'value' },
body: { key: 'value' },
json: true,
});
});
});
describe('lemlistApiRequestAllItems', () => {
const mockThis = {
helpers: {
requestWithAuthentication: jest
.fn()
.mockResolvedValue([{ id: 'cam_A1B2C3D4E5F6G7H8I9' }, { id: 'cam_A1B2C3D4E5F6G7H8I8' }]),
},
} as unknown as IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions;
it('should return all results', async () => {
const method: IHttpRequestMethods = 'GET';
const endpoint = '/test-endpoint';
const qs: IDataObject = {};
qs.version = 'v2';
const result = await lemlistApiRequestAllItems.call(mockThis, method, endpoint, qs);
expect(result).toEqual([{ id: 'cam_A1B2C3D4E5F6G7H8I9' }, { id: 'cam_A1B2C3D4E5F6G7H8I8' }]);
});
});
describe('getEvents', () => {
it('should return a list of events with capitalized names', () => {
const expectedEvents = [
{ name: '*', value: '*' },
{ name: 'Contacted', value: 'contacted' },
{ name: 'Hooked', value: 'hooked' },
{ name: 'Attracted', value: 'attracted' },
{ name: 'Warmed', value: 'warmed' },
{ name: 'Interested', value: 'interested' },
{ name: 'Skipped', value: 'skipped' },
{ name: 'Not Interested', value: 'notInterested' },
{ name: 'Emails Sent', value: 'emailsSent' },
{ name: 'Emails Opened', value: 'emailsOpened' },
{ name: 'Emails Clicked', value: 'emailsClicked' },
{ name: 'Emails Replied', value: 'emailsReplied' },
{ name: 'Emails Bounced', value: 'emailsBounced' },
{ name: 'Emails Send Failed', value: 'emailsSendFailed' },
{ name: 'Emails Failed', value: 'emailsFailed' },
{ name: 'Emails Unsubscribed', value: 'emailsUnsubscribed' },
{ name: 'Emails Interested', value: 'emailsInterested' },
{ name: 'Emails Not Interested', value: 'emailsNotInterested' },
{ name: 'Opportunities Done', value: 'opportunitiesDone' },
{ name: 'Aircall Created', value: 'aircallCreated' },
{ name: 'Aircall Ended', value: 'aircallEnded' },
{ name: 'Aircall Done', value: 'aircallDone' },
{ name: 'Aircall Interested', value: 'aircallInterested' },
{ name: 'Aircall Not Interested', value: 'aircallNotInterested' },
{ name: 'Api Done', value: 'apiDone' },
{ name: 'Api Interested', value: 'apiInterested' },
{ name: 'Api Not Interested', value: 'apiNotInterested' },
{ name: 'Api Failed', value: 'apiFailed' },
{ name: 'LinkedIn Visit Done', value: 'linkedinVisitDone' },
{ name: 'LinkedIn Visit Failed', value: 'linkedinVisitFailed' },
{ name: 'LinkedIn Invite Done', value: 'linkedinInviteDone' },
{ name: 'LinkedIn Invite Failed', value: 'linkedinInviteFailed' },
{ name: 'LinkedIn Invite Accepted', value: 'linkedinInviteAccepted' },
{ name: 'LinkedIn Replied', value: 'linkedinReplied' },
{ name: 'LinkedIn Sent', value: 'linkedinSent' },
{ name: 'LinkedIn Voice Note Done', value: 'linkedinVoiceNoteDone' },
{ name: 'LinkedIn Voice Note Failed', value: 'linkedinVoiceNoteFailed' },
{ name: 'LinkedIn Interested', value: 'linkedinInterested' },
{ name: 'LinkedIn Not Interested', value: 'linkedinNotInterested' },
{ name: 'LinkedIn Send Failed', value: 'linkedinSendFailed' },
{ name: 'Manual Interested', value: 'manualInterested' },
{ name: 'Manual Not Interested', value: 'manualNotInterested' },
{ name: 'Paused', value: 'paused' },
{ name: 'Resumed', value: 'resumed' },
{ name: 'Custom Domain Errors', value: 'customDomainErrors' },
{ name: 'Connection Issue', value: 'connectionIssue' },
{ name: 'Send Limit Reached', value: 'sendLimitReached' },
{ name: 'Lemwarm Paused', value: 'lemwarmPaused' },
];
const result = getEvents();
expect(result).toEqual(expectedEvents);
});
});
});
@@ -0,0 +1,321 @@
import isEmpty from 'lodash/isEmpty';
import omit from 'lodash/omit';
import {
type IExecuteFunctions,
type IDataObject,
type ILoadOptionsFunctions,
type INodeExecutionData,
type INodeType,
type INodeTypeDescription,
type INodeTypeBaseDescription,
NodeConnectionTypes,
} from 'n8n-workflow';
import {
activityFields,
activityOperations,
campaignFields,
campaignOperations,
leadFields,
leadOperations,
teamFields,
teamOperations,
unsubscribeFields,
unsubscribeOperations,
} from './descriptions';
import { lemlistApiRequest, lemlistApiRequestAllItems } from '../GenericFunctions';
const versionDescription: INodeTypeDescription = {
displayName: 'Lemlist',
name: 'lemlist',
icon: 'file:lemlist.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the Lemlist API',
defaults: {
name: 'Lemlist',
},
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'lemlistApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Activity',
value: 'activity',
},
{
name: 'Campaign',
value: 'campaign',
},
{
name: 'Lead',
value: 'lead',
},
{
name: 'Team',
value: 'team',
},
{
name: 'Unsubscribe',
value: 'unsubscribe',
},
],
default: 'activity',
},
...activityOperations,
...activityFields,
...campaignOperations,
...campaignFields,
...leadOperations,
...leadFields,
...teamOperations,
...teamFields,
...unsubscribeOperations,
...unsubscribeFields,
],
};
export class LemlistV1 implements INodeType {
description: INodeTypeDescription;
constructor(baseDescription: INodeTypeBaseDescription) {
this.description = {
...baseDescription,
...versionDescription,
};
}
methods = {
loadOptions: {
async getCampaigns(this: ILoadOptionsFunctions) {
const campaigns = await lemlistApiRequest.call(this, 'GET', '/campaigns');
return campaigns.map(({ _id, name }: { _id: string; name: string }) => ({
name,
value: _id,
}));
},
},
};
async execute(this: IExecuteFunctions) {
const items = this.getInputData();
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
let responseData;
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'activity') {
// *********************************************************************
// activity
// *********************************************************************
if (operation === 'getAll') {
// ----------------------------------
// activity: getAll
// ----------------------------------
// https://developer.lemlist.com/#activities
const returnAll = this.getNodeParameter('returnAll', i);
const qs = {} as IDataObject;
const filters = this.getNodeParameter('filters', i);
if (!isEmpty(filters)) {
Object.assign(qs, filters);
}
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/activities', qs);
} else {
qs.limit = this.getNodeParameter('limit', i);
responseData = await lemlistApiRequest.call(this, 'GET', '/activities', {}, qs);
}
}
} else if (resource === 'campaign') {
// *********************************************************************
// campaign
// *********************************************************************
if (operation === 'getAll') {
// ----------------------------------
// campaign: getAll
// ----------------------------------
// https://developer.lemlist.com/#list-all-campaigns
const returnAll = this.getNodeParameter('returnAll', i);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/campaigns', {});
} else {
const qs = {
limit: this.getNodeParameter('limit', i),
};
responseData = await lemlistApiRequest.call(this, 'GET', '/campaigns', {}, qs);
}
}
} else if (resource === 'lead') {
// *********************************************************************
// lead
// *********************************************************************
if (operation === 'create') {
// ----------------------------------
// lead: create
// ----------------------------------
// https://developer.lemlist.com/#add-a-lead-in-a-campaign
const qs = {} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i);
if (additionalFields.deduplicate !== undefined) {
qs.deduplicate = additionalFields.deduplicate;
}
const body = {} as IDataObject;
const remainingAdditionalFields = omit(additionalFields, 'deduplicate');
if (!isEmpty(remainingAdditionalFields)) {
Object.assign(body, remainingAdditionalFields);
}
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(this, 'POST', endpoint, body, qs);
} else if (operation === 'delete') {
// ----------------------------------
// lead: delete
// ----------------------------------
// https://developer.lemlist.com/#delete-a-lead-from-a-campaign
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(
this,
'DELETE',
endpoint,
{},
{ action: 'remove' },
);
} else if (operation === 'get') {
// ----------------------------------
// lead: get
// ----------------------------------
// https://developer.lemlist.com/#get-a-specific-lead-by-email
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'GET', `/leads/${email}`);
} else if (operation === 'unsubscribe') {
// ----------------------------------
// lead: unsubscribe
// ----------------------------------
// https://developer.lemlist.com/#unsubscribe-a-lead-from-a-campaign
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(this, 'DELETE', endpoint);
}
} else if (resource === 'team') {
// *********************************************************************
// team
// *********************************************************************
if (operation === 'get') {
// ----------------------------------
// team: get
// ----------------------------------
// https://developer.lemlist.com/#team
responseData = await lemlistApiRequest.call(this, 'GET', '/team');
}
} else if (resource === 'unsubscribe') {
// *********************************************************************
// unsubscribe
// *********************************************************************
if (operation === 'add') {
// ----------------------------------
// unsubscribe: Add
// ----------------------------------
// https://developer.lemlist.com/#add-an-email-address-in-the-unsubscribes
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'POST', `/unsubscribes/${email}`);
} else if (operation === 'delete') {
// ----------------------------------
// unsubscribe: delete
// ----------------------------------
// https://developer.lemlist.com/#delete-an-email-address-from-the-unsubscribes
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'DELETE', `/unsubscribes/${email}`);
} else if (operation === 'getAll') {
// ----------------------------------
// unsubscribe: getAll
// ----------------------------------
// https://developer.lemlist.com/#list-all-unsubscribes
const returnAll = this.getNodeParameter('returnAll', i);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/unsubscribes', {});
} else {
const qs = {
limit: this.getNodeParameter('limit', i),
};
responseData = await lemlistApiRequest.call(this, 'GET', '/unsubscribes', {}, qs);
}
}
}
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionErrorData);
continue;
}
throw error;
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
return [returnData];
}
}
@@ -0,0 +1,123 @@
import type { INodeProperties } from 'n8n-workflow';
export const activityOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'getAll',
options: [
{
name: 'Get Many',
value: 'getAll',
action: 'Get many activities',
},
],
displayOptions: {
show: {
resource: ['activity'],
},
},
},
];
export const activityFields: INodeProperties[] = [
// ----------------------------------
// activity: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
returnAll: [false],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to retrieve activity for. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Type',
name: 'type',
type: 'options',
default: 'emailsOpened',
description: 'Type of activity to retrieve',
options: [
{
name: 'Emails Bounced',
value: 'emailsBounced',
},
{
name: 'Emails Clicked',
value: 'emailsClicked',
},
{
name: 'Emails Opened',
value: 'emailsOpened',
},
{
name: 'Emails Replied',
value: 'emailsReplied',
},
{
name: 'Emails Send Failed',
value: 'emailsSendFailed',
},
{
name: 'Emails Sent',
value: 'emailsSent',
},
{
name: 'Emails Unsubscribed',
value: 'emailsUnsubscribed',
},
],
},
],
},
];
@@ -0,0 +1,60 @@
import type { INodeProperties } from 'n8n-workflow';
export const campaignOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'getAll',
options: [
{
name: 'Get Many',
value: 'getAll',
action: 'Get many campaigns',
},
],
displayOptions: {
show: {
resource: ['campaign'],
},
},
},
];
export const campaignFields: INodeProperties[] = [
// ----------------------------------
// campaign: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getAll'],
returnAll: [false],
},
},
},
];
@@ -0,0 +1,238 @@
import type { INodeProperties } from 'n8n-workflow';
export const leadOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'create',
options: [
{
name: 'Create',
value: 'create',
action: 'Create a lead',
},
{
name: 'Delete',
value: 'delete',
action: 'Delete a lead',
},
{
name: 'Get',
value: 'get',
action: 'Get a lead',
},
{
name: 'Unsubscribe',
value: 'unsubscribe',
action: 'Unsubscribe a lead',
},
],
displayOptions: {
show: {
resource: ['lead'],
},
},
},
];
export const leadFields: INodeProperties[] = [
// ----------------------------------
// lead: create
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to create the lead under. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to create',
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
options: [
{
displayName: 'Company Name',
name: 'companyName',
type: 'string',
default: '',
description: 'Company name of the lead to create',
},
{
displayName: 'Deduplicate',
name: 'deduplicate',
type: 'boolean',
default: false,
description:
'Whether to do not insert if this email is already present in another campaign',
},
{
displayName: 'First Name',
name: 'firstName',
type: 'string',
default: '',
description: 'First name of the lead to create',
},
{
displayName: 'Last Name',
name: 'lastName',
type: 'string',
default: '',
description: 'Last name of the lead to create',
},
{
displayName: 'Icebreaker',
name: 'icebreaker',
type: 'string',
default: '',
description: 'Icebreaker of the lead to create',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Phone number of the lead to create',
},
{
displayName: 'Picture URL',
name: 'picture',
type: 'string',
default: '',
description: 'Picture URL of the lead to create',
},
{
displayName: 'LinkedIn URL',
name: 'linkedinUrl',
type: 'string',
default: '',
description: 'LinkedIn URL of the lead to create',
},
],
},
// ----------------------------------
// lead: delete
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to remove the lead from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['delete'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to delete',
displayOptions: {
show: {
resource: ['lead'],
operation: ['delete'],
},
},
},
// ----------------------------------
// lead: get
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to retrieve',
displayOptions: {
show: {
resource: ['lead'],
operation: ['get'],
},
},
},
// ----------------------------------
// lead: unsubscribe
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to unsubscribe the lead from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['unsubscribe'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to unsubscribe',
displayOptions: {
show: {
resource: ['lead'],
operation: ['unsubscribe'],
},
},
},
];
@@ -0,0 +1,29 @@
import type { INodeProperties } from 'n8n-workflow';
export const teamOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'get',
options: [
{
name: 'Get',
value: 'get',
action: 'Get a team',
},
],
displayOptions: {
show: {
resource: ['team'],
},
},
},
];
export const teamFields: INodeProperties[] = [
// ----------------------------------
// team: get
// ----------------------------------
];
@@ -0,0 +1,106 @@
import type { INodeProperties } from 'n8n-workflow';
export const unsubscribeOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'add',
options: [
{
name: 'Add',
value: 'add',
action: 'Add an email to an unsubscribe list',
},
{
name: 'Delete',
value: 'delete',
action: 'Delete an email from an unsubscribe list',
},
{
name: 'Get Many',
value: 'getAll',
action: 'Get many unsubscribed emails',
},
],
displayOptions: {
show: {
resource: ['unsubscribe'],
},
},
},
];
export const unsubscribeFields: INodeProperties[] = [
// ----------------------------------
// unsubscribe: add
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email to add to the unsubscribes',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['add'],
},
},
},
// ----------------------------------
// unsubscribe: delete
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email to delete from the unsubscribes',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['delete'],
},
},
},
// ----------------------------------
// unsubscribe: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['getAll'],
returnAll: [false],
},
},
},
];
@@ -0,0 +1,5 @@
export * from './ActivityDescription';
export * from './CampaignDescription';
export * from './LeadDescription';
export * from './TeamDescription';
export * from './UnsubscribeDescription';
@@ -0,0 +1,417 @@
import isEmpty from 'lodash/isEmpty';
import omit from 'lodash/omit';
import {
type IExecuteFunctions,
type IDataObject,
type ILoadOptionsFunctions,
type INodeExecutionData,
type INodeType,
type INodeTypeDescription,
type INodeTypeBaseDescription,
NodeConnectionTypes,
} from 'n8n-workflow';
import {
activityFields,
activityOperations,
campaignFields,
campaignOperations,
enrichmentFields,
enrichmentOperations,
leadFields,
leadOperations,
teamFields,
teamOperations,
unsubscribeFields,
unsubscribeOperations,
} from './descriptions';
import { lemlistApiRequest, lemlistApiRequestAllItems } from '../GenericFunctions';
const versionDescription: INodeTypeDescription = {
displayName: 'Lemlist',
name: 'lemlist',
icon: 'file:lemlist.svg',
group: ['transform'],
version: 2,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the Lemlist API',
defaults: {
name: 'Lemlist',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'lemlistApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Activity',
value: 'activity',
},
{
name: 'Campaign',
value: 'campaign',
},
{
name: 'Enrichment',
value: 'enrich',
},
{
name: 'Lead',
value: 'lead',
},
{
name: 'Team',
value: 'team',
},
{
name: 'Unsubscribe',
value: 'unsubscribe',
},
],
default: 'activity',
},
...activityOperations,
...activityFields,
...campaignOperations,
...campaignFields,
...enrichmentOperations,
...enrichmentFields,
...leadOperations,
...leadFields,
...teamOperations,
...teamFields,
...unsubscribeOperations,
...unsubscribeFields,
],
};
export class LemlistV2 implements INodeType {
description: INodeTypeDescription;
constructor(baseDescription: INodeTypeBaseDescription) {
this.description = {
...baseDescription,
...versionDescription,
};
}
methods = {
loadOptions: {
async getCampaigns(this: ILoadOptionsFunctions) {
const campaigns = await lemlistApiRequest.call(this, 'GET', '/campaigns');
return campaigns.map(({ _id, name }: { _id: string; name: string }) => ({
name,
value: _id,
}));
},
},
};
async execute(this: IExecuteFunctions) {
const items = this.getInputData();
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
let responseData;
const returnData: INodeExecutionData[] = [];
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'activity') {
// *********************************************************************
// activity
// *********************************************************************
if (operation === 'getAll') {
// ----------------------------------
// activity: getAll
// ----------------------------------
// https://developer.lemlist.com/#activities
const returnAll = this.getNodeParameter('returnAll', i);
const qs = {} as IDataObject;
const filters = this.getNodeParameter('filters', i);
if (!isEmpty(filters)) {
Object.assign(qs, filters);
}
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/activities', qs);
} else {
qs.limit = this.getNodeParameter('limit', i);
responseData = await lemlistApiRequest.call(this, 'GET', '/activities', {}, qs);
}
}
} else if (resource === 'campaign') {
// *********************************************************************
// campaign
// *********************************************************************
if (operation === 'getAll') {
// ----------------------------------
// campaign: getAll
// ----------------------------------
// https://developer.lemlist.com/#32ab1bf9-9b2f-40ed-9bbd-0b8370fed3d9
const qs = {} as IDataObject;
const filters = this.getNodeParameter('filters', i);
if (!isEmpty(filters)) {
Object.assign(qs, filters);
}
const returnAll = this.getNodeParameter('returnAll', i);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/campaigns', {});
} else {
qs.limit = this.getNodeParameter('limit', i);
responseData = await lemlistApiRequest.call(this, 'GET', '/campaigns', {}, qs);
}
} else if (operation === 'getStats') {
// ----------------------------------
// campaign: getStats
// ----------------------------------
// https://developer.lemlist.com/#0b5cc72c-c1c8-47d0-a086-32b1b63522e3
const qs = {} as IDataObject;
const campaignId = this.getNodeParameter('campaignId', i);
qs.startDate = this.getNodeParameter('startDate', i);
qs.endDate = this.getNodeParameter('endDate', i);
qs.timezone = this.getNodeParameter('timezone', i);
responseData = await lemlistApiRequest.call(
this,
'GET',
`/campaigns/${campaignId}/stats`,
{},
qs,
);
}
} else if (resource === 'lead') {
// *********************************************************************
// lead
// *********************************************************************
if (operation === 'create') {
// ----------------------------------
// lead: create
// ----------------------------------
// https://developer.lemlist.com/#add-a-lead-in-a-campaign
const qs = {} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i);
if (additionalFields.deduplicate !== undefined) {
qs.deduplicate = additionalFields.deduplicate;
}
const body = {} as IDataObject;
const remainingAdditionalFields = omit(additionalFields, 'deduplicate');
if (!isEmpty(remainingAdditionalFields)) {
Object.assign(body, remainingAdditionalFields);
}
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(this, 'POST', endpoint, body, qs);
} else if (operation === 'delete') {
// ----------------------------------
// lead: delete
// ----------------------------------
// https://developer.lemlist.com/#delete-a-lead-from-a-campaign
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(
this,
'DELETE',
endpoint,
{},
{ action: 'remove' },
);
} else if (operation === 'get') {
// ----------------------------------
// lead: get
// ----------------------------------
// https://developer.lemlist.com/#get-a-specific-lead-by-email
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'GET', `/leads/${email}`);
} else if (operation === 'unsubscribe') {
// ----------------------------------
// lead: unsubscribe
// ----------------------------------
// https://developer.lemlist.com/#unsubscribe-a-lead-from-a-campaign
const campaignId = this.getNodeParameter('campaignId', i);
const email = this.getNodeParameter('email', i);
const endpoint = `/campaigns/${campaignId}/leads/${email}`;
responseData = await lemlistApiRequest.call(this, 'DELETE', endpoint);
}
} else if (resource === 'team') {
// *********************************************************************
// team
// *********************************************************************
if (operation === 'get') {
// ----------------------------------
// team: get
// ----------------------------------
// https://developer.lemlist.com/#team
responseData = await lemlistApiRequest.call(this, 'GET', '/team');
} else if (operation === 'getCredits') {
// ----------------------------------
// team: getCredits
// ----------------------------------
// https://developer.lemlist.com/#c9af1cf3-8d3d-469e-a548-268b579d2cb3
responseData = await lemlistApiRequest.call(this, 'GET', '/team/credits');
}
} else if (resource === 'unsubscribe') {
// *********************************************************************
// unsubscribe
// *********************************************************************
if (operation === 'add') {
// ----------------------------------
// unsubscribe: Add
// ----------------------------------
// https://developer.lemlist.com/#add-an-email-address-in-the-unsubscribes
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'POST', `/unsubscribes/${email}`);
} else if (operation === 'delete') {
// ----------------------------------
// unsubscribe: delete
// ----------------------------------
// https://developer.lemlist.com/#delete-an-email-address-from-the-unsubscribes
const email = this.getNodeParameter('email', i);
responseData = await lemlistApiRequest.call(this, 'DELETE', `/unsubscribes/${email}`);
} else if (operation === 'getAll') {
// ----------------------------------
// unsubscribe: getAll
// ----------------------------------
// https://developer.lemlist.com/#list-all-unsubscribes
const returnAll = this.getNodeParameter('returnAll', i);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/unsubscribes', {});
} else {
const qs = {
limit: this.getNodeParameter('limit', i),
};
responseData = await lemlistApiRequest.call(this, 'GET', '/unsubscribes', {}, qs);
}
}
} else if (resource === 'enrich') {
// *********************************************************************
// enrichment
// *********************************************************************
if (operation === 'get') {
// ----------------------------------
// enrichment: get
// ----------------------------------
// https://developer.lemlist.com/#71b74cc3-8098-4389-b3c2-67a027df9407
const enrichId = this.getNodeParameter('enrichId', i);
responseData = await lemlistApiRequest.call(this, 'GET', `/enrich/${enrichId}`);
} else if (operation === 'enrichLead') {
// https://developer.lemlist.com/#fe2a52fc-fa73-46d0-8b7d-395d9653bfd5
const findEmail = this.getNodeParameter('findEmail', i);
const verifyEmail = this.getNodeParameter('verifyEmail', i);
const linkedinEnrichment = this.getNodeParameter('linkedinEnrichment', i);
const findPhone = this.getNodeParameter('findPhone', i);
const qs = {} as IDataObject;
qs.findEmail = findEmail;
qs.verifyEmail = verifyEmail;
qs.linkedinEnrichment = linkedinEnrichment;
qs.findPhone = findPhone;
const body = {} as IDataObject;
const leadId = this.getNodeParameter('leadId', i);
const endpoint = `/leads/${leadId}/enrich/`;
responseData = await lemlistApiRequest.call(this, 'POST', endpoint, body, qs);
} else if (operation === 'enrichPerson') {
// https://developer.lemlist.com/#4ba3d505-0bfa-4f36-8549-f3cb343786bf
const findEmail = this.getNodeParameter('findEmail', i);
const verifyEmail = this.getNodeParameter('verifyEmail', i);
const linkedinEnrichment = this.getNodeParameter('linkedinEnrichment', i);
const findPhone = this.getNodeParameter('findPhone', i);
const additionalFields = this.getNodeParameter('additionalFields', i);
const qs = {} as IDataObject;
if (!isEmpty(additionalFields)) {
Object.assign(qs, additionalFields);
}
qs.findEmail = findEmail;
qs.verifyEmail = verifyEmail;
qs.linkedinEnrichment = linkedinEnrichment;
qs.findPhone = findPhone;
const body = {} as IDataObject;
const endpoint = '/enrich/';
responseData = await lemlistApiRequest.call(this, 'POST', endpoint, body, qs);
}
}
} catch (error) {
if (this.continueOnFail()) {
const executionErrorData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ error: error.message }),
{ itemData: { item: i } },
);
returnData.push(...executionErrorData);
continue;
}
throw error;
}
const executionData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject),
{ itemData: { item: i } },
);
returnData.push(...executionData);
}
return [returnData];
}
}
@@ -0,0 +1,301 @@
import type { INodeProperties } from 'n8n-workflow';
export const activityOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'getAll',
options: [
{
name: 'Get Many',
value: 'getAll',
action: 'Get many activities',
},
],
displayOptions: {
show: {
resource: ['activity'],
},
},
},
];
export const activityFields: INodeProperties[] = [
// ----------------------------------
// activity: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
returnAll: [false],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: ['activity'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
default: '',
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to retrieve activity for. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
},
{
displayName: 'Is First',
name: 'isFirst',
type: 'boolean',
default: false,
},
{
displayName: 'Lead ID',
name: 'leadId',
type: 'string',
default: '',
},
{
displayName: 'Type',
name: 'type',
type: 'options',
default: 'emailsOpened',
description: 'Type of activity to retrieve',
options: [
{
name: 'Aircall Created',
value: 'aircallCreated',
},
{
name: 'Aircall Done',
value: 'aircallDone',
},
{
name: 'Aircall Ended',
value: 'aircallEnded',
},
{
name: 'Aircall Interested',
value: 'aircallInterested',
},
{
name: 'Aircall Not Interested',
value: 'aircallNotInterested',
},
{
name: 'Api Done',
value: 'apiDone',
},
{
name: 'Api Failed',
value: 'apiFailed',
},
{
name: 'Api Interested',
value: 'apiInterested',
},
{
name: 'Api Not Interested',
value: 'apiNotInterested',
},
{
name: 'Attracted',
value: 'attracted',
},
{
name: 'Connection Issue',
value: 'connectionIssue',
},
{
name: 'Contacted',
value: 'contacted',
},
{
name: 'Custom Domain Errors',
value: 'customDomainErrors',
},
{
name: 'Emails Bounced',
value: 'emailsBounced',
},
{
name: 'Emails Clicked',
value: 'emailsClicked',
},
{
name: 'Emails Failed',
value: 'emailsFailed',
},
{
name: 'Emails Interested',
value: 'emailsInterested',
},
{
name: 'Emails Not Interested',
value: 'emailsNotInterested',
},
{
name: 'Emails Opened',
value: 'emailsOpened',
},
{
name: 'Emails Replied',
value: 'emailsReplied',
},
{
name: 'Emails Send Failed',
value: 'emailsSendFailed',
},
{
name: 'Emails Sent',
value: 'emailsSent',
},
{
name: 'Emails Unsubscribed',
value: 'emailsUnsubscribed',
},
{
name: 'Hooked',
value: 'hooked',
},
{
name: 'Interested',
value: 'interested',
},
{
name: 'Lemwarm Paused',
value: 'lemwarmPaused',
},
{
name: 'LinkedIn Interested',
value: 'linkedinInterested',
},
{
name: 'LinkedIn Invite Accepted',
value: 'linkedinInviteAccepted',
},
{
name: 'LinkedIn Invite Done',
value: 'linkedinInviteDone',
},
{
name: 'LinkedIn Invite Failed',
value: 'linkedinInviteFailed',
},
{
name: 'LinkedIn Not Interested',
value: 'linkedinNotInterested',
},
{
name: 'LinkedIn Replied',
value: 'linkedinReplied',
},
{
name: 'LinkedIn Send Failed',
value: 'linkedinSendFailed',
},
{
name: 'LinkedIn Sent',
value: 'linkedinSent',
},
{
name: 'LinkedIn Visit Done',
value: 'linkedinVisitDone',
},
{
name: 'LinkedIn Visit Failed',
value: 'linkedinVisitFailed',
},
{
name: 'LinkedIn Voice Note Done',
value: 'linkedinVoiceNoteDone',
},
{
name: 'LinkedIn Voice Note Failed',
value: 'linkedinVoiceNoteFailed',
},
{
name: 'Manual Interested',
value: 'manualInterested',
},
{
name: 'Manual Not Interested',
value: 'manualNotInterested',
},
{
name: 'Not Interested',
value: 'notInterested',
},
{
name: 'Opportunities Done',
value: 'opportunitiesDone',
},
{
name: 'Paused',
value: 'paused',
},
{
name: 'Resumed',
value: 'resumed',
},
{
name: 'Send Limit Reached',
value: 'sendLimitReached',
},
{
name: 'Skipped',
value: 'skipped',
},
{
name: 'Warmed',
value: 'warmed',
},
],
},
{
displayName: 'Version',
name: 'version',
type: 'string',
default: 'v2',
},
],
},
];
@@ -0,0 +1,149 @@
import type { INodeProperties } from 'n8n-workflow';
export const campaignOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'getAll',
options: [
{
name: 'Get Many',
value: 'getAll',
action: 'Get many campaigns',
},
{
name: 'Get Stats',
value: 'getStats',
action: 'Get campaign stats',
},
],
displayOptions: {
show: {
resource: ['campaign'],
},
},
},
];
export const campaignFields: INodeProperties[] = [
// ----------------------------------
// campaign: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getAll'],
returnAll: [false],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getAll'],
},
},
options: [
{
displayName: 'Version',
name: 'version',
type: 'string',
default: 'v2',
},
],
},
// ----------------------------------
// campaign: getStats
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to get stats for. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getStats'],
},
},
},
{
displayName: 'Start Date',
name: 'startDate',
type: 'dateTime',
default: '',
required: true,
placeholder: 'e.g. 2024-09-03 00:00:00Z',
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getStats'],
},
},
},
{
displayName: 'End Date',
name: 'endDate',
type: 'dateTime',
default: '',
placeholder: 'e.g. 2024-09-03 00:00:00Z',
required: true,
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getStats'],
},
},
},
{
displayName: 'Timezone',
name: 'timezone',
type: 'string',
default: '',
required: true,
placeholder: 'e.g. Europe/Paris',
displayOptions: {
show: {
resource: ['campaign'],
operation: ['getStats'],
},
},
},
];
@@ -0,0 +1,172 @@
import type { INodeProperties } from 'n8n-workflow';
export const enrichmentOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'get',
options: [
{
name: 'Get',
value: 'get',
action: 'Fetches a previously completed enrichment',
},
{
name: 'Enrich Lead',
value: 'enrichLead',
action: 'Enrich a lead using an email or LinkedIn URL',
},
{
name: 'Enrich Person',
value: 'enrichPerson',
action: 'Enrich a person using an email or LinkedIn URL',
},
],
displayOptions: {
show: {
resource: ['enrich'],
},
},
},
];
export const enrichmentFields: INodeProperties[] = [
// ----------------------------------
// enrichment: get
// ----------------------------------
{
displayName: 'Enrichment ID',
name: 'enrichId',
type: 'string',
default: '',
required: true,
description: 'ID of the enrichment to retrieve',
displayOptions: {
show: {
resource: ['enrich'],
operation: ['get'],
},
},
},
// ----------------------------------
// enrichment: enrichLead
// ----------------------------------
{
displayName: 'Lead ID',
name: 'leadId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichLead'],
},
},
},
{
displayName: 'Find Email',
name: 'findEmail',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichLead', 'enrichPerson'],
},
},
},
{
displayName: 'Verify Email',
name: 'verifyEmail',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichLead', 'enrichPerson'],
},
},
},
{
displayName: 'LinkedIn Enrichment',
name: 'linkedinEnrichment',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichLead', 'enrichPerson'],
},
},
},
{
displayName: 'Find Phone',
name: 'findPhone',
type: 'boolean',
default: false,
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichLead', 'enrichPerson'],
},
},
},
// ----------------------------------
// enrichment: enrichPerson
// ----------------------------------
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['enrich'],
operation: ['enrichPerson'],
},
},
options: [
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
},
{
displayName: 'First Name',
name: 'firstName',
type: 'string',
default: '',
},
{
displayName: 'Last Name',
name: 'lastName',
type: 'string',
default: '',
},
{
displayName: 'LinkedIn Url',
name: 'linkedinUrl',
type: 'string',
default: '',
},
{
displayName: 'Company Name',
name: 'companyName',
type: 'string',
default: '',
},
{
displayName: 'Company Domain',
name: 'companyDomain',
type: 'string',
default: '',
},
],
},
];
@@ -0,0 +1,281 @@
import type { INodeProperties } from 'n8n-workflow';
export const leadOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'create',
options: [
{
name: 'Create',
value: 'create',
action: 'Create a lead',
},
{
name: 'Delete',
value: 'delete',
action: 'Delete a lead',
},
{
name: 'Get',
value: 'get',
action: 'Get a lead',
},
{
name: 'Unsubscribe',
value: 'unsubscribe',
action: 'Unsubscribe a lead',
},
],
displayOptions: {
show: {
resource: ['lead'],
},
},
},
];
export const leadFields: INodeProperties[] = [
// ----------------------------------
// lead: create
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to create the lead under. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to create',
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: ['lead'],
operation: ['create'],
},
},
options: [
{
displayName: 'Company Name',
name: 'companyName',
type: 'string',
default: '',
description: 'Company name of the lead to create',
},
{
displayName: 'Company Domain',
name: 'companyDomain',
type: 'string',
default: '',
description: 'Company domain of the lead to create',
},
{
displayName: 'Deduplicate',
name: 'deduplicate',
type: 'boolean',
default: false,
description:
'Whether to do not insert if this email is already present in another campaign',
},
{
displayName: 'Find Email',
name: 'findEmail',
type: 'boolean',
default: false,
description: 'Whether to find verified email',
},
{
displayName: 'Find Phone',
name: 'findPhone',
type: 'boolean',
default: false,
description: 'Whether to find phone number',
},
{
displayName: 'First Name',
name: 'firstName',
type: 'string',
default: '',
description: 'First name of the lead to create',
},
{
displayName: 'Icebreaker',
name: 'icebreaker',
type: 'string',
default: '',
description: 'Icebreaker of the lead to create',
},
{
displayName: 'Job Title',
name: 'jobTitle',
type: 'string',
default: '',
description: 'Job title of the lead to create',
},
{
displayName: 'Last Name',
name: 'lastName',
type: 'string',
default: '',
description: 'Last name of the lead to create',
},
{
displayName: 'LinkedIn Enrichment',
name: 'linkedinEnrichment',
type: 'boolean',
default: false,
description: 'Whether to run the LinkedIn enrichment',
},
{
displayName: 'LinkedIn URL',
name: 'linkedinUrl',
type: 'string',
default: '',
description: 'LinkedIn URL of the lead to create',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Phone number of the lead to create',
},
{
displayName: 'Picture URL',
name: 'picture',
type: 'string',
default: '',
description: 'Picture URL of the lead to create',
},
{
displayName: 'Verify Email',
name: 'verifyEmail',
type: 'boolean',
default: false,
description: 'Whether to verify existing email (debounce)',
},
],
},
// ----------------------------------
// lead: delete
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to remove the lead from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['delete'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to delete',
displayOptions: {
show: {
resource: ['lead'],
operation: ['delete'],
},
},
},
// ----------------------------------
// lead: get
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to retrieve',
displayOptions: {
show: {
resource: ['lead'],
operation: ['get'],
},
},
},
// ----------------------------------
// lead: unsubscribe
// ----------------------------------
{
displayName: 'Campaign Name or ID',
name: 'campaignId',
type: 'options',
required: true,
default: [],
typeOptions: {
loadOptionsMethod: 'getCampaigns',
},
description:
'ID of the campaign to unsubscribe the lead from. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
displayOptions: {
show: {
resource: ['lead'],
operation: ['unsubscribe'],
},
},
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email of the lead to unsubscribe',
displayOptions: {
show: {
resource: ['lead'],
operation: ['unsubscribe'],
},
},
},
];
@@ -0,0 +1,34 @@
import type { INodeProperties } from 'n8n-workflow';
export const teamOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'get',
options: [
{
name: 'Get',
value: 'get',
action: 'Get a team',
},
{
name: 'Get Credits',
value: 'getCredits',
action: 'Get team credits',
},
],
displayOptions: {
show: {
resource: ['team'],
},
},
},
];
export const teamFields: INodeProperties[] = [
// ----------------------------------
// team: get
// ----------------------------------
];
@@ -0,0 +1,106 @@
import type { INodeProperties } from 'n8n-workflow';
export const unsubscribeOperations: INodeProperties[] = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
default: 'add',
options: [
{
name: 'Add',
value: 'add',
action: 'Add an email to an unsubscribe list',
},
{
name: 'Delete',
value: 'delete',
action: 'Delete an email from an unsubscribe list',
},
{
name: 'Get Many',
value: 'getAll',
action: 'Get many unsubscribed emails',
},
],
displayOptions: {
show: {
resource: ['unsubscribe'],
},
},
},
];
export const unsubscribeFields: INodeProperties[] = [
// ----------------------------------
// unsubscribe: add
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email to add to the unsubscribes',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['add'],
},
},
},
// ----------------------------------
// unsubscribe: delete
// ----------------------------------
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'Email to delete from the unsubscribes',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['delete'],
},
},
},
// ----------------------------------
// unsubscribe: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['getAll'],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 5,
description: 'Max number of results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: ['unsubscribe'],
operation: ['getAll'],
returnAll: [false],
},
},
},
];
@@ -0,0 +1,6 @@
export * from './ActivityDescription';
export * from './CampaignDescription';
export * from './EnrichmentDescription';
export * from './LeadDescription';
export * from './TeamDescription';
export * from './UnsubscribeDescription';