Skip to main content
POST
Add and update contact
Creates a new contact in your CRM, or updates an existing one if a contact with the same email, linkedinUrl, or linkedinUrlSalesNav already exists (upsert). On update, the updateStrategy query parameter decides what the existing record keeps (see below). By default, sent values replace stored ones and empty values are ignored.

Upsert matching

At least one identifier is required: If a contact with the same email, linkedinUrl, or linkedinUrlSalesNav already exists, the endpoint updates it instead of creating a duplicate. When contactId is provided, the contact is matched by its ID directly — email and linkedinUrl are not required and are not used for matching (they are stored as data if provided).
contactId can only be used to update an existing contact. It cannot be used to create a new contact — use email or linkedinUrl for creation.

Update strategy

The updateStrategy query parameter decides what an existing contact keeps: null and absent keys never touch a field. Identifiers (email, linkedinUrl, linkedinUrlSalesNav) are never cleared. Under fillEmptyOnly, the company link, the owner and the status are kept when set and filled when missing. A new contact receives every value sent. Any other value answers 400 INVALID_UPDATE_STRATEGY.
Kept values are reported: warnings carries a FIELDS_KEPT entry with the field names in params.fields. It appears under fillEmptyOnly on a stored value, and under the default when an empty string is ignored on a filled field, never for an identical value.

Linking to a company

You can link the contact to a company that already exists in your lemlist CRM using one of the following fields (in order of priority): When a company is successfully linked, the response includes companyLinked: true and the companyId.

Owner assignment

You can assign an owner to the contact using the contactOwner field. Accepted formats:
If the provided value does not match a team member (invalid format, unknown email, or unknown user ID), the contact is still written and the response carries an OWNER_NOT_FOUND or INVALID_OWNER_FORMAT entry in warnings. On creation, the contact defaults to the API key owner; on update, the current owner is unchanged.
On an existing contact, updateStrategy decides the owner: Without contactOwner, the owner is never touched.

Authorizations

Authorization
string
header
required

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

Query Parameters

updateStrategy
enum<string>
default:overwriteIgnoreEmpty

What an existing record keeps. overwriteIgnoreEmpty (default): sent values replace stored ones, empty values are ignored. overwrite: an empty string clears the field. fillEmptyOnly: only empty fields are filled, identifiers, links, owner and status kept. A new record receives every value sent. Other values: 400 INVALID_UPDATE_STRATEGY.

Available options:
overwrite,
overwriteIgnoreEmpty,
fillEmptyOnly

Body

application/json
contactId
string

Existing contact ID. Updates a specific contact by ID, bypassing email/LinkedIn matching. Can only be used to update an existing contact, not to create a new one. When provided, email and linkedinUrl are not required. At least one of contactId, email, linkedinUrl, or linkedinUrlSalesNav is required.

email
string

Contact email address. Used as a unique key for upsert matching. At least one of contactId, email, linkedinUrl, or linkedinUrlSalesNav is required.

linkedinUrl
string

LinkedIn profile URL. Used as an alternative unique key for upsert matching. At least one of contactId, email, linkedinUrl, or linkedinUrlSalesNav is required.

linkedinUrlSalesNav
string

LinkedIn Sales Navigator profile URL. Used as an alternative unique key for upsert matching.

additionalEmails
string[]

Additional email addresses for the contact. Each must be a valid email address.

firstName
string

Contact first name.

lastName
string

Contact last name.

phone
string

Contact phone number.

jobTitle
string

Contact job title. If a company is linked, this is saved as part of the job data.

jobDescription
string

Contact job description. If a company is linked, this is saved as part of the job data.

picture
string

URL of the contact's profile picture.

timezone
string

Contact timezone.

industry
string

Contact industry.

languages
string

Contact languages.

location
string

Contact location.

skills
string

Contact skills.

summary
string

Contact summary or bio.

tagline
string

Contact tagline.

contactOwner
string

Owner of the contact. Can be a user ID (e.g. usr_...) or a team member's email address. If the provided value does not match a team member, the contact is still written with an OWNER_NOT_FOUND or INVALID_OWNER_FORMAT entry in warnings: the owner defaults to the API key owner on creation and is unchanged on update. On update it replaces the current owner, except under fillEmptyOnly where it is only set when the contact has none.

source
string
default:api

Origin of the contact record. Set on creation only and cannot be updated afterwards. Defaults to api.

companyId
string

ID of a company already existing in lemlist to link to this contact. Takes priority over companyDomain and companyLinkedinUrl.

companyDomain
string

Domain of a company already existing in lemlist to link to this contact (e.g. lemlist.com). Used if companyId is not provided.

companyLinkedinUrl
string

LinkedIn URL of a company already existing in lemlist to link to this contact. Used if companyId and companyDomain are not provided.

{key}
any

Any additional key is treated as a custom field. Custom fields must be registered in the team's CRM field registry beforehand.

Response

Existing contact updated (upsert matched by email or LinkedIn URL)

success
boolean
data
object

Same shape as the 201 response, with created: false and updated: true.

warnings
object[]

Non-blocking notices: owner or company not resolved, or FIELDS_KEPT when the update strategy kept values you sent (params.fields names them).