Skip to content

Deduplication

Every POST /leads request runs automatic duplicate detection before inserting. This prevents polluting your database with duplicate entries from different sources.

PriorityCriterionConfidenceAction
1email match (case-insensitive)HighMerge into existing
2source_id exact matchHighMerge into existing
3phone match + name similarity > 80%MediumMerge into existing (similarity uses normalized string comparison — “Acme Corp” and “ACME Corporation” may not match)
4name + city match (case-insensitive)LowCreate new, flag with potential_duplicate_id

When a duplicate is detected at priority 1–3:

  • Non-empty fields from the incoming request overwrite the existing lead.
  • Fields not present in the request are left unchanged.
  • last_interaction_at is always bumped — even if no field changed.

This models “freshness of interest”: every new push from a source registers as a new interaction.

{
"id": "cl_existing...",
"message": "Duplicate detected, existing lead updated",
"created_at": 1703520000,
"duplicate": true
}

HTTP status is 200 OK (not 201) on a merge.

On a name+city match only, a new lead is created but the response includes a hint:

{
"id": "cl_new...",
"potential_duplicate_id": "cl_similar...",
"message": "Lead created successfully"
}

You can review these in the dashboard: navigate to Leads, search for the potential_duplicate_id, and manually merge or dismiss.

FieldUpdates when
updated_atA structural field is modified (name, email, city, etc.)
last_interaction_atAny push arrives — including merges with no field changes

Use sort_by=last_interaction_at&sort_order=DESC to find the leads with the most recent activity, independent of data changes.