- Brand
- lemlist
- Category
- Sales & CRM
- Primary Subcategory
- Sales Engagement & Outreach Automation
Integration details
Description
lemlist is a sales engagement platform for running multichannel outreach across email, LinkedIn, calls, WhatsApp, and SMS from a single sequence. Campaigns and sequences: create campaigns, draft and preview personalized multichannel sequences step by step, set up A/B variants and AI-generated variables, validate a campaign before launch, and start, pause, or resume it. Leads and prospecting: search your existing campaign leads, add or import leads, update their data and custom variables, and search the lemlist leads database to build new lists. Enrichment tools can look up a lead's professional email and phone number, individually or in bulk, using enrichment credits from your plan. Signals and watch lists: build watch lists that track buying signals on companies you care about, browse the signal library, and turn a watch list into a campaign. CRM and contacts: create and update contacts and companies, organize them into lists, import them from CSV, and push campaign leads into your contact database. Conversations and activity: read your unified inbox, follow up on conversations, reply to a lead, review call activity and outcomes, and work through your task list. Deliverability and sending infrastructure: check the deliverability and DNS health of your sending domains, review and configure DNS records, run a deliverability audit and inbox placement tests, and connect, test, and manage the mailboxes you send from. Reporting: track how campaigns perform with detailed stats and reports across channels. Account: review your team, users, sending settings, unsubscribe list, and webhooks. All actions run on your own lemlist workspace with your own data, using the permissions granted to the connected account.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Sales Engagement & Outreach Automation
- Secondary Subcategories
- None listed
- Brand
- lemlist
- Access
- Account required
- First tracked
- 2026-09-19
- Tool count
- 174
- Market
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
Agent DiscoverabilityChatGPT Discoverability ScoreUpdated dailyThe first to track the ChatGPT, Claude, Muse, Grok & Google ecosystems, with the largest database on the core platforms. Tracked daily since .
0/100
Invisible#13of 33
in Sales Engagement & Outreach Automation- Picked
- 0.0/100
- Found
- 0.0/100
- Positioned
- –/100
Category leaderboard
Sales Engagement & Outreach Automation
- 1O
Outreach33
- 2A
ACA0
- 3A
Amplemarket0
- 4B
BoothIQ0
- 13L
lemlist0
Get alerts for lemlist
Get updates when lemlist’s Discoverability Score or category rank changes.
Competing in ChatGPT Sales Engagement & Outreach Automation
View Category174 tools agents can invoke
Add one or more team members to the sender pool of a campaign, or add channels to senders already in the pool. It never removes a sender or a channel: a sender already in the pool keeps its channels and gains the listed ones. Idempotent. Keywords: add a sender, assign a teammate to a campaign, add Ben to the campaign, send from this mailbox too. Use when the user asks about: - Adding a teammate to a campaign ("add Ben to the Q4 campaign"): one entry with the userId and no channels enables the channel types that the steps require, healthy channels first, exactly as the editor toggle does - Adding a teammate with chosen channels ("add Ben with the mailbox sales@acme.com only"): pass channels with the ids from get_senders - Enabling one channel type on many senders at once (channels on several entries) Before any write: call get_senders with the campaignId. It lists every team member who can send, in the pool or not (inPool), with the user ids, the channel ids, the aliases, the health of each channel and requiredChannelTypes, the channel types that the steps require. Never guess a user id, a mailbox id, a WhatsApp account id or an alias. Load load_skill("senders") first: it tells which tool fits the request, when to change the sender strategy, and how to read the diagnostics. Contract rules reproduced by the backend: - A campaign with a dynamic sender strategy (contactOwner, leadImporter, customField:<field>) has a read-only pool that the leads fill: every pool write is refused. Switch the strategy with set_campaign_sender_strategy first, only when the user wants it. - A channel type is accepted only when a non-forced step of the campaign uses it: no WhatsApp channel without a WhatsApp step. Add the step first with add_sequence_step: it enables the type on each pool sender who owns an account of it, and lists the enabled types in senderPoolChange. - Every entry must be a team member who owns the listed channels; an alias must be one of the aliases of the mailbox. - LinkedIn has no channel to pick: a sender in the pool is enabled on LinkedIn. Never list linkedin with an id. - A pool with more than one sender needs the emailPro plan; the mailboxes above the plan allowance are dropped. - A write runs on a running campaign: the leads not contacted yet get a new sender from the pool, the contacted leads keep theirs. - Every write answers "data": the pool after the change, with the diagnostics of each sender and channel. Read them and report the errors to the user. To define the whole pool at once, use replace_campaign_senders. To add one channel to one sender, enable_campaign_sender_channels does the same with a single entry. No user confirmation required.
add_campaign_senders
Add existing CRM companies to a company list. Use when the user asks about: - Organizing companies or accounts into lists (e.g. "Target accounts", "Churn risk") - Grouping the companies returned by search_companies Contract rules reproduced by the backend: - company ids come from search_companies; the list id comes from get_company_lists — never invent one - the list must exist, hold companies (not contacts), and not be dynamic - companies already in the list are silently skipped, never duplicated - at most 1000 companies per call
add_companies_to_list
Add existing CRM contacts to a contact list. Use when the user asks about: - Organizing contacts into lists (e.g. "Nurturing", "Hot leads") - Grouping the contacts returned by search_contacts Contract rules reproduced by the backend: - contact ids come from search_contacts; the list id comes from get_contact_lists — never invent one - the list must exist, hold contacts (not companies), and not be dynamic - contacts already in the list are silently skipped, never duplicated - at most 1000 contacts per call
add_contacts_to_list
Add one or more leads to a campaign in a single call (max 100). Requires campaignId + a non-empty leads array. Each lead must have at least one identifying field (email, firstName, lastName, companyName, phone, linkedinUrl, linkedinUrlSalesNav, or customVariables). Server-side bulk dedup runs during the import — **do NOT call search_campaign_leads or search_contacts to pre-check** before this tool. The response reports each existing lead with outcome="skippedAlreadyInCampaign" (or "skippedDuplicateCrossCampaign" when deduplicate=true), so the LLM has full visibility without an extra round-trip. Invalid leads are reported in the results array with outcome="missingIdentifier", "forbiddenCustomKey", etc. — they do not abort the rest of the batch. Company matching: send companyDomain alongside companyName whenever you can (the work email usually gives it away). A name on its own only matches companies that have no domain, so omitting the domain creates a SECOND company with the same name and moves the contact onto it. Enrichment options (findEmail, verifyEmail, linkedinEnrichment, findPhone) and deduplicate apply to every lead in the batch. ⚠️ Enrichment COSTS CREDITS per successfully added lead — warn the user before enabling.
add_leads_to_campaign
REQUIRES CONFIRMATION: Add a step to an ALREADY CREATED campaign sequence (modification only). For initial campaign creation use save_campaign_from_proposal instead — it materializes the whole tree atomically. Supported types: email, linkedinSend, linkedinInvite, linkedinVisit, linkedinFollow, linkedinEndorse, linkedinLikeLastPost, linkedinCommentLastPost, linkedinWithdrawInvitation, linkedinVoiceNote (LinkedIn voice message. Two INDEPENDENT settings: recordMode = how the audio is produced, manual = the "Mark as manual" toggle. Set recordMode="ai" to generate the audio from a script via ElevenLabs: pass the script in `message` (full Liquid syntax) and the voice in `voiceId` (call list_voice_profiles first). When NO AI voice is available, set `manual: true` so the step becomes a per-lead recording task and the campaign stays launchable: do NOT set a voiceId and the script is optional (`message` is then only the optional LinkedIn invite-fallback text). Do NOT create a non-manual voice note with recordMode="manual" and no audio - the auto-send path still requires a recorded file at launch), manual, phone, whatsappMessage, sms, conditional, sendToAnotherCampaign, api, enrichment (⚠️ COSTS CREDITS: automatically enriches leads at this sequence step using the specified workflowIds; requires MULTI plan). By default the step is appended at the end; pass `index` (zero-based) to insert at a specific position (e.g. index=0 to insert before the first existing step). For YES/NO branching use type="conditional" with conditionKey and delayType. delayType is ALWAYS required: use "within" or "waitUntil" for action conditions (hasScore, emailsOpened, emailsClicked, emailsUnsubscribed, meetingBooked, linkedinInviteAccepted, linkedinOpened, aircallDone), use "within" with delay 0 for field-check conditions (hasEmailAddress, hasLinkedinUrl, hasPhoneNumber). For hasScore: use scoreComparator ("$gte"/"$lt") and scoreThreshold (0-100). For hasEmailAddress: use emailStatusFilter (["deliverable","risky","undeliverable","unverified"]). For aircallDone ("Call status", branch on native lemlist call dispositions): use callStatusFilter (call status KEYS, e.g. ["connected-positive","no-answer"]; keys are team-specific, call get_call_statuses first; omit to match any completed call). For customLeadInfo (branch on any custom lead variable): use customField (variable name, e.g. "secteur"; prefix "fields." for a contact field), customOperator ("equal"/"contains"/"empty"/"notEmpty"), customValue (required for equal/contains), with delayType="within" and delay 0. To move a lead between campaigns (e.g. when a LinkedIn invitation is not accepted within 7 days), use type="conditional" with conditionKey="linkedinInviteAccepted" and delayType="waitUntil", then add a type="sendToAnotherCampaign" step (with targetCampaignId) inside the NO branch. Beware of cycles between campaigns. For type="api" (outbound webhook to Zapier/Make/n8n/Pipedream/etc.): provide method (GET or POST only, iso with the lemlist UI) and url. The URL supports Liquid templating against lead variables. The request body for POST is automatically the lead data — custom bodies and custom headers are not supported. Response returns sub-sequence IDs for YES/NO branches. Also returns the full updated step list in `steps` (each with its real `stepId`, `sequenceId`, `type`, `delay`). Reuse those ids for any follow-up edit in the same turn — do NOT call get_campaign_context to rediscover steps. REQUIRES userConfirmed=true. Fails on running campaigns.
add_sequence_step
Add one or more email addresses, whole email domains, phone numbers or LinkedIn URLs to the unsubscribe blocklist in a single call. Blocks all future campaign sends to them. Use delete_unsubscribe to reverse. **Accepted values (each entry in `values`):** - An email address, e.g. "john@acme.com": blocks that address only. - A domain starting with "@", e.g. "@acme.com": blocks every lead whose email is on that domain. - A phone number, e.g. "+33612345678": blocks SMS and WhatsApp steps to that number. - A LinkedIn URL, e.g. "https://www.linkedin.com/in/john": blocks LinkedIn steps to that profile. An email block does not stop the LinkedIn steps of a lead that has not started yet: block its LinkedIn URL. Pass a lead's `linkedinUrl` (not `linkedinUrlSalesNav`) or `phone` exactly as search_campaign_leads returns it: any rewrite blocks nothing. Batch semantics: - One call handles up to 1000 targets. Always pass ALL the values the user asked to block in a single call. Do NOT call the tool once per value. - Duplicates and values that are already unsubscribed are silently ignored server-side (no per-item failure). - Use the "@domain.com" form when the user wants to stop contacting everyone at a company (e.g. "block @luxottica.com").
add_unsubscribe
Enrich one or more contacts (max 500). ASYNC — lemAgent clients receive a 'dataRef' to pass to bulk_get_enrichment_results. External MCP clients receive an inline 'results' array of { enrichmentId?, error?, metadata? } to poll individually. ALL options COST CREDITS per item. Types: find_email, find_phone, verify, linkedin_enrichment. Submitting an enrichment does NOT mean data will be found. An enrichment can complete with nothing found. Always confirm the actual result via bulk_get_enrichment_results (check each 'summary') before telling the user any data was found.
bulk_enrich_data
Poll one or more enrichments in one call. Provide exactly one of: a dataRef returned by bulk_enrich_data (first poll), the nextPollRef from a previous result (subsequent polls), OR a plain enrichmentIds list — not both. Each call returns ONLY the enrichments that completed or failed in this poll. Use nextPollRef as the dataRef input for the next call. Repeat until pending=0. When pending=0, the dataRef contains ALL completed rows from every poll — pass it to display_table to show the full results in one table. Intermediate polls return a dataRef with only the newly completed rows for incremental display. A completed enrichment (status "done") can still return NO data. Inspect each result's 'summary' before reporting anything: when 'summary.noDataFound' is true (or the only fields present are 'emailNotFound'/'phoneNotFound'), tell the user that profile was "not found". Never claim an email, headline, or company was found, and never narrate fields that are absent from the 'summary'. An empty results table means nothing was found, not success. lemAgent clients get compact summaries + dataRef + nextPollRef; external MCP clients get full 'data' and 'input' inline per entry.
bulk_get_enrichment_results
Compute cold-email infrastructure sizing from campaign inputs. Returns: - Peak daily volume + injection rate - Mailbox count (raw and with safety buffer) - ESP split (Google / Microsoft / SMTP) - Domains needed per seat (cap: 3 mailboxes per domain) - Warmup timeline (rampup + 14-day stabilization) - Lemlist slot cost (included + extras at $9/month) - Brand-consistent domain name suggestions - Mailbox naming proposals per SDR (when sdrs provided), with SDR userId echoed back in `sdrPlans[].userId` if it was passed in All math is deterministic — pure domain function, no LLM math. Use in Step 2 of the outreach-infra skill, after gathering campaign inputs via ask_question.
calculate_infrastructure
⚠️ **REQUIRED FIRST STEP**: You MUST call `load_skill("api-reference")` once in the current session before `call_api`. The server rejects every `call_api` until then. `load_skill("api-reference")` returns the live catalog of available endpoints (cached 1h from the OpenAPI spec). Without it the model cannot know which paths exist; with it, `call_api` is unlocked for the session. ⚠️ **FALLBACK ONLY** — Use a dedicated tool whenever one exists in your tools list. Call `call_api` only when no dedicated tool matches. Common operations are covered by dedicated tools — scan your tools list first for matches in these categories before reaching for `call_api`: - **Campaigns:** list, details, stats, reports, create, start/pause, readiness - **Leads:** add to campaign, update, enrich, search within a campaign - **Sequences:** list steps, add step, update step (with preview) - **Contacts & lists:** search, create, manage CRM lists - **Inbox:** list/read conversations, send email/LinkedIn/SMS/WhatsApp - **Team & user:** team info, members, settings, connected channels - **Enrichment:** single / bulk / lead; poll results - **Webhooks & unsubscribes:** list, create, delete - **People database:** filter options, search, push to contacts **Strict server-side validation:** - Endpoints covered by a dedicated tool are **rejected** — the error names the tool to use. - If that tool is **not in your tools list** (this connector exposes a narrowed set), the call runs instead and the result carries a `hint` naming the tool and the bucket that would provide it. Relay that hint to the user: they can widen their connector URL to get the dedicated tool. - Endpoints not found in the lemlist OpenAPI spec are **rejected** — suggestions of similar spec endpoints are returned in the error. **Genuine use cases (no dedicated tool yet):** - Campaign schedules: `GET /api/campaigns/:campaignId/schedules`, `POST /api/campaigns/:campaignId/schedules/:scheduleId` (associate), `DELETE /api/campaigns/:campaignId/schedules/:scheduleId` (remove), `GET /api/schedules`, `POST /api/schedules` (create) - Email templates - Any documented endpoint without a dedicated tool **Safety rules:** - GET requests execute immediately - POST, PUT, PATCH, DELETE require `confirmed: true` after user approval **Full API reference:** https://developer.lemlist.com/api-reference **Example — replace a campaign schedule:** 1. `POST /api/campaigns/cam_xxx/schedules/skd_new` (associate new) 2. `DELETE /api/campaigns/cam_xxx/schedules/skd_old` (remove old)
call_api
Check DNS health for email sending domains (MX, SPF, DMARC, blacklists). Returns score (0-100), per-check status, and DNS fix records.
check_domain_health
Remove the forced sender of one sequence step. The step then uses the campaign sender pool again. Use when the user asks to: - Stop sending a step from a specific team member or account - Put a step back on the campaign sender strategy Contract rules reproduced by the backend: - A LinkedIn or WhatsApp voice note step always has a forced sender: use set_sequence_step_sender to change it instead. - The channel type of the step comes back into the pool, as in the campaign editor. senderPoolChange lists the channel types that the change enabled or disabled. It does not tell whether each sender has an account of the type: read get_campaign_senders and report each error diagnostic. - On a running campaign, the pending tasks of the step move to a sender of the pool.
clear_sequence_step_sender
Write DNS records for a team-owned domain. Two modes: - Provide **records**: replaces the domain's full record set (SPF / DMARC / MX / CNAME etc.). - Provide **dkimRecord**: appends the DKIM TXT record only (after mailbox provisioning). Use in Step 4 (initial SPF/DMARC/MX) and Step 6 (DKIM after Google/M365 gives the public key) of the outreach-infra skill.
configure_domain_dns
Connect a custom SMTP/IMAP email account for sending and receiving emails. For Google/Microsoft, use the UI instead. - You need SMTP credentials for sending and IMAP credentials for receiving - Ports are typically 587 (SMTP) and 993 (IMAP) with TLS enabled - The sender email will be verified before the account is connected
connect_email_account
Copy every lead from one campaign into another, in a single call, by re-importing their variables. Prefer this over composing search_campaign_leads + add_leads_to_campaign whenever the user wants to copy / recreate / move / duplicate the leads of a whole campaign into another campaign (e.g. "copy the leads from campaign A into campaign B", "put everyone from the old campaign into the rebuilt one"). Composing the two other tools drops fields (Sales Nav URL, phone, custom variables) and creates new empty contacts — this tool does not. Use when the user asks about: - Copying/recreating a whole campaign's leads into another campaign - Repopulating a freshly duplicated campaign (duplication never copies leads) from the original Contract rules reproduced by the backend: - Works by lead id server-side: it re-imports every variable (linkedinUrlSalesNav, phone, custom fields) and re-resolves the CRM contact from the identity variables (email, LinkedIn URL), so an identified lead reuses its existing contact (no empty duplicate). - Both campaigns must belong to the current team; sourceCampaignId and targetCampaignId must be different. - ADDS to the target (source campaign is left untouched). Leads already in the target follow the same dedup rules as a manual push.
copy_campaign_leads
Use ONLY in the People Database scope. Return the exact number of People Database documents (leads or companies) that match a set of filters, without returning the documents themselves. Use it when: - The user asks how many people or companies match a set of criteria. - To refine a set of filters after people_database_nl_to_filters. - To size an audience before running a full search or building a campaign. - To compare how restrictive two filter sets are. Every filterId must be an exact id returned by people_database_nl_to_filters.
people_database_search_count
Create a NEW AI variable column (an AI-generated column in the Leads table: icebreaker, opener, company research, etc.) on a campaign. Provide the column name, the AI-generation prompt, and optionally the model. The column is created team-owned and editable, wired into the campaign so it shows up in the Leads table and generates for leads. Use {{variable}} placeholders in the prompt to reference existing fields or columns. The variable name must be unique on the campaign — creating a duplicate is rejected. To edit an existing column's prompt instead, use update_ai_variable_prompt; to read existing columns, use get_ai_variable_prompts. Creating the column only sets it up — it does NOT generate values. Values are generated per lead later (from the Leads table UI or on import) and that is what consumes credits, not this call. Pass autofill:true to turn the column's auto-generate toggle on, so every lead added or imported to the campaign afterwards (CSV import, CRM sync, manual add) generates it automatically; it stays off by default. To scrape LinkedIn profiles for the column, pass tools:["enrich-linkedin"] AND reference {{linkedinUrl}} in the prompt; enabling any tool forces the premium lemlist model and lemlist-credit billing (per lead, at generation). Use when the user asks to: - Add a new AI column / AI variable to a campaign's leads - Generate a new piece of AI content (research, icebreaker, summary) per lead - Have an AI column filled automatically for every lead imported into a campaign This mutates campaign configuration, so confirm the column name and prompt with the user before calling.
create_ai_variable_prompt
Create campaign. If subject AND body are provided, creates the first email step. If omitted, creates an empty sequence (use add_sequence_step to add a condition or any step type as the first step). Call add_sequence_step for each additional step. For a copilot, the tool assigns a default sender to the new campaign: the response names that member in `assignedSenderUserId`. Tell the user who it is: that member now sees the campaign, and may be another member than the user. Supports Liquid syntax, including spin for variations (only when the user asks for them): {% spin %}{% variation %}Hello{% variation %}Hi{% endspin %} — each variation must be genuinely different wording, never the same text repeated.
create_campaign_with_sequence
Create one or more campaign folders that share the same parent, in a single call. Use when the user asks about: - Adding one or several folders at the same level (pass them all in `names`). - Creating sub-folders under an existing folder (pass its `parentId`). For a nested chain (A > B > C) call once per level instead, threading each returned folderId as the next `parentId`. Contract rules reproduced by the backend: - Each name must be unique among folders that share the same parent. - Depth is capped at 15 levels, 500 folders per level, 5000 folders per team. - Best-effort: valid names are created even if others fail; the response lists `created` and `failed` (with a per-name reason).
create_campaign_folder
Create a new static company list in the team's CRM. Use when the user asks about: - Grouping companies or accounts into a new list that does not exist yet - Preparing a destination before add_companies_to_list Contract rules reproduced by the backend: - the list is always static; filter-driven (dynamic) lists are built in the web app, not here - the list starts empty — add its members with add_companies_to_list - check get_company_lists first: a list with that name may already exist
create_company_list
Create a new static contact list in the team's CRM. Use when the user asks about: - Grouping contacts into a new list that does not exist yet - Preparing a destination before add_contacts_to_list or push_contacts_from_people_database Contract rules reproduced by the backend: - the list is always static; filter-driven (dynamic) lists are built in the web app, not here - the list starts empty — add its members with add_contacts_to_list - check get_contact_lists first: a list with that name may already exist
create_contact_list
Create one or more custom enrichment waterfalls in ONE call, each serving the leads whose country is in 'conditions.country.in' (ISO 3166-1 alpha-2). A country may belong to only one waterfall per type (email, phone); leads with no country or an unassigned country use the default waterfall of the type. 'providers' is the execution order (first tried first); providers left out are appended disabled. Names are unique within a type, and a type holds at most 20 custom waterfalls. Run list_enrichment_waterfalls first to see the countries already taken and the legal provider ids. Entries are applied independently: 'results' reports the created waterfall or an error per name. Team-shared and free (no credits).
create_enrichment_waterfalls
Create a People Database persona for the current team. Use when the user asks about: - Saving a set of People Database filters as a reusable audience - Defining an ICP / persona to reuse later Contract rules reproduced by the backend: - name must be non-empty and unique within the team (duplicates are rejected) - mode must be "leads": company personas are not supported yet - every filterId must be an exact id from the People Database filter catalog (GET /api/database/filters) - filters gated by a plan the team does not have are silently dropped ⚠️ A persona only SAVES filters for reuse — it does NOT export or push results to the CRM. To USE the results (add to a contact list, push to a campaign), run lemleads_search (or, in the People Database panel, people_database_nl_to_filters) with this persona via personaId, then push_contacts_from_people_database. Returns the created persona id (pdp_xxx).
create_people_database_persona
REQUIRES CONFIRMATION: Push lemlist contacts or companies to the team's connected CRM — the grid's "Create in CRM". Each record is searched in the CRM first: linked when found, created there otherwise. Use when the user asks about: - Pushing, syncing or creating contacts or companies in their CRM - Forcing contacts that are missing from the CRM into it Two-phase confirmation flow: 1. First call without confirmed: returns status="awaiting_confirmation" and runs nothing. Tell the user which records will be pushed, that the missing ones will be created in the CRM, and ask for approval. 2. Only after the user replied yes, call again with the same arguments and confirmed=true. The user's request is not the approval: never send confirmed=true in the same turn as the first call. Contract rules reproduced by the backend: - entity="contact" takes idsOrEmails (ctc_xxx ids or emails), entity="company" takes idsOrDomains (cpn_xxx ids or domains); or listId (clt_xxx) for a whole list of that entity, never both - At most 10000 records per call, however they are named: references (TOO_MANY_RECORDS otherwise), the members of a listId (LIST_TOO_LARGE otherwise), or the companies the domains match, since a domain matches every company carrying it (TOO_MANY_MATCHES otherwise). References matching no lemlist record come back in notFound - A record already linked to a CRM record is synced with it again instead of searched (alreadyLinked) - A record with no email, domain or LinkedIn URL cannot be searched: it is left untouched and counted in notSearchable - A record whose CRM search is already queued is not queued twice (alreadyInProgress) - Requires a connected CRM (HubSpot, Salesforce, Pipedrive, Attio, Zoho): NO_CRM_CONNECTED otherwise - Processing is ASYNCHRONOUS: the counts say what was queued, not what happened. Never present the action as done, and do not poll. When the user asks for the outcome, read it on the records: search_contacts / search_companies with the same listId and crmSyncStatus (searching = still running, synced, not_found) after a list, or after references the crmSync block search_contacts (by email or name) / search_companies (by name) return on each record. Never repeat crmSyncStatus without listId to wait for the outcome: that filter reads every record of the team - Only a team admin can create records in the CRM (CREATE_IN_CRM_NOT_ALLOWED otherwise) - asLead=true creates Salesforce Leads, for contacts on Salesforce only (AS_LEAD_NOT_SUPPORTED otherwise) - On Salesforce, the connection must grant the object created (Contact, Account or Lead): CRM_OBJECT_NOT_ALLOWED otherwise
create_in_crm
Create one OR many standalone tasks (opportunities) on contacts, companies or campaign leads: to-dos listed on the Tasks / Focus page, each assigned to a teammate and due at its own date, for a person to complete. Use when the user asks about: - Creating a follow-up, reminder or to-do task on one or several contacts, companies or leads - Planning a call, or an email / LinkedIn / WhatsApp message to send later from the Tasks page - Assigning a task to a teammate with a due date and a priority Pass every task in ONE call through tasks[] (1 to 100), each with its own record, title, type, content, priority, due date and assignee. The result is always the aggregate { total, succeeded, failed, results[] }: each entry carries the task's index in tasks[], its record ID, and either opportunityId or an error code. Contract rules reproduced by the backend: - Exactly one of contactId, companyId or leadId per task. A lead task is linked to the lead's contact, shows the lead's campaign as its Task source, and follows its own due date and assignee alongside the lead's sequence. - A company task can only be of type "manual". - message holds the instructions of the task; content is the message to send (email, linkedinSend, whatsappMessage only); subject is email only. - assignedTo must be a teammate (list them with get_users); it defaults to the current user. - dueDate defaults to now; a past date creates a task that is already due. - A task that breaks one of the rules above rejects the whole call before any task is created: fix it and send the full list again. - A task whose record or assignee is not found fails on its own (error code in its results[] entry); the other tasks are still created. - A message task holds the message for later: it is sent with send_task, once the user approves. After the call: - Link every created task as [title](task://opp_xxx), with the exact title you sent and its opportunityId. - Retry ONLY the failed indexes: calling again with the whole list creates the successful tasks a second time.
create_tasks
Get a presigned URL to upload a file from the user's machine to lemlist storage, then reference it by key. Use this to AVOID retyping large file contents through the conversation. Flow: 1. Call this tool with purpose, fileName, and the EXACT fileSize in bytes. 2. Upload the raw file to the returned uploadUrl with an HTTP PUT, e.g.: curl -T leads.csv -H "Content-Type: <contentType>" "<uploadUrl>" 3. Pass the returned uploadKey to the tool that consumes it: - purpose="leadsCsv" → import_leads_to_campaign - purpose="contactsCsv" → import_contacts_from_csv - purpose="companiesCsv" → import_companies_from_csv - purpose="csvData" → read_uploaded_csv The URL is short-lived (expiresInSeconds). fileSize MUST be the real byte size of the file — it is signed into the URL, so a mismatch makes the upload fail, and a size above the limit is rejected up front.
create_upload_url
Create a new watch list for the current team. Use when the user asks about: - Starting to monitor a new signal type - Setting up a watch list end-to-end (create + configure + activate) - Creating a draft watch list that the user will configure later in the UI Contract rules reproduced by the backend: - activate=true ⇒ segmentType AND signalProcessingType must be set - signalProcessingType="create_opportunity" ⇒ signalOpportunityTemplate required (and forbidden otherwise) - personaId is accepted ONLY on a company watch list with signalProcessingType="push_to_campaign" (any other config is rejected), and only for teams in the personas beta - personaId is optional there: without it the signals are still recorded, they simply source no contact, so nothing reaches the campaign - get a personaId from list_people_database_personas (or create_people_database_persona); never invent one - Only segmentType="all" is accepted via API (CRM lists and CSV imports are not)
create_watch_list
Create a webhook for real-time campaign activity notifications. Max 200 per account, no duplicate URLs. Filter by activity type (emailsSent, emailsOpened, emailsReplied, etc.) and/or campaignId.
create_webhook
Create a new company in the user's Lemlist company database, or update an existing one (upsert). Requires a name plus at least one identifier: domain, linkedinUrl, or linkedinUrlSalesNav. If a company with the same domain, LinkedIn URL, or Sales Navigator URL already exists, it will be updated instead of creating a duplicate. Returns the company data and whether it was created or updated.
create_or_update_company
Create a new contact in the user's Lemlist contact database, or update an existing one (upsert). Provide at least one identifier: email, linkedinUrl, or contactId. Use when the user asks to: - Create a contact from an email or LinkedIn URL - Update fields on an existing contact (standard fields AND custom fields) Identifiers: - email / linkedinUrl: match an existing contact (updated instead of duplicated) or create one if none matches. - contactId (ctc_xxx): update that exact contact in place, update-only. Prefer it when search_contacts already resolved the contact. Custom fields go in the "fields" object; call get_contact_fields_schema first for the valid names. Returns the contact data and whether it was created or updated.
create_or_update_contact
Delete one or more campaign folders. Campaigns are NEVER deleted — each folder's campaigns and sub-folders move up one level (to the parent folder, or to the root if the folder was at the top). Use when the user asks about: - Removing one or several folders while keeping their campaigns (pass them all in `folderIds`). Contract rules reproduced by the backend: - Deleting a folder is blocked if a sub-folder would collide, by name, with a folder already present in the parent — rename the conflicting sub-folder first. - Best-effort: each id is handled independently; the response lists `deleted` and `failed` (with a per-id reason).
delete_campaign_folder
Permanently delete leads from ONE campaign in a single bulk call. Irreversible: it also removes each lead's activity and task history in that campaign. Use when the user asks about: - Removing a specific set of leads from a campaign at once (e.g. after moving or segmenting them elsewhere) - Cleaning leads out of a campaign without calling the unitary delete endpoint one lead at a time Two-phase confirmation flow (mandatory): 1. First call WITHOUT confirmed (or confirmed=false): returns the count and a sample of the exact leads that will be deleted, with status="awaiting_confirmation". Show these to the user and get explicit approval via ask_question. 2. Once the user has approved, call again with confirmed=true to actually delete. Contract rules reproduced by the backend: - Scoped to a SINGLE campaignId; a lead id is unique to one campaign (campaignId + email). - Every leadId MUST belong to campaignId. Ids from another campaign (or already deleted) are rejected with an error, not silently skipped. Re-fetch the ids via search_campaign_leads on the target campaign. - At most 1000 lead ids per call. - Never call with confirmed=true without explicit user approval.
delete_campaign_leads
Delete one or more custom enrichment waterfalls in ONE call; their countries fall back to the default waterfall of the type. Default waterfalls (default_email, default_phone) cannot be deleted — use reset_enrichment_waterfalls. Ids are applied independently: 'results' reports 'deleted: true' or an error per waterfallId. Team-shared and free (no credits).
delete_enrichment_waterfalls
REQUIRES CONFIRMATION: Delete a lemlist company. Only the lemlist record is removed — no CRM-side propagation. REQUIRES userConfirmed=true. By default the call fails with COMPANY_HAS_CONTACTS if contacts are still attached; pass force=true to detach them (their companyId is unset) before deleting. Typical use: as the final step of the duplicate-remapping flow — after reassigning contacts of a duplicate to the canonical company (via create_or_update_contact with companyId), drop the now-empty duplicate.
delete_company
REQUIRES CONFIRMATION: Delete a lemlist contact by its ID (ctc_xxx) or email. Only the lemlist record is removed — no CRM-side propagation. Deletion cascades to the contact's leads, opportunities, list memberships, inbox conversations and activities. REQUIRES userConfirmed=true. Fails with CONTACT_DELETE_BLOCKED when the contact cannot be deleted right now (e.g. an enrichment is still running — retry once it finishes).
delete_contact
Delete a memory by topic. Use this when: - The user asks you to forget something - Information is explicitly outdated or incorrect - The user says "that's no longer true" or "forget about..."
delete_memory
Delete a People Database persona of the current team. The deletion is permanent. Use when the user asks about: - Removing a persona they no longer need - Cleaning up duplicate or outdated personas Important: - Ask the user to confirm before calling this tool; there is no undo. - Use list_people_database_personas to resolve a persona name into its id. - An unknown id, another team's persona, and the auto-generated system persona all fail the same way (not found) — none of them can be deleted here.
delete_people_database_persona
Delete a saved People Database search of the current team. The deletion is permanent. Use when the user asks about: - Removing a saved search they no longer need - Cleaning up duplicate or outdated saved searches Important: - Ask the user to confirm before calling this tool; there is no undo. - Use list_saved_searches to resolve a saved search name into its id. - An unknown id and another team's saved search both fail as not found.
delete_saved_search
REQUIRES CONFIRMATION: Delete a step from a campaign sequence. Use this to remove a step that was added by mistake or is no longer needed (e.g. a wrongly-placed warm-up step). Cascades sub-sequences for conditional steps. Returns the full updated step list in `steps` (each with its real `stepId`, `sequenceId`, `type`, `delay`). Reuse those ids for any follow-up edit in the same turn — do NOT call get_campaign_context to rediscover steps. Sender pool: the tool adjusts the sender pool of the campaign as the campaign editor does. An added step enables its channel type (email, WhatsApp, phone) on each pool sender who owns an account of the type and has none enabled, healthy accounts first. A removed step disables each channel type that no step uses any more. This adjustment adds no sender to an empty pool. The response carries `senderPoolChange`: the channel types that the adjustment enabled (`enabledChannelTypes`) or disabled (`disabledChannelTypes`). It does not tell whether each sender can send the step: after a step of a channel type that the campaign did not use yet, read the pool with get_campaign_senders and report each error diagnostic to the user, for example channel_missing when a pool sender has no account of the new type (load_skill("senders") for the actions). `senderPoolWarning` means that the step change is saved but the pool was not adjusted: tell the user, then fix the pool with the sender tools. REQUIRES userConfirmed=true. Fails on a running campaign. Fails once leads have entered the campaign, whatever its state: pausing does not lift that, use skip_step_for_everyone instead.
delete_sequence_step
Remove one or more email addresses, whole email domains, phone numbers or LinkedIn URLs from the unsubscribe list in a single call. Re-enables the targets to be contacted again in future campaigns. **Accepted values (each entry in `values`):** - An email address, e.g. "lead@example.com": re-enables that address only. - A domain starting with "@", e.g. "@example.com": re-enables every address on that domain (only removes a domain-level block; per-address blocks stay). - A phone number or a LinkedIn URL, exactly as it was blocked (get_unsubscribes lists the stored values). Batch semantics: - One call handles up to 1000 targets. Always pass ALL the values the user asked to re-subscribe in a single call. Do NOT call the tool once per value. - Values that weren't unsubscribed (or are protected internal blocks) are silently ignored server-side. **Use this when:** - Leads were unsubscribed by mistake - A lead wants to re-subscribe to your campaigns - You need to re-enable communication with specific targets - Testing campaigns with your own email address **Important notes:** - Once removed, these targets can be contacted again - This does NOT automatically re-add the leads to any campaign - The leads will need to be added to campaigns manually - Use with caution — respect unsubscribe preferences **Example:** { "values": ["lead@example.com", "@partner.com"] } **Common workflow:** 1. Check if the targets are unsubscribed (via search_campaign_leads) 2. Call delete_unsubscribe with the full list to remove them from the unsubscribe list 3. Add the leads back to a campaign if needed **IMPORTANT:** Do NOT pass confirmed=true on your first call. Ask the user to confirm the values via ask_question, then call again with the same values and confirmed=true.
delete_unsubscribe
Delete a watch list. The backend performs a soft delete (status set to "delete") and stops processing signals for this watch list immediately. Use when the user asks about: - Removing a watch list they no longer want to monitor - Cleaning up outdated or duplicate watch lists Two-phase confirmation flow: 1. First call WITHOUT confirmed (or confirmed=false): returns the watch list details and status="awaiting_confirmation". Use these details to ask the user to confirm via ask_question. 2. Once the user has explicitly approved, call again with confirmed=true to actually delete. Important: - Never call with confirmed=true without explicit user approval. - Use list_watch_lists first if you need to resolve a name into a watch list ID. - The watch list is soft-deleted; its signals are not removed.
delete_watch_list
Delete a webhook from your lemlist account. The webhook will stop receiving notifications immediately. **Use this when:** - Removing outdated integrations - Cleaning up unused webhooks - Replacing a webhook (delete old, create new) - Webhook URL has changed and needs to be recreated **Important notes:** - Once deleted, the webhook cannot be recovered - The webhook will immediately stop receiving notifications - Use get_webhooks to find the webhook ID first **Example:** { "webhookId": "hoo_abc123xyz" } **Common workflow:** 1. Call get_webhooks to list all webhooks 2. Find the webhook ID you want to delete 3. Call delete_webhook with that ID
delete_webhook
Disable one or more channels on one sender of a campaign, and keep the person: a mailbox, a WhatsApp account, a phone number. The other channels of the sender stay active. When the last channel leaves, the sender leaves the pool. Keywords: remove this mailbox from the campaign, stop sending from ana@old.com, drop Ana's WhatsApp on this campaign. Use when the user asks about: - Removing one channel of a sender from a campaign ("remove the mailbox ana@old.com from the Q4 campaign") - Stopping one channel type for a sender (the type without id disables every channel of the type) To remove the person, use remove_campaign_senders. Call get_campaign_senders first: it gives the channel ids of the pool. Two-phase confirmation flow: 1. First call WITHOUT confirmed: the backend counts the contacted leads that keep a sender or a channel this change removes (impact.contactedLeads). Above 0 the call writes nothing and answers status="awaiting_confirmation" with "data" (the pool after the change) and the count: show them to the user, ask with ask_question, then call again with confirmed=true and the SAME input. At 0 the call writes at once. 2. Never call with confirmed=true without explicit user approval. Contract rules reproduced by the backend: - A campaign with a dynamic sender strategy (contactOwner, leadImporter, customField:<field>) has a read-only pool that the leads fill: every pool write is refused. Switch the strategy with set_campaign_sender_strategy first, only when the user wants it. - A channel type is accepted only when a non-forced step of the campaign uses it: no WhatsApp channel without a WhatsApp step. Add the step first with add_sequence_step: it enables the type on each pool sender who owns an account of it, and lists the enabled types in senderPoolChange. - Every entry must be a team member who owns the listed channels; an alias must be one of the aliases of the mailbox. - LinkedIn has no channel to pick: a sender in the pool is enabled on LinkedIn. Never list linkedin with an id. - A pool with more than one sender needs the emailPro plan; the mailboxes above the plan allowance are dropped. - A write runs on a running campaign: the leads not contacted yet get a new sender from the pool, the contacted leads keep theirs. - Every write answers "data": the pool after the change, with the diagnostics of each sender and channel. Read them and report the errors to the user. - linkedin cannot be disabled alone: a sender in the pool is enabled on LinkedIn. Remove the sender instead.
disable_campaign_sender_channels
Disconnect email account. Stops sending immediately. Cannot be undone. Use get_user_channels to find account ID.
disconnect_email_account
Remove the team's saved API key (or ZoomInfo login) for an external enrichment provider (Lusha, Apollo, ZoomInfo): lemlist stops calling it and it is dropped from the waterfalls. Only a connected external provider can be disconnected; anything else returns an error. Team-shared.
disconnect_enrichment_provider
Show leads in an interactive workspace table. Users can select, filter, and push to campaigns. For the two-step pattern (lemleads_search in companies mode with `description` -> display_leads), you MUST pass the returned `dataRef` to this tool. The server resolves it to the full company set server-side and injects a `currentCompanyByIds` filter so the leads table queries leads at those companies. This persists in the workspace item (no 30-min TTL concern). Do NOT copy the `companyIds` array into a `currentCompanyByIds` filter inline — emitting hundreds of IDs inline risks truncation; pass them via the `companyIds` field instead and the server builds the filter for you. FOLLOW-UP TURNS over an existing companies table ("find CEOs of those companies", "now show me leads from this list", "and the marketing directors"): the workspace already holds the company set, so DO NOT re-run lemleads_search. Recovery order: 1. If the companies-mode lemleads_search `dataRef` from earlier is still in your context AND was issued in the last ~30 minutes, pass it as `dataRef`. 2. Otherwise, call `get_workspace_items({ itemType: "companies" })`, read `data.companyIds` from the workspace_companies item, and pass that array via the `companyIds` field on this tool. The server builds `currentCompanyByIds` for you (no truncation risk). Re-running lemleads_search to "re-verify the count" loses the curated set and is what produces the bad / off-topic lead lists. Otherwise (no prior companies table involved), call display_leads directly with filters only — the table loads data dynamically. Pass any combination of `filters`, `dataRef`, and `companyIds` together; they are AND-combined server-side. To modify an existing LEADS search: get_workspace_items -> display_leads with updated filters + replaceItemId. Only pass replaceItemId when the target item is itself a leads table — never to convert a companies/messages/other item into leads. To show a different artifact type alongside, omit replaceItemId so a new item is appended.
display_leads
Fetch one page of People Database leads for the workspace-leads table. App-only: called by the leads grid iframe (pagination, select-all), not by the agent. Returns the raw Elastic hits the iframe transforms into rows, the total count, and the already-in-campaign / already-in-contacts maps.
display_leads_page
Display a data table in the workspace panel. CRITICAL RULES — follow exactly or the table will be empty: 1. dataRef: If the source tool returned a dataRef string, pass it as dataRef (preferred — avoids large data transfer). The rows will be resolved automatically from the stored reference. 2. rows: Only if no dataRef is available. Pass the ORIGINAL data array from the tool result AS-IS. NEVER construct row objects manually or map/transform the array. 3. columns: Use suggestedColumns from the source tool result directly when available. NEVER invent column keys — they must match actual property names in the row objects. PREFERRED: dataRef=result.dataRef, columns=result.suggestedColumns, groupKey=result.groupKey, tableType=result.tableType FALLBACK: rows=result.campaigns, columns=result.suggestedColumns WRONG: rows=result.campaigns.map(c => ({sentCount: c.stats.sentCount})) — this strips data Always forward groupKey and tableType from the source tool when available.
display_table
Duplicate a whole campaign server-side: the copy gets the same sequence, step for step, with every step's content carried over as-is. ALWAYS prefer this over rebuilding a campaign step by step whenever the user wants to copy / clone / duplicate / recreate an existing campaign, or start a new one "like" an existing one (e.g. "duplicate my Q3 campaign for the DACH market", "same campaign but for CTOs"). Replaying a campaign's steps through add_sequence_step drops what that tool cannot set, e.g. images, videos, A/B variants, the plain-text flag, or a condition with several branches. This tool copies the underlying templates, so it drops nothing. To adapt the copy afterwards, duplicate first, then edit the new campaign's steps with update_sequence_step. Never reconstruct from scratch to change a few messages. Use when the user asks about: - Duplicating / cloning / copying an existing campaign - Starting a campaign from an existing one, for another market, persona or language - Re-running a past campaign on a new audience Contract rules reproduced by the backend: - Copies the sequence, its steps and their content, plus the campaign's schedules. Does NOT copy leads: pair with copy_campaign_leads when the user wants the same audience. - Send stats start at zero on the copy, and it is named "<source name> Copy" unless you pass a name. - Requires the createCampaign permission. - The source campaign is never modified.
duplicate_campaign
Enable one or more channels on one sender of a campaign: a second mailbox, the WhatsApp account, a phone number. The other channels of the sender do not change. Also sets the send-as alias of a mailbox. A sender outside the pool joins it with the listed channels. Idempotent. Keywords: add Ana's WhatsApp on the campaign, send from this mailbox too, change the sending alias, send as hello@acme.com. Use when the user asks about: - Adding one channel to a sender already in the pool ("add Ana's WhatsApp on the Q4 campaign") - Changing the alias a mailbox sends from ("Ana must send from hello@acme.com"): pass the email channel with its id and the alias - Enabling every account of a type on a sender: pass the type without id, the healthy accounts are enabled Before any write: call get_senders with the campaignId. It lists every team member who can send, in the pool or not (inPool), with the user ids, the channel ids, the aliases, the health of each channel and requiredChannelTypes, the channel types that the steps require. Never guess a user id, a mailbox id, a WhatsApp account id or an alias. Load load_skill("senders") first: it tells which tool fits the request, when to change the sender strategy, and how to read the diagnostics. Contract rules reproduced by the backend: - A campaign with a dynamic sender strategy (contactOwner, leadImporter, customField:<field>) has a read-only pool that the leads fill: every pool write is refused. Switch the strategy with set_campaign_sender_strategy first, only when the user wants it. - A channel type is accepted only when a non-forced step of the campaign uses it: no WhatsApp channel without a WhatsApp step. Add the step first with add_sequence_step: it enables the type on each pool sender who owns an account of it, and lists the enabled types in senderPoolChange. - Every entry must be a team member who owns the listed channels; an alias must be one of the aliases of the mailbox. - LinkedIn has no channel to pick: a sender in the pool is enabled on LinkedIn. Never list linkedin with an id. - A pool with more than one sender needs the emailPro plan; the mailboxes above the plan allowance are dropped. - A write runs on a running campaign: the leads not contacted yet get a new sender from the pool, the contacted leads keep theirs. - Every write answers "data": the pool after the change, with the diagnostics of each sender and channel. Read them and report the errors to the user. For several senders at once, use add_campaign_senders. To remove a channel, use disable_campaign_sender_channels. No user confirmation required.
enable_campaign_sender_channels
lemlist ChatGPT Plugin FAQ
How the directory, categories and Discoverability Score work.
Read the methodologyHow do I improve lemlist's ChatGPT Plugin discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
What are lemlist alternatives on ChatGPT?
As of 2026-11-02, lemlist competes with Outreach, ACA, Amplemarket, BoothIQ, Business Follow-up Assistant, Crono, Expandi, FirstTouch and 24 more in ChatGPT Sales Engagement & Outreach Automation, ranked by public Discoverability Score.
Where does lemlist rank in Sales Engagement & Outreach Automation on ChatGPT?
As of 2026-11-02, lemlist ranks #13 of 33 in ChatGPT Sales Engagement & Outreach Automation with a Discoverability Score of 0/100 (Invisible).
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.