For AI agents: markdown of this page — /docs-content-en/duplicates.md documentation index — /llms.txt
Duplicate search
POST /v1/duplicates/find
Finds CRM leads, contacts, and companies whose phone number or email address matches the supplied values. Use it before creating a new record to avoid duplicates, when importing data from external sources, and when you need to find a record by phone number.
Bitrix24 API: crm.duplicate.findbycomm
Scope: crm
Request fields (body)
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | yes | Value type to search by: phone or email |
values |
array | yes | List of values to check — phone numbers or email addresses. Maximum 20 values per request |
entityType |
string | no | Restrict the search to a single type: lead, contact, or company. If omitted, the search covers all three types |
Examples
curl — personal key
curl -X POST https://vibecode.bitrix24.com/v1/duplicates/find \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "phone",
"values": ["+12025550123"]
}'
curl — OAuth application
curl -X POST https://vibecode.bitrix24.com/v1/duplicates/find \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "phone",
"values": ["+12025550123"]
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/duplicates/find', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'phone',
values: ['+12025550123'],
}),
})
const { success, data } = await res.json()
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/duplicates/find', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'phone',
values: ['+12025550123'],
}),
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | Always true on success |
data |
object | array | Matches found, grouped by entity type. Empty array [] when there are no matches |
data.lead |
array | IDs of leads with matching contact details. Full records: GET /v1/leads |
data.contact |
array | IDs of contacts with matching contact details. Full records: GET /v1/contacts |
data.company |
array | IDs of companies with matching contact details. Full records: GET /v1/companies |
Response example
Matches found — data contains one key per entity type:
{
"success": true,
"data": {
"lead": [105],
"contact": [42]
}
}
No matches — data comes back as an empty array:
{
"success": true,
"data": []
}
Error response example
400 — required parameters not supplied:
{
"success": false,
"error": {
"code": "MISSING_PARAMS",
"message": "Required: type (\"PHONE\" or \"EMAIL\"), values (string array, max 20)"
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 400 | MISSING_PARAMS |
type or values not supplied, or values is an empty array |
| 400 | TOO_MANY_VALUES |
More than 20 values in values |
| 422 | BITRIX_ERROR |
Invalid type — the error text is returned in the message field |
| 403 | SCOPE_DENIED |
The key lacks the crm scope |
| 401 | TOKEN_MISSING |
The key has no access tokens configured |
Full list of common API errors — Errors.
Known specifics
A number is matched in any format and against any of the numbers stored on the record. The values +1 (202) 555-0123, +12025550123, and 12025550123 all find the same record, no matter how the number is stored in the Bitrix24 account. If a contact has both a work and a mobile phone, the method finds it by either of them. That is why you look up a record by number with this method rather than with the filter.phone filter in list or search requests: that filter compares the string against the stored value in full and sees only the record's first number — Filter by phone and email. Pass the number in full: without the country code it is not recognized.
The data type depends on the result. When there are matches, it is an object keyed by entity type. When there are none, it is an empty array []. Check the type before processing — Array.isArray(data) means no matches were found.
A single value can match several types at once. If a phone number or email address exists on both a lead and a contact, the response includes both keys with their own IDs. Without entityType, check every returned group, not just the first.