Дубли контактов — главная боль любой CRM-интеграции: одна и та же заявка приходит с сайта, из мессенджера и по телефону, и без контроля в базе появляются три карточки одного клиента. REST-методы crm.contact.* и crm.duplicate.findbycomm позволяют проверить наличие клиента ещё до создания записи.
Модель данных контакта
Контакт (crm.contact) описывает физлицо. Ключевая особенность модели — множественные коммуникационные поля: телефон, e-mail, мессенджеры и веб-адреса хранятся массивами, где у каждого значения есть тип.
POST /rest/1/xxxxxxxx/crm.contact.add.json
{
"fields": {
"NAME": "Иван",
"LAST_NAME": "Петров",
"PHONE": [ { "VALUE": "+79001234567", "VALUE_TYPE": "WORK" } ],
"EMAIL": [ { "VALUE": "ivan@example.com", "VALUE_TYPE": "WORK" } ]
},
"params": { "REGISTER_SONET_EVENT": "Y" }
}Полный список полей и допустимых типов значений вернёт crm.contact.fields. Обратите внимание: попытка передать телефон строкой, а не массивом объектов, приведёт к его потере.
Поиск дублей: crm.duplicate.findbycomm
Штатный способ найти существующий контакт по телефону или почте — метод crm.duplicate.findbycomm. Он ищет по нормализованным коммуникациям и возвращает идентификаторы совпадений.
POST /rest/1/xxxxxxxx/crm.duplicate.findbycomm.json
{
"type": "PHONE",
"values": [ "+79001234567" ],
"entity_type": "CONTACT"
}Ответ выглядит так:
{ "result": { "CONTACT": [ 145, 302 ] } }| Параметр | Назначение |
|---|---|
type | PHONE или EMAIL |
values | массив значений для поиска |
entity_type | CONTACT, COMPANY или LEAD |
+7 (900) 123-45-67 и 89001234567 будут распознаны как одно значение. Не нужно чистить номер вручную.Сценарий upsert без дублей
Правильный порядок действий при приёме заявки — «проверить, потом создать или обновить». Псевдологика интеграции:
- Нормализовать входящие телефон и e-mail;
- Вызвать
crm.duplicate.findbycommпо телефону, затем по e-mail; - Если найдены ID — взять первый и обновить контакт через
crm.contact.update; - Если совпадений нет — создать контакт через
crm.contact.add; - Привязать контакт к сделке через
crm.deal.contact.add.
Такой upsert исключает гонку данных, когда одна заявка успевает создать карточку, а вторая — её дубликат. Для нагрузочных сценариев оборачивайте цепочку в batch, но помните: findbycomm внутри батча выполняется на состоянии до текущих операций, поэтому проверку дубля лучше делать отдельным вызовом.
Встроенный контроль дублей
Помимо ручного поиска, у Битрикс24 есть встроенный механизм контроля дублей. При создании через add можно управлять его поведением параметром params:
"params": { "DUPLICATE_CONTROL": { "ENABLE": "Y" } }— включить проверку на стороне сервера;- если совпадение найдено, запрос вернёт ошибку с кодом, а не создаст запись.
Для массового слияния уже накопленных дублей используются интерфейсные инструменты «Обработка дубликатов», а из REST доступны низкоуровневые методы работы со списком коммуникаций. На практике для интеграций надёжнее полагаться на явный findbycomm перед записью — так вы контролируете логику выбора «главной» карточки.
Выборка и фильтрация контактов
Метод crm.contact.list поддерживает фильтры, сортировку и постраничность шагом 50 записей. Фильтрация по телефону выполняется по служебному полю PHONE с оператором вхождения:
POST /rest/1/xxxxxxxx/crm.contact.list.json
{
"filter": { "%PHONE": "9001234567" },
"select": ["ID", "NAME", "LAST_NAME", "PHONE", "EMAIL"],
"order": { "DATE_CREATE": "DESC" }
}%PHONE ищет по подстроке и не нормализует номер так же аккуратно, как findbycomm. Для точечного поиска дубля предпочитайте crm.duplicate.findbycomm, а list используйте для выборок и отчётов.Для перебора всей базы используйте параметр start; при больших объёмах эффективнее «быстрый» обход с "start": -1 и фильтром по возрастанию ID.
Частые ошибки и как их избежать
| Ошибка | Последствие | Как правильно |
|---|---|---|
| Телефон передан строкой | Значение не сохраняется | Массив объектов VALUE/VALUE_TYPE |
| Создание без findbycomm | Растут дубли | Проверка перед add |
| Поиск по %PHONE вместо findbycomm | Пропуск дубля из-за формата номера | findbycomm нормализует номер |
| Игнорирование e-mail при поиске | Дубль при смене телефона | Проверять оба канала |
Отдельно стоит следить за правами: методам дедупликации нужен доступ к области crm. Без него вебхук вернёт ошибку доступа ещё до выполнения поиска.
Ещё один тонкий момент — множественность коммуникаций при обновлении. Если вы передаёте в crm.contact.update поле PHONE целиком, старый набор номеров будет заменён на новый. Чтобы добавить телефон, не потеряв существующие, сначала прочитайте текущие значения через crm.contact.get, дополните массив и отправьте обратно полный список. У каждого элемента при этом сохраняется технический ID значения — передавая его, вы редактируете конкретный номер, а не создаёте дубль внутри карточки. Игнорирование этой механики — вторая по частоте причина «раздувания» контактов после ошибки с форматом номера.
Итог
Чистая база контактов начинается с дисциплины на входе. Множественные поля телефона и e-mail нужно передавать массивами, а перед каждым созданием карточки — прогонять значения через crm.duplicate.findbycomm, который сам нормализует номера и находит совпадения по контактам, компаниям и лидам. Схема upsert «проверил — обновил или создал» надёжнее любой постфактум-обработки дублей.
Мы выстраиваем такую логику в интеграциях сайта и Битрикс24: заявки с форм попадают в CRM без задвоений, а контакты корректно связываются со сделками. Если нужен отлаженный поток заявок без ручной чистки дублей — поможем спроектировать и внедрить обмен.
Частые вопросы
Чем findbycomm лучше фильтра list по телефону?
crm.duplicate.findbycomm нормализует номер и ищет по каналам коммуникации, поэтому находит дубль независимо от формата записи. Фильтр %PHONE ищет по подстроке и может пропустить совпадение.
Можно ли искать дубли сразу по нескольким номерам?
Да, параметр values принимает массив значений. Метод вернёт объединённый список найденных идентификаторов по указанному типу сущности.
Как правильно передать несколько телефонов у контакта?
Поле PHONE — это массив объектов вида {VALUE, VALUE_TYPE}. Каждый элемент описывает отдельный номер со своим типом: WORK, MOBILE, HOME и другими.
findbycomm ищет только среди контактов?
Нет. Параметр entity_type принимает CONTACT, COMPANY и LEAD, поэтому одним семейством методов можно проверять дубли по всем ключевым сущностям CRM.
Что делать, если найдено несколько дублей?
Метод вернёт массив всех совпавших ID. Логику выбора главной карточки определяете вы: чаще берут самую раннюю по дате создания или с наиболее полными данными.
Поможет ли DUPLICATE_CONTROL полностью убрать дубли?
Он блокирует создание при совпадении, но не решает, какую карточку считать основной. Для интеграций надёжнее явная проверка findbycomm перед записью.
Нужно ли чистить номер телефона перед поиском?
Нет, findbycomm нормализует значения самостоятельно. Достаточно передать номер в любом распространённом формате.
Поможем с настройкой и поддержкой Для разработчиков
Поможем с настройкой, доработкой и поддержкой Для разработчиков.