lemlist Companies API

CRM-side companies and company notes.

OpenAPI Specification

lemlist-companies-api-openapi.yml Raw ↑
openapi: 3.0.0
info:
  title: lemlist Companies API
  version: 1.0.0
  description: The Companies operations of the lemlist API, split by tag from the OpenAPI lemlist publishes
    at https://developer.lemlist.com/api-reference/openapi/v2.json. Operation content is carried verbatim
    from the provider spec.
servers:
- url: https://api.lemlist.com/api
security:
- basicAuth: []
tags:
- name: Companies
paths:
  /companies:
    get:
      summary: Get Many Companies
      tags:
      - Companies
      parameters:
      - name: idsOrDomains
        in: query
        required: false
        description: Comma-separated list of company IDs or domains to fetch. When provided, returns only
          matching companies (no pagination). Each value is classified as a company ID (e.g. `cpn_xxx`)
          or a domain (e.g. `example.com`). URLs are normalized automatically (e.g. `https://example.com/path`
          → `example.com`). Invalid values are silently skipped. Maximum 100 values.
        example: cpn_gG7PsmZFpEAnpMCHO,persana.ai
        schema:
          type: string
      - name: offset
        in: query
        required: false
        description: Number of companies to skip for pagination. Defaults to 0. Ignored when `idsOrDomains`
          is provided.
        schema:
          type: integer
          minimum: 0
          default: 0
      - name: sortBy
        in: query
        required: false
        description: The field by which to sort. Currently, only 'createdAt' is supported.
        example: createdAt
        schema:
          type: string
          enum:
          - createdAt
      - name: sortOrder
        in: query
        required: false
        description: The sort direction. Use 'desc' for descending order; any other value (or omission)
          will sort in ascending order.
        example: desc
        schema:
          type: string
          enum:
          - asc
          - desc
      - name: search
        in: query
        required: false
        description: Search by company name (case insensitive)
        example: lemlist
        schema:
          type: string
      - name: fields
        in: query
        required: false
        description: Returns selected fields. Returns all fields if empty. Each field is separated by
          a comma (e.g., '_id,fields.name,domain')
        example: _id,fields.name,domain
        schema:
          type: string
      - name: limit
        in: query
        required: false
        description: 'Number of companies to retrieve. Default: 100. Maximum: 500'
        example: '10'
        schema:
          type: integer
          minimum: 1
          maximum: 500
          default: 100
      - name: crmSyncStatus
        in: query
        required: false
        description: 'Filter companies by their CRM sync state against the team''s active CRM provider.
          Requires a CRM (Hubspot, Salesforce, or Pipedrive) to be connected — otherwise the request returns
          `400 NO_CRM_CONNECTED`. Common values:

          - `synced` — the company has a CRM record and no sync errors.

          - `not_synced` — the company has no CRM record yet.

          - `error` — at least one sync error is currently raised.

          - A specific error reason (lowercase form), to filter by root cause: `unique_index_error_company`,
          `property_doesnt_exist`, `required_field_missing`, `company_already_exists_with_name`, `company_already_exists_with_linkedin_url`.


          For each returned company, see `crmSync.errors[].metadata.alreadyExistingCompanyId` to identify
          the lemlist company that already occupies the conflicting CRM record (useful to remap contacts
          before deleting the duplicate).'
        example: unique_index_error_company
        schema:
          type: string
          enum:
          - synced
          - not_synced
          - error
          - unique_index_error_company
          - property_doesnt_exist
          - required_field_missing
          - company_already_exists_with_name
          - company_already_exists_with_linkedin_url
      - name: fieldRejectionReason
        in: query
        required: false
        description: 'Filter companies to those carrying a field rejection with this reason — a value
          lemlist refused to write, raised during CRM sync (`crm_sync_*`). Returns an empty list (`total:
          0`) when no company matches. Each returned company exposes the full detail under `fieldRejections[]`
          (which field, why, and `conflictingRecordId` for duplicates). Independent of `crmSyncStatus`
          (which keys off the live provider errors); this filter reads the stored field rejections. Only
          applies to the paginated list — ignored when `idsOrDomains` is provided (that path returns the
          exact companies requested, unfiltered).'
        example: crm_sync_duplicate_company
        schema:
          type: string
          enum:
          - crm_sync_duplicate_company
          - crm_sync_invalid_domain
          - crm_sync_company_not_found
          - crm_sync_update_failed
          - crm_sync_duplicate_linkedin_url
          - crm_sync_invalid_linkedin_url
          - crm_sync_value_oscillating
          - crm_sync_owner_sync_loop
          - crm_sync_unmapped_user
          - crm_sync_value_incompatible
          - crm_sync_unknown_error
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Company'
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
                required:
                - data
                - total
                - limit
                - offset
              example:
                data:
                - _id: cpn_gG7PsmZFpEAnpMCHO
                  createdAt: '2025-10-26T11:54:27.387Z'
                  createdBy: usr_iGBmhLaxZmL0s7k1G
                  domain: persana.ai
                  fields:
                    name: Persana AI
                    picture: https://example.com/logos/company-1.png
                  ownerId: usr_iGBmhLaxZmL0s7k1G
                - _id: cpn_FEWCjzMWXo5StjpDa
                  createdAt: '2025-10-26T11:45:18.773Z'
                  createdBy: usr_iGBmhLaxZmL0s7k1G
                  domain: duno.ai
                  fields:
                    industry: IT Services and IT Consulting
                    name: Duno.ai
                    picture: https://example.com/logos/company-2.png
                  ownerId: usr_iGBmhLaxZmL0s7k1G
                - _id: cpn_2STz8x5Bexmd0nvIz
                  createdAt: '2025-10-25T21:37:45.741Z'
                  createdBy: usr_iGBmhLaxZmL0s7k1G
                  domain: tally.so
                  fields:
                    industry: Computer Software
                    name: lemlist family
                    picture: https://example.com/logos/lemlist.png
                  ownerId: usr_iGBmhLaxZmL0s7k1G
                - _id: cpn_Qf4CJuUrNUNmHm6uZ
                  createdAt: '2025-10-24T07:26:34.956Z'
                  createdBy: usr_ahfFktBBHUIxbVG5P
                  domain: example.com
                  fields:
                    name: Growth & GTM Engineering
                  ownerId: usr_ahfFktBBHUIxbVG5P
                - _id: cpn_A1B2C3D4E5F6G7H8I
                  createdAt: '2025-11-02T09:14:08.512Z'
                  createdBy: usr_A1B2C3D4E5F6G7H8I
                  domain: acme.com
                  fields:
                    name: Acme Inc
                  ownerId: usr_A1B2C3D4E5F6G7H8I
                  crmSync:
                    provider: hubspot
                    crmRecordId: null
                    syncDisabled: false
                    errors:
                    - type: CONNECT_FAILED
                      reason: UNIQUE_INDEX_ERROR_COMPANY
                      raisedAt: '2025-11-02T09:14:12.034Z'
                      metadata:
                        alreadyExistingCompanyId: cpn_J1K2L3M4N5O6P7Q8R
                total: 59310
                limit: 100
                offset: 0
        '400':
          description: Bad team
          content:
            text/plain:
              example: Bad team
        '401':
          description: The authentication you supplied is incorrect
          content:
            text/plain:
              example: The authentication you supplied is incorrect
        '405':
          description: Method not allowed
    post:
      summary: Add and update company
      description: Creates a new company or updates an existing one (upsert). If a company with the same
        domain, LinkedIn URL, or Sales Navigator URL already exists, it will be updated with the provided
        non-empty fields. Null or empty values are ignored during updates to preserve existing data. You
        can target an existing company directly by providing `companyId`, bypassing domain/LinkedIn matching
        — in that case `name` and `domain` become optional.
      tags:
      - Companies
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                companyId:
                  type: string
                  description: Existing company ID. Updates a specific company by ID, bypassing domain/LinkedIn
                    matching. Can only be used to update an existing company, not to create a new one.
                    When provided, `name` and `domain` become optional.
                name:
                  type: string
                  description: Company name. Required unless `companyId` is provided.
                domain:
                  type: string
                  description: Company website domain (e.g. `lemlist.com`). Used as a unique key for upsert
                    matching. Required unless `companyId` is provided.
                linkedinUrl:
                  type: string
                  description: LinkedIn company page URL. Used as an alternative unique key for upsert
                    matching.
                linkedinUrlSalesNav:
                  type: string
                  description: LinkedIn Sales Navigator company URL. Used as an alternative unique key
                    for upsert matching.
                companyOwner:
                  type: string
                  description: Owner of the company. 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 owner defaults
                    to the API key owner.
                industry:
                  type: string
                  description: Industry sector of the company.
                location:
                  type: string
                  description: Geographic location of the company.
                size:
                  type: string
                  description: Company size.
                specialties:
                  type: string
                  description: Company specialties.
                tagline:
                  type: string
                  description: Company tagline.
                type:
                  type: string
                  description: Company type.
                description:
                  type: string
                  description: Company description.
                foundedOn:
                  type: string
                  description: Company founding date.
                headquarters:
                  type: string
                  description: Company headquarters location.
                picture:
                  type: string
                  description: URL of the company logo or picture.
                source:
                  type: string
                  description: Origin of the company record. Set on creation only and cannot be updated
                    afterwards. Defaults to `api`.
                  default: api
              additionalProperties:
                description: Any additional key is treated as a custom field. Custom fields must be registered
                  in the team's CRM field registry beforehand.
            example:
              name: Acme Corp
              domain: acme.com
              linkedinUrl: https://linkedin.com/company/acme
              industry: Technology
              location: San Francisco, CA
      responses:
        '201':
          description: Company created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      _id:
                        type: string
                        description: Unique company identifier
                      teamId:
                        type: string
                        description: Team ID
                      domain:
                        type: string
                        description: Company domain
                      linkedinUrl:
                        type: string
                        description: LinkedIn URL
                      fields:
                        type: object
                        description: Key/value fields (name, picture, industry, location, custom fields,
                          etc.)
                        additionalProperties: true
                      ownerId:
                        type: string
                        description: Owner user ID
                      source:
                        type: string
                        description: Record origin
                      createdAt:
                        type: string
                        format: date-time
                        description: Creation timestamp
                      createdBy:
                        type: string
                        description: User ID who created the record
                      created:
                        type: boolean
                        description: '`true` when a new company was created, `false` when an existing
                          company was updated.'
                      updated:
                        type: boolean
                        description: Present and set to `true` only when an existing company was updated
                          (i.e. `created` is `false`).
                  warnings:
                    type: array
                    description: Optional warnings (e.g. owner resolution issues).
                    items:
                      type: object
                      properties:
                        code:
                          type: string
                        message:
                          type: string
              example:
                success: true
                data:
                  _id: cpn_gG7PsmZFpEAnpMCHO
                  teamId: tea_8QvkOiBfPdb2ZRhHi
                  domain: acme.com
                  linkedinUrl: https://www.linkedin.com/company/acme
                  fields:
                    name: Acme Corp
                    industry: Technology
                    location: San Francisco, CA
                  ownerId: usr_ahfFktBBHUIxbVG5P
                  source: api
                  createdAt: '2025-10-28T00:40:37.917Z'
                  createdBy: usr_ahfFktBBHUIxbVG5P
                  created: true
        '200':
          description: Existing company updated (upsert matched by domain or LinkedIn URL)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    description: 'Same shape as the 201 response, with `created: false` and `updated:
                      true`.'
              example:
                success: true
                data:
                  _id: cpn_gG7PsmZFpEAnpMCHO
                  teamId: tea_8QvkOiBfPdb2ZRhHi
                  domain: acme.com
                  fields:
                    name: Acme Corp
                    industry: Technology
                    location: San Francisco, CA
                  ownerId: usr_ahfFktBBHUIxbVG5P
                  source: api
                  createdAt: '2025-10-28T00:40:37.917Z'
                  createdBy: usr_ahfFktBBHUIxbVG5P
                  created: false
                  updated: true
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        description: 'Error code: `MISSING_REQUIRED_FIELD`, `INVALID_COMPANY_ID`, `COMPANY_NOT_FOUND_BY_ID`,
                          `INVALID_DOMAIN`, `INVALID_LINKEDIN_URL`, or `INVALID_FIELD`.'
                      message:
                        type: string
              example:
                success: false
                error:
                  code: MISSING_REQUIRED_FIELD
                  message: 'Missing required field: name'
        '401':
          description: The authentication you supplied is incorrect
          content:
            text/plain:
              example: The authentication you supplied is incorrect
      parameters: []
  /companies/{companyId}:
    delete:
      summary: Delete Company
      description: 'Deletes a lemlist company. Refuses by default when contacts are still attached — pass
        `force=true` to detach them (the `companyId` field is unset on each contact) before deleting the
        company.


        **No CRM-side propagation:** only the lemlist record is removed. Designed for the contact-to-company
        remapping workflow: after reassigning the contacts of a duplicate company to the canonical one
        (via `POST /contacts/{idOrEmail}`), call this endpoint to drop the now-empty duplicate.'
      tags:
      - Companies
      parameters:
      - name: companyId
        in: path
        required: true
        description: The lemlist company ID to delete.
        example: cpn_A1B2C3D4E5F6G7H8I
        schema:
          type: string
          pattern: ^cpn_[a-zA-Z0-9]+$
      - name: force
        in: query
        required: false
        description: When `true`, detaches contacts attached to this company (unsets their `companyId`)
          before deleting it. When omitted or `false`, the request fails with `400 COMPANY_HAS_CONTACTS`
          if any contact is still attached.
        example: 'true'
        schema:
          type: boolean
          default: false
      responses:
        '200':
          description: Company deleted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  deletedCompanyId:
                    type: string
                    description: ID of the deleted lemlist company.
                  unlinkedContacts:
                    type: integer
                    description: Number of contacts whose `companyId` was unset before deletion. Only
                      present when `force=true`.
                required:
                - success
                - deletedCompanyId
              examples:
                no contacts attached:
                  value:
                    success: true
                    deletedCompanyId: cpn_A1B2C3D4E5F6G7H8I
                force=true with attached contacts:
                  value:
                    success: true
                    deletedCompanyId: cpn_A1B2C3D4E5F6G7H8I
                    unlinkedContacts: 3
        '400':
          description: 'Invalid request. Possible error codes: `INVALID_COMPANY_ID` (malformed ID), `COMPANY_HAS_CONTACTS`
            (contacts still attached and `force` not set).'
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                      message:
                        type: string
                      contactCount:
                        type: integer
                        description: Only on `COMPANY_HAS_CONTACTS` — how many contacts are still attached.
              example:
                success: false
                error:
                  code: COMPANY_HAS_CONTACTS
                  message: Company still has contacts attached. Pass ?force=true to detach them before
                    deletion. (3 contacts attached)
                  contactCount: 3
        '401':
          description: The authentication you supplied is incorrect.
          content:
            text/plain:
              example: The authentication you supplied is incorrect
        '404':
          description: Company not found (`COMPANY_NOT_FOUND_BY_ID`).
          content:
            application/json:
              example:
                success: false
                error:
                  code: COMPANY_NOT_FOUND_BY_ID
                  message: Company not found by ID
        '405':
          description: Method not allowed.
  /companies/{companyId}/notes:
    get:
      summary: Get Company Notes
      tags:
      - Companies
      parameters:
      - name: limit
        in: query
        required: false
        description: 'Number of notes to retrieve. Default: 100. Maximum: 100'
        example: '2'
        schema:
          type: integer
      - name: page
        in: query
        required: false
        description: Page number to retrieve
        example: '1'
        schema:
          type: integer
      - name: sortBy
        in: query
        required: false
        description: The field by which to sort. Currently, only 'createdAt' is supported.
        example: createdAt
        schema:
          type: string
          enum:
          - createdAt
      - name: sortOrder
        in: query
        required: false
        description: The sort direction. Use 'desc' for descending order; any other value (or omission)
          will sort in ascending order.
        example: desc
        schema:
          type: string
          enum:
          - asc
          - desc
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CompanyNote'
                  total:
                    type: integer
                required:
                - data
                - total
              example:
                data:
                - _id: act_j0NrG6rYEPP9TMmWC
                  teamId: tea_8QvkOiBfPdb2ZRhHi
                  companyId: cpn_Qf4CJuUrNUNmHm6uZ
                  createdAt: '2025-10-28T04:25:00.653Z'
                  note: could help our GTM team be more productive
                  userId: usr_ahfFktBBHUIxbVG5P
                - _id: act_BYF2j06u0wgeLncub
                  teamId: tea_8QvkOiBfPdb2ZRhHi
                  companyId: cpn_Qf4CJuUrNUNmHm6uZ
                  createdAt: '2025-10-24T12:42:40.605Z'
                  note: Note created from the API!
                  userId: usr_ahfFktBBHUIxbVG5P
                total: 2
        '400':
          description: Bad team
          content:
            text/plain:
              example: Bad team
        '401':
          description: The authentication you supplied is incorrect
          content:
            text/plain:
              example: The authentication you supplied is incorrect
        '404':
          description: Company not found
          content:
            text/plain:
              example: Company not found
        '405':
          description: Method not allowed
    parameters:
    - name: companyId
      in: path
      required: true
      description: The unique identifier of the company
      example: cmp_ABC123
      schema:
        type: string
    post:
      summary: Create Company Note
      tags:
      - Companies
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                note:
                  type: string
                  description: The note content
              required:
              - note
            example:
              note: Note created from the API!
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyNote'
              example:
                _id: act_j0NrG6rYEPP9TMmWC
                teamId: tea_8QvkOiBfPdb2ZRhHi
                companyId: cpn_Qf4CJuUrNUNmHm6uZ
                type: annotated
                createdAt: '2025-10-28T04:25:00.653Z'
                note: could help our GTM team be more productive
                sendUserId: usr_ahfFktBBHUIxbVG5P
                userId: usr_ahfFktBBHUIxbVG5P
        '400':
          description: Bad team
          content:
            text/plain:
              example: Bad team
        '401':
          description: The authentication you supplied is incorrect
          content:
            text/plain:
              example: The authentication you supplied is incorrect
        '404':
          description: Company not found
          content:
            text/plain:
              example: Company not found
        '405':
          description: Method not allowed
      parameters: []
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
  schemas:
    Company:
      type: object
      description: An organization record in your CRM.
      properties:
        _id:
          type: string
          description: Unique company identifier
        name:
          type: string
          description: Company name (may also be present under fields.name)
        domain:
          type: string
          description: Website domain
        industry:
          type: string
          description: Industry sector
        size:
          type: string
          description: Company size
        location:
          type: string
          description: Geographic location
        fields:
          type: object
          description: Flexible key/value fields of the company (e.g., name, picture, industry, location,
            size, foundedOn)
          additionalProperties: true
        createdBy:
          type: string
          description: User ID who created the company
        ownerId:
          type: string
          description: User ID of the owner of the company
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp
        fieldRejections:
          type: array
          description: Values lemlist refused to write on this company, each with its reason. Empty when
            none. Filter the list endpoint to only flagged companies via `GET /companies?fieldRejectionReason=...`.
          items:
            $ref: '#/components/schemas/FieldRejection'
        crmSync:
          type: object
          nullable: true
          description: CRM sync status for the company, resolved against the team's active CRM provider
            (Hubspot, Salesforce, or Pipedrive). Only present when a CRM is connected. Use this block
            to monitor sync state and resolve duplicates (e.g. via `GET /companies?crmSyncStatus=unique_index_error_company`).
          properties:
            provider:
              type: string
              enum:
              - hubspot
              - salesforce
              - pipedrive
              description: Active CRM provider for the team.
            crmRecordId:
              type: string
              nullable: true
              description: Identifier of the company record on the CRM side. `null` when the lemlist company
                has not been synced yet.
            syncDisabled:
              type: boolean
              description: When `true`, automatic sync is paused for this company.
            errors:
              type: array
              description: List of recent sync errors. Empty when the company is synced cleanly.
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: Coarse error category (e.g. `CONNECT_FAILED`, `CREATE_FAILED`, `UPDATE_FAILED`).
                  reason:
                    type: string
                    description: Specific error reason. Matches the lowercase form accepted by the `crmSyncStatus`
                      query param (e.g. `UNIQUE_INDEX_ERROR_COMPANY`, `PROPERTY_DOESNT_EXIST`, `REQUIRED_FIELD_MISSING`).
                  raisedAt:
                    type: string
                    format: date-time
                    description: Timestamp when the error was last raised.
                  metadata:
                    type: object
                    additionalProperties: true
                    description: Extra context. For `UNIQUE_INDEX_ERROR_COMPANY`, contains `alreadyExistingCompanyId`
                      — the lemlist company that already occupies the conflicting CRM record. Use it to
                      remap contacts onto the right lemlist company before deleting the duplicate.
    CompanyNote:
      type: object
      description: A text note attached to a company record to store information.
      properties:
        _id:
          type: string
          description: Unique note identifier
        teamId:
          type: string
          description: Team ID that owns the company
        companyId:
          type: string
          description: Parent company ID
        note:
          type: string
          description: Note text content
        type:
          type: string
          description: Type of note or activity (e.g., 'annotated')
        userId:
          type: string
          description: ID of the user who created the note
        sendUserId:
          type: string
          description: ID of the sending user if applicable
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp
        updatedAt:
          type: string
          format: date-time
          description: Last update timestamp
    FieldRejection:
      type: object
      description: A value lemlist refused to write on a Contact or Company, with the reason why. Surfaced
        under `fieldRejections[]` on those objects; filter a list endpoint to only flagged records via
        the `fieldRejectionReason` query param.
      properties:
        field:
          type: string
          description: The record field the rejected value targeted (e.g. `emails`, `linkedinUrl`, `domain`).
        reason:
          type: string
          description: Why the value was rejected, prefixed by its origin — `enrichment_*` (raised while
            enriching) or `crm_sync_*` (raised during CRM sync). Same values accepted by the `fieldRejectionReason`
            query param.
        source:
          type: string
          description: Where the rejection came from — an enrichment source (`lemrich`) or a CRM provider
            (`hubspot`, `salesforce`, `pipedrive`).
        conflictingRecordId:
          type: string
          description: For duplicate reasons, the id of the record that already holds the value — use
            it to merge or remap before resolving the duplicate. Omitted for non-duplicate reasons.
        rejectedValue:
          type: string
          description: The value that was refused.
        rejectedAt:
          typ

# --- truncated at 32 KB (32 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/lemlist/refs/heads/main/openapi/lemlist-companies-api-openapi.yml