# Duplicate check before the import: who's already in your CRM?

Before new contacts reach the CRM, ListPlus looks up every row in your HubSpot – contacts by email, companies by domain – and writes Yes or No into a column. Your agent fetches the new ones as JSON or hands over only them; existing contacts stay untouched. HubSpot today.

https://listplus.ai/en/gtm-workflows/crm-duplicate-check-before-import

## Inputs and connections

Contacts with an email address (companies with a domain), a connected HubSpot account in the workspace and a list shared with your connection (Edit). For the column the connection needs the Set up right.

A HubSpot account in the workspace (Pro, or on Basic as your one tool), the list shared with Edit and the Set up right for the column.

## Steps

1. **Rows into the list** (Your agent · by call). add_records puts the contacts into the shared list. Duplicate rows inside the file are caught on the way in.
2. **Add the HubSpot column** (Your agent · by call). add_column with kind “hubspot” – contacts by email, companies by domain. The column looks up every row in your HubSpot and writes Yes or No.
3. **New rows are looked up too** (ListPlus · runs automatically). Whatever enters the list later is looked up as well – within the list's daily budget. After an export the column asks again for the rows it handed over.
4. **Fetch only the new ones** (Your agent · by call). query_records with the filter “In HubSpot” = “No” returns the new contacts as JSON – for your stack, or send_to_pipeline hands only them to your CRM pipeline.
5. **Or export in the app** (Your team · manual in ListPlus). Export to HubSpot with “only create new ones”: existing contacts stay unchanged, and companies are found by domain before a new one is created.

## Expected sample result

Of 24 trade show leads HubSpot already has 9; the 15 new ones come back as JSON. After the export the column asks again for the rows it handed over – now all 24 say Yes, without a single duplicate in the CRM.

## Costs and boundaries

The column asks HubSpot in bundles: 1 credits per request, one request checks up to 100 rows – 500 contacts cost 5 credits ($0.18 on Pro). List, column and query cost nothing else; a pipeline handoff is charged per record.

Matching is by email or domain – a person with a different address in HubSpot is not recognised. Rows without an email count as “not in HubSpot”. Other CRMs don't work this way yet.

## Agent prompt

Put my trade show leads (CSV) into the list “Trade show November”. Add a HubSpot column “In HubSpot” for contacts by email. Then give me every row with “No” as JSON (name, company, email) and tell me how many HubSpot already has. Don't write anything to HubSpot.

## Tools

`add_records`, `describe_setup`, `add_column`, `query_records`, `send_to_pipeline`

MCP: https://listplus.ai/mcp
REST: https://listplus.ai/a/v1/{action}
API: https://listplus.ai/a

## Sample calls

These calls use fictional IDs. Use the IDs returned by your workspace.

```text
add_records({
  "list_id": "<shared_list_id>",
  "records": [
    {
      "first_name": "Markus",
      "last_name": "Brandt",
      "email": "markus.brandt@nordwind-logistik.de",
      "company_name": "Nordwind Logistik"
    }
  ]
})
add_column({
  "list_id": "<shared_list_id>",
  "columns": [
    {
      "kind": "hubspot",
      "title": "In HubSpot",
      "object": "contacts",
      "account_id": "<hubspot_account_id>"
    }
  ]
})
query_records({
  "list_id": "<shared_list_id>",
  "filter": {
    "In HubSpot": "No"
  },
  "columns": [
    "first_name",
    "last_name",
    "company_name",
    "email"
  ]
})
```
