Live Direct Marketing Contacts API

The Contacts API from Live Direct Marketing — 19 operation(s) for contacts.

Business capability
Customer Data Management BC-420.10

Operations 24

Each operation below carries the questions people ask an LLM about it and the instructions they give an agent to run it. Generated by API Evangelist overlay

GET /api/contacts/stats Get contact statistics · Get contact statistics, optionally scoped to a list #
Ask an LLM
“How many contacts do I have, and can I break the stats down for one list?”
“What contact statistics does Live Direct Marketing report for my workspace?”
Tell an agent
Show contact statistics for list {listId}.
Give me overall contact stats for my workspace.
GET /api/contacts/duplicates Find duplicate contacts across the workspace · Find duplicate contacts across the workspace #
Ask an LLM
“Which contacts across my whole workspace look like duplicates?”
“Can I look for duplicate contacts by a specific field rather than email only?”
Tell an agent
Find duplicate contacts across the workspace by {field}.
Scan my workspace for duplicate contacts.
GET /api/contacts List and search contacts · List contacts with pagination, search, and filters #
Ask an LLM
“Can I search my contacts and filter them by list, company or email validation status?”
“Which contacts have role-based or disposable email addresses?”
Tell an agent
Search contacts for {search}, page {page} with {pageSize} per page.
List contacts in list {listId}.
POST /api/contacts Create a new contact · Create a new contact. #
Ask an LLM
“How do I add a new person to my contacts?”
“Can I set a contact's position, department and company when creating them?”
Tell an agent
Create a contact named {firstName} {lastName}.
Add a new contact {firstName} working as {position} at company {companyId}.
GET /api/contacts/{id} Get a contact's details · Get a single contact by ID #
Ask an LLM
“What details are stored for a particular contact?”
“Can I look up one contact record by its id?”
Tell an agent
Get contact {id}.
Show me the full record for contact {id}.
PATCH /api/contacts/{id} Update a contact's details · Update an existing contact #
Ask an LLM
“Can I change the name, job title or company on an existing contact?”
“What fields of a contact can I edit after it is created?”
Tell an agent
Update contact {id} to job title {position}.
Change contact {id}'s company to {companyId}.
DELETE /api/contacts/{id} Move a contact to the trash · Soft-delete a contact #
Ask an LLM
“Can I delete a contact but still be able to restore it later?”
“What does soft-deleting a contact do?”
Tell an agent destructive · confirm first
Soft-delete contact {id}.
Move contact {id} to the trash.
GET /api/contacts/{id}/timeline Get a contact's activity timeline · Get a paginated timeline of events for a contact #
Ask an LLM
“What has happened with a contact over time, event by event?”
“Can I page through the history of interactions for one person?”
Tell an agent
Show the timeline for contact {id}.
Get page {page} of contact {id}'s event history.
POST /api/contacts/bulk Run a bulk action on many contacts · Bulk action on contacts (async, BullMQ). #
Ask an LLM
“Can I add tags or move a whole filtered set of contacts to a list in one go?”
“Is there a way to update one field on hundreds of contacts at once?”
Tell an agent
Run bulk action {action} on contacts {contactIds}.
Add all contacts matching {search} to list {listId}.
GET /api/contacts/bulk/{jobId} Check a bulk contact job's progress · Get the status of a bulk contact job #
Ask an LLM
“Has my bulk contact action finished yet?”
“What is the progress of a background bulk job on contacts?”
Tell an agent
Get the status of bulk contact job {jobId}.
Check progress on contact bulk job {jobId}.
DELETE /api/contacts/bulk/{jobId} Cancel a running bulk contact job · Cancel an in-progress bulk contact job #
Ask an LLM
“Can I stop a bulk contact action that is still in progress?”
“What if I started a bulk delete on contacts by mistake; can I cancel it?”
Tell an agent destructive · confirm first
Cancel bulk contact job {jobId}.
Stop the in-progress contact bulk job {jobId}.
POST /api/contacts/export Export contacts to a file · Export contacts to a downloadable file #
Ask an LLM
“Can I export my contacts to CSV or Excel, including custom fields?”
“Which contacts can I choose to export, a list or a search?”
Tell an agent
Export contacts in list {listId} as {format}.
Export contacts with scope {scope} including custom fields {includeCustomFields}.
POST /api/contacts/import/preview Preview a contacts import mapping · Preview a contacts import with proposed mapping #
Ask an LLM
“Before importing a spreadsheet of contacts, can I see how the columns will be mapped?”
“Can I dry-run a contact import to check the field mapping?”
Tell an agent
Preview importing these contact rows {rows} with mapping {mapping}.
Show how {rows} would map into contacts using {mapping}.
POST /api/contacts/import/start Start a contacts import job · Start a contacts import job #
Ask an LLM
“How do I actually start importing a batch of contacts once the mapping looks right?”
“Can I pass import options when kicking off a contact import?”
Tell an agent
Start importing contact rows {rows} with mapping {mapping}.
Import contacts {rows} using mapping {mapping} and options {options}.
POST /api/contacts/{id}/restore Restore a contact from the trash · Restore a soft-deleted contact #
Ask an LLM
“Can I bring back a contact I soft-deleted?”
“Is there an undo for deleting a contact?”
Tell an agent
Restore contact {id} from the trash.
Undelete contact {id}.
DELETE /api/contacts/{id}/purge Permanently delete a trashed contact · PERMANENTLY delete a trashed contact (requires isDeleted). Irreversible #
Ask an LLM
“Can I permanently erase a contact that is already in the trash?”
“Is purging a contact reversible?”
Tell an agent destructive · confirm first
Permanently purge trashed contact {id}.
Erase contact {id} for good from the trash.
POST /api/contacts/merge Merge duplicate contacts into one · Merge multiple contacts into one keeper record #
Ask an LLM
“Can I combine several duplicate contacts into a single record?”
“Which record survives when I merge contacts?”
Tell an agent
Merge contacts {mergeIds} into contact {keepId}.
Keep contact {keepId} and fold {mergeIds} into it.
POST /api/contacts/{id}/dig Run DIG email enrichment on a contact · Manually trigger DIG email enrichment for a contact #
Ask an LLM
“Can I re-check a contact's email domain for MX, SPF and DMARC on demand?”
“How do I trigger DIG enrichment manually for one person?”
Tell an agent
Run DIG email enrichment on contact {id}.
Trigger a DIG check for contact {id}.
GET /api/contacts/{id}/duplicates Check one contact for duplicates · Check for duplicates of a specific contact #
Ask an LLM
“Does this specific contact have any duplicates in my workspace?”
“Can I find records that look like copies of one particular contact?”
Tell an agent
Check contact {id} for duplicates.
Find possible duplicates of contact {id}.
POST /api/contacts/{id}/channels Add an email or phone channel to a contact · Add a communication channel to a contact #
Ask an LLM
“How do I attach an email address or phone number to a contact?”
“Can I mark a newly added channel as the contact's primary one?”
Tell an agent
Add a {type} channel {value} to contact {id}.
Attach {value} as the primary {type} for contact {id}.
PATCH /api/contacts/{contactId}/channels/{channelId} Update a contact's email or phone channel · Update a contact channel #
Ask an LLM
“Can I change the value or validation status of a contact's existing email channel?”
“Is it possible to switch which channel is primary for a contact?”
Tell an agent
Update channel {channelId} on contact {contactId} to {value}.
Make channel {channelId} primary for contact {contactId}.
DELETE /api/contacts/{contactId}/channels/{channelId} Remove a channel from a contact · Delete a contact channel #
Ask an LLM
“Can I remove an old email address or phone number from a contact?”
“What happens when I delete one of a contact's channels?”
Tell an agent destructive · confirm first
Delete channel {channelId} from contact {contactId}.
Remove contact {contactId}'s channel {channelId}.
DELETE /api/contacts/import/rollback/{batchId} Roll back a contact import batch · Roll back a contact import batch by ID #
Ask an LLM
“I imported the wrong file; can I undo that whole contact import?”
“Can I remove every contact that came from one import batch?”
Tell an agent destructive · confirm first
Roll back contact import batch {batchId}.
Undo the contacts imported in batch {batchId}.
GET /api/contacts/duplicates/by-email Find contacts sharing the same email · Find contacts that share duplicate email addresses #
Ask an LLM
“Which contacts share the exact same email address?”
“Can I list duplicate contacts grouped by email?”
Tell an agent
Find contacts that share duplicate email addresses.
List contacts with the same email address.

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/live-direct-marketing-online:live-direct-marketing-online-contacts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

live-direct-marketing-online-contacts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: LDM v3 Contacts API
  description: 'Multi-tenant B2B outreach automation platform. Auth: JWT Bearer (15-min) or tenant API key (ldm_*) managed in CRM Settings → API Keys. All tenant-scoped endpoints require the X-Tenant-Id header.'
  version: 1.0.0
  contact: {}
servers:
- url: https://api.live-direct-marketing.online
  description: Production
- url: https://api.dev.live-direct-marketing.online
  description: Development
- url: http://127.0.0.1:3000
  description: Local
tags:
- name: Contacts
paths:
  /api/contacts/stats:
    get:
      operationId: ContactsController_getStats
      parameters:
      - name: listId
        required: false
        in: query
        description: Restrict stats to a single list
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Get contact statistics, optionally scoped to a list
      tags:
      - Contacts
      x-required-scope:
      - crm:read
  /api/contacts/duplicates:
    get:
      operationId: ContactsController_findAllDuplicates
      parameters:
      - name: field
        required: false
        in: query
        description: Which field to detect duplicates by
        schema:
          enum:
          - email
          - name
          - all
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Find duplicate contacts across the workspace
      tags:
      - Contacts
      x-required-scope:
      - crm:read
  /api/contacts:
    get:
      operationId: ContactsController_findAll
      parameters:
      - name: page
        required: false
        in: query
        description: 1-based page number
        schema:
          example: 1
          type: number
      - name: pageSize
        required: false
        in: query
        description: Items per page (default 25)
        schema:
          example: 25
          type: number
      - name: search
        required: false
        in: query
        description: Full-text search across name/position/channels
        schema:
          type: string
      - name: companyId
        required: false
        in: query
        description: Filter to contacts of a single company
        schema:
          type: string
      - name: listId
        required: false
        in: query
        description: Filter to contacts in a single list
        schema:
          type: string
      - name: sortBy
        required: false
        in: query
        description: Sort column
        schema:
          type: string
      - name: sortDir
        required: false
        in: query
        description: Sort direction
        schema:
          enum:
          - asc
          - desc
          type: string
      - name: sort
        required: false
        in: query
        description: Combined sort token (alternative to sortBy/sortDir)
        schema:
          type: string
      - name: digProvider
        required: false
        in: query
        description: 'DIG: filter by MX provider (e.g. google, yandex)'
        schema:
          type: string
      - name: digDomainType
        required: false
        in: query
        description: 'DIG: filter by domain type'
        schema:
          type: string
      - name: digHasMx
        required: false
        in: query
        description: 'DIG: has MX records (true/false)'
        schema:
          type: string
      - name: digHasSpf
        required: false
        in: query
        description: 'DIG: has SPF record (true/false)'
        schema:
          type: string
      - name: digHasDmarc
        required: false
        in: query
        description: 'DIG: has DMARC record (true/false)'
        schema:
          type: string
      - name: digIsRoleBased
        required: false
        in: query
        description: 'DIG: role-based mailbox (true/false)'
        schema:
          type: string
      - name: digIsDisposable
        required: false
        in: query
        description: 'DIG: disposable address (true/false)'
        schema:
          type: string
      - name: digIsSuspicious
        required: false
        in: query
        description: 'DIG: suspicious heuristics (true/false)'
        schema:
          type: string
      - name: digAnalyzed
        required: false
        in: query
        description: 'DIG: enrichment completed (true/false)'
        schema:
          type: string
      - name: emailValidStatus
        required: false
        in: query
        description: Filter by email validation status
        schema:
          type: string
      - name: taskId
        required: false
        in: query
        description: Filter to contacts attached to a task
        schema:
          type: string
      - name: includeDeleted
        required: true
        in: query
        schema:
          type: string
      - name: onlyDeleted
        required: true
        in: query
        schema:
          type: string
      - name: filters
        required: true
        in: query
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: List contacts with pagination, search, and filters
      tags:
      - Contacts
    post:
      operationId: ContactsController_create
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateContactDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Create a new contact.
      tags:
      - Contacts
  /api/contacts/{id}:
    get:
      operationId: ContactsController_findById
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Get a single contact by ID
      tags:
      - Contacts
    patch:
      operationId: ContactsController_update
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateContactDto'
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Update an existing contact
      tags:
      - Contacts
    delete:
      operationId: ContactsController_softDelete
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Soft-delete a contact
      tags:
      - Contacts
  /api/contacts/{id}/timeline:
    get:
      operationId: ContactsController_getTimeline
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: page
        required: false
        in: query
        description: 1-based page number
        schema:
          example: 1
          type: number
      - name: pageSize
        required: false
        in: query
        description: Items per page (default 20)
        schema:
          example: 20
          type: number
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Get a paginated timeline of events for a contact
      tags:
      - Contacts
  /api/contacts/bulk:
    post:
      operationId: ContactsController_bulk
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactsBulkDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Bulk action on contacts (async, BullMQ).
      tags:
      - Contacts
      x-required-scope:
      - crm:write
  /api/contacts/bulk/{jobId}:
    get:
      operationId: ContactsController_getBulkStatus
      parameters:
      - name: jobId
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Get the status of a bulk contact job
      tags:
      - Contacts
    delete:
      operationId: ContactsController_cancelBulk
      parameters:
      - name: jobId
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Cancel an in-progress bulk contact job
      tags:
      - Contacts
  /api/contacts/export:
    post:
      operationId: ContactsController_exportContacts
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExportContactsDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Export contacts to a downloadable file
      tags:
      - Contacts
      x-required-scope:
      - crm:write
  /api/contacts/import/preview:
    post:
      operationId: ContactsController_importPreview
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactsImportPreviewDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Preview a contacts import with proposed mapping
      tags:
      - Contacts
      x-required-scope:
      - crm:write
  /api/contacts/import/start:
    post:
      operationId: ContactsController_importStart
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactsImportStartDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Start a contacts import job
      tags:
      - Contacts
      x-required-scope:
      - crm:write
  /api/contacts/{id}/restore:
    post:
      operationId: ContactsController_restore
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Restore a soft-deleted contact
      tags:
      - Contacts
  /api/contacts/{id}/purge:
    delete:
      operationId: ContactsController_purge
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: PERMANENTLY delete a trashed contact (requires isDeleted). Irreversible
      tags:
      - Contacts
  /api/contacts/merge:
    post:
      operationId: ContactsController_mergeContacts
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MergeContactsDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Merge multiple contacts into one keeper record
      tags:
      - Contacts
      x-required-scope:
      - crm:write
  /api/contacts/{id}/dig:
    post:
      operationId: ContactsController_triggerDig
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Manually trigger DIG email enrichment for a contact
      tags:
      - Contacts
  /api/contacts/{id}/duplicates:
    get:
      operationId: ContactsController_checkDuplicates
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Check for duplicates of a specific contact
      tags:
      - Contacts
  /api/contacts/{id}/channels:
    post:
      operationId: ContactsController_addChannel
      parameters:
      - name: id
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddChannelDto'
      responses:
        '201':
          description: ''
      security:
      - jwt: []
      summary: Add a communication channel to a contact
      tags:
      - Contacts
  /api/contacts/{contactId}/channels/{channelId}:
    patch:
      operationId: ContactsController_updateChannel
      parameters:
      - name: contactId
        required: true
        in: path
        schema:
          type: string
      - name: channelId
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateChannelDto'
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Update a contact channel
      tags:
      - Contacts
    delete:
      operationId: ContactsController_deleteChannel
      parameters:
      - name: contactId
        required: true
        in: path
        schema:
          type: string
      - name: channelId
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Delete a contact channel
      tags:
      - Contacts
  /api/contacts/import/rollback/{batchId}:
    delete:
      operationId: ContactsController_rollbackImport
      parameters:
      - name: batchId
        required: true
        in: path
        schema:
          type: string
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Roll back a contact import batch by ID
      tags:
      - Contacts
  /api/contacts/duplicates/by-email:
    get:
      operationId: ContactsController_findDuplicates
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          type: string
          format: uuid
        description: Tenant UUID — required for all tenant-scoped endpoints
      responses:
        '200':
          description: ''
      security:
      - jwt: []
      summary: Find contacts that share duplicate email addresses
      tags:
      - Contacts
      x-required-scope:
      - crm:read
components:
  schemas:
    UpdateContactDto:
      type: object
      properties:
        firstName:
          type: string
          maxLength: 100
        lastName:
          type: string
          maxLength: 100
        middleName:
          type: string
          maxLength: 100
        gender:
          type: string
          enum:
          - male
          - female
          - unknown
        position:
          type: string
        department:
          type: string
        companyId:
          type: string
        source:
          type: string
        contactType:
          type: string
          enum:
          - PERSONAL
          - COMPANY
    UpdateChannelDto:
      type: object
      properties:
        value:
          type: string
        label:
          type: string
        isPrimary:
          type: boolean
        status:
          type: string
          enum:
          - ACTIVE
          - BOUNCED
          - OPTED_OUT
          - INVALID
          - STOP_ALL
          - CHECKING
        emailValidStatus:
          type: string
          enum:
          - UNKNOWN
          - VALID
          - INVALID
          - CATCH_ALL
          - DISPOSABLE
          - ROLE
          - SPAM_TRAP
          - HARD_BOUNCE
          - UNSUBSCRIBED
    MergeContactsDto:
      type: object
      properties:
        keepId:
          type: string
          description: Id of the contact record to keep
        mergeIds:
          description: Ids of the contacts to merge into keepId and delete
          type: array
          items:
            type: string
      required:
      - keepId
      - mergeIds
    ContactsBulkDto:
      type: object
      properties:
        action:
          type: string
          description: Bulk action name (delete, addTags, removeTags, addToList, removeFromList, updateField)
        contactIds:
          description: Contact ids to act on
          type: array
          items:
            type: string
        ids:
          description: Alias for contactIds
          type: array
          items:
            type: string
        selectAll:
          type: boolean
          description: Resolve target ids server-side from the current filter instead of contactIds/ids
        search:
          type: string
          description: Search term used when selectAll is true
        listId:
          type: string
          description: Target list id for addToList/removeFromList; also the fallback selectAll filter list
        filterListId:
          type: string
          description: Source filter list id when selectAll is true (listId is reserved for the addToList/removeFromList target)
        tagIds:
          description: Tag ids for addTags/removeTags actions
          type: array
          items:
            type: string
        companyId:
          type: string
          description: Company id for a company-scoped action
        fieldName:
          type: string
          description: Field name for an updateField-style action
        fieldValue:
          type: object
          description: Field value for an updateField-style action (shape depends on fieldName)
        digProvider:
          type: string
          description: 'DIG selectAll filter: enrichment provider'
        digDomainType:
          type: string
          description: 'DIG selectAll filter: domain type'
        digHasMx:
          type: string
          description: 'DIG selectAll filter: has MX ("true"/"false")'
        digHasSpf:
          type: string
          description: 'DIG selectAll filter: has SPF ("true"/"false")'
        digHasDmarc:
          type: string
          description: 'DIG selectAll filter: has DMARC ("true"/"false")'
        digIsRoleBased:
          type: string
          description: 'DIG selectAll filter: role-based mailbox ("true"/"false")'
        digIsDisposable:
          type: string
          description: 'DIG selectAll filter: disposable domain ("true"/"false")'
        digIsSuspicious:
          type: string
          description: 'DIG selectAll filter: suspicious ("true"/"false")'
        digAnalyzed:
          type: string
          description: 'DIG selectAll filter: already analyzed ("true"/"false")'
        emailValidStatus:
          type: string
          description: 'DIG selectAll filter: email validation status'
      required:
      - action
    CreateContactDto:
      type: object
      properties:
        firstName:
          type: string
          maxLength: 100
        lastName:
          type: string
          maxLength: 100
        middleName:
          type: string
          maxLength: 100
        gender:
          type: string
          enum:
          - male
          - female
          - unknown
        position:
          type: string
        department:
          type: string
        companyId:
          type: string
        source:
          type: string
        contactType:
          type: string
          enum:
          - PERSONAL
          - COMPANY
        importBatchId:
          type: string
          description: '[LEGACY] import_task_id for import rollback'
      required:
      - firstName
    ExportContactsDto:
      type: object
      properties:
        scope:
          type: string
          description: Which contacts to export
          enum:
          - all
          - filtered
          - selected
          - list
        contactIds:
          description: Contact ids to export when scope is "selected"
          type: array
          items:
            type: string
        listId:
          type: string
          description: Restrict export to contacts in this list
        search:
          type: string
          description: Search term applied when scope is "filtered"
        format:
          type: string
          description: Export file format (e.g. csv, xlsx)
        includeCustomFields:
          type: boolean
          description: Include tenant custom field columns
      required:
      - scope
    ContactsImportPreviewDto:
      type: object
      properties:
        rows:
          description: Raw rows parsed from the source file/sheet
          type: array
          items:
            type: object
        mapping:
          type: object
          description: Column -> field mapping (csvColumn -> target field)
      required:
      - rows
      - mapping
    ContactsImportStartDto:
      type: object
      properties:
        rows:
          description: Raw rows parsed from the source file/sheet
          type: array
          items:
            type: object
        mapping:
          type: object
          description: Column -> field mapping (csvColumn -> target field)
        options:
          type: object
          description: 'duplicateHandling: "skip"|"update"|"create" (default skip); listId; tagIds'
      required:
      - rows
      - mapping
    AddChannelDto:
      type: object
      properties:
        type:
          type: string
          enum:
          - EMAIL
          - PHONE
          - LINKEDIN
          - TELEGRAM
          - VK
          - WHATSAPP
          - WEBSITE
          - SKYPE
          - OTHER
          example: EMAIL
          description: Channel type — UPPERCASE enum. Use field name "type", NOT "kind".
        value:
          type: string
          example: anna@acme.com
          description: Channel value — email address, phone number, URL, etc.
        label:
          type: string
          example: work
        isPrimary:
          type: boolean
          example: false
          description: Set as primary channel of this type for the contact.
      required:
      - type
      - value
  securitySchemes:
    jwt:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: JWT access token from /auth/login (Bearer <token>)
    tenant-api-key:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Tenant API key (Bearer ldm_*) for MCP/A2A clients. Issued via CRM Settings → API Keys.
    rpa-service:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Dedicated RPA service key. No tenant API-key or query-key authentication.