Skip to main content
POST
Create Lead in Campaign
This endpoint creates, it never updates. A contact that already has a lead in this campaign is refused with 400 LEAD_ALREADY_IN_CAMPAIGN (409 from December 1, 2026, same message), nothing written; use PATCH /campaigns/{campaignId}/leads/{leadId} instead. With deduplicate=true, a contact with a lead in another campaign is refused with 409 LEAD_ALREADY_IN_OTHER_CAMPAIGN; only this parameter drives that check, not the campaign’s “remove duplicates” setting. POST /campaigns/{campaignId}/leads/{leadIdOrEmail} behaves the same, with the email in the path.
The lead is imported as the API key’s user. When its company is not in lemlist yet, that user needs the “Create companies” permission, otherwise the request fails with 403 ({"error": "The user jane@acme.com does not have the permission to create companies"}) and nothing is written. A company already in lemlist is linked as usual.Likewise, when its contact is not in lemlist yet, that user needs the “Create contacts” permission, otherwise the request fails with 403 ({"error": "The user jane@acme.com does not have the permission to create contacts"}) and nothing is written, company included. A contact already in lemlist is updated as usual.When the API key’s user is no longer in the team, they hold no permission there: the error says so ({"error": "The user jane@acme.com is no longer in this team: ask a current member to create a new API key or reconnect"}).
The lead is always new, but the contact and the company it matches are updated with the fields you send; updateStrategy decides what they keep. overwrite (default): sent values replace stored ones, an empty value clears. overwriteIgnoreEmpty: same, empty values ignored. fillEmptyOnly: only empty fields are filled, identifiers, company link, owner and status kept, and the lead takes the values the contact kept. Kept values are listed in warnings (FIELDS_KEPT, params.fields, company fields prefixed with company).
Beyond the standard fields above, any additional key/value pair you send in the body is stored as a custom variable on the lead and can be used in your campaign with {{yourVariableName}}.In the example, companySize and customVariable1 are custom variables.Naming rules: only letters, digits, _, -, space and # are kept — any other character (e.g. . or $) is replaced by _. Values are stored as text.
Company fields — companyName, companyDomain, companyIndustry, any company-prefixed key — reach the company record the lead is matched to, the same record every other lead linked to it reads, not that lead alone. Creating a lead with its company is the intended flow; to edit a company on purpose, use Upsert Company.

Linking to a CRM record

Send crmId with the id of a record in your connected CRM to link the lead’s contact to that record. lemlist links it without searching the CRM, then runs a first sync that follows your field mapping (the CRM wins conflicts by default). The response’s hubspotLeadId, salesforceContactId, salesforceLeadId, pipedriveLeadId or attioLeadId shows the record the contact is linked to.
crmId is in closed beta. Unless the CRM ID remap beta is enabled for your team, it is stored as a custom variable like any other key. It also requires an admin API key.
The id takes the formats of Upsert Contact: a HubSpot, Pipedrive or Zoho numeric id (send a Zoho id as a string), an Attio record id, or a Salesforce Contact (003…) or Lead (00Q…) id. This call adds a lead: it never moves a link, and never refuses the lead because of its crmId. Any other reason the id cannot be applied — an API key that is not an admin’s, an id that is not one of your CRM’s, no CRM connected, a record missing, merged or converted in the CRM, a CRM that did not answer — adds the lead without the link and names the reason in warnings (see the 200 response).

Authorizations

Authorization
string
header
required

Basic authentication header of the form Basic <encoded-value>, where <encoded-value> is the base64-encoded string username:password.

Path Parameters

campaignId
string
required

The unique identifier of the campaign

Query Parameters

deduplicate
boolean

Refuse the lead with 409 LEAD_ALREADY_IN_OTHER_CAMPAIGN when the contact already has one in another campaign. Default: false. The campaign's own "remove duplicates" setting does not apply here.

linkedinEnrichment
boolean

Run the LinkedIn enrichment. Default: false

findEmail
boolean

Find verified email. Default: false

verifyEmail
boolean

Verify existing email (debounce). Default: false

findPhone
boolean

Find phone number. Default: false

updateStrategy
enum<string>
default:overwrite

What the matched contact and company keep (the lead is always created). overwrite (default): sent values replace stored ones, an empty string clears. overwriteIgnoreEmpty: empty values ignored. fillEmptyOnly: only empty fields filled, identifiers, links, owner and status kept. Other values: 400.

Available options:
overwrite,
overwriteIgnoreEmpty,
fillEmptyOnly

Body

application/json
email
string

Email of the lead

firstName
string

First name of the lead

lastName
string

Last name of the lead

companyName
string

Company name

jobTitle
string

Job title

linkedinUrl
string

LinkedIn profile URL

picture
string

Profile picture URL

phone
string

Phone number

companyDomain
string

Company domain

icebreaker
string

Personalized icebreaker message

timezone
string

Lead's timezone in IANA format (e.g., Europe/Paris, America/New_York)

contactOwner
string

Contact owner (user ID or user login email)

crmId
string

Closed beta: stored as a custom variable like any other key unless the CRM ID remap beta is enabled for your team. Id of the record of the connected CRM to link the lead's contact to: a HubSpot, Pipedrive or Zoho numeric id (send a Zoho id as a string: its 19 digits are too long for a JSON number), an Attio record id, or a Salesforce Contact (003…) or Lead (00Q…) id of 15 or 18 characters. Requires an admin API key. Never refuses the lead: a new contact is created already linked, a contact without a link is linked, a contact linked to another record keeps it, and an id that cannot be applied comes back in warnings. See the endpoint page.

Example:

"123456789"

{key}
string

Response

Success

campaignId
string
campaignName
string
email
string<email>
firstName
string
lastName
string
companyName
string
jobTitle
string
companyDomain
string
_id
string
isPaused
boolean

Whether the lead is paused in the campaign

contactId
string

Associated contact ID

hubspotLeadId
string

The HubSpot contact the lead's contact is linked to. Present only when it is linked.

salesforceContactId
string

The Salesforce Contact (003…) the lead's contact is linked to. Present only when it is linked.

salesforceLeadId
string

The Salesforce Lead (00Q…) the lead's contact is linked to. Present only when it is linked.

pipedriveLeadId
string

The Pipedrive person the lead's contact is linked to. Present only when it is linked.

attioLeadId
string

The Attio person record the lead's contact is linked to. Present only when it is linked.

warnings
object[]

Non-blocking notices, never a failure — the request went through. They tell you why the company part was skipped, when it was, why the crmId was not applied, and which values the update strategy kept. See code.