Как изменить или удалить номера телефонов и email
Scope:
crmКто может выполнять методы: чтобы пройти сценарий целиком, нужно самое строгое из перечисленных прав — «изменения» элементов объекта CRM
- crm.item.update — пользователь с правом «изменения» элементов объекта CRM
- crm.item.add — пользователь с правом «добавления» элемента объекта CRM
- crm.item.get — пользователь с правом «чтения» элементов объекта CRM
Выберите инструмент для разработки с AI-агентом:
- используйте Битрикс24 Вайбкод, чтобы создать приложение для Битрикс24 по описанию задачи без знания языков программирования. Агент напишет код и разместит приложение на сервере без ручной настройки хостинга
- используйте MCP-сервер, чтобы разрабатывать интеграцию через REST API в своем проекте. Агент будет обращаться к официальной REST-документации
Телефоны и почту Битрикс24 хранит не отдельными полями контакта, а мультиполем fm — набором записей типа crm_multifield. У одного контакта может быть сколько угодно таких записей: рабочая и личная почта, мобильный и рабочий телефон.
У каждой записи есть свой идентификатор id, который выдает Битрикс24 при создании. Изменить или удалить конкретный номер можно только по этому идентификатору: по тексту значения система запись не ищет. Поэтому сначала нужно прочитать контакт и узнать идентификаторы, а уже потом отправлять изменения.
В результате сценария у контакта изменятся рабочая почта и мобильный телефон, личная почта будет удалена, а рабочий телефон останется прежним.
Сценарий состоит из трех шагов.
- Создать контакт с почтой и телефонами методом crm.item.add
- Прочитать контакт и узнать
idзаписей мультиполя методом crm.item.get - Изменить одни значения и удалить другие методом crm.item.update
Если контакт уже существует, шаг 1 пропустите и начните с шага 2.
Что нужно до начала
-
вебхук создан от имени пользователя, у которого есть право изменять контакты в CRM
-
в правах вебхука отмечен scope
crm -
путь вебхука дает полный доступ в рамках своего scope. Храните путь в переменной окружения и не публикуйте его в открытом коде
-
обязательные пользовательские поля контакта передавайте в шаге 1 сами: учитывает их метод или нет, зависит от настройки CRM «Проверять наличие обязательных пользовательских полей»
Сценарий показан на контакте — entityTypeId: 3. Мультиполя устроены одинаково у контакта, компании и лида: что поменять для других объектов, описано в блоке Что важно учитывать.
Как ключ в поле fm определяет операцию
В шаге 1 поле fm — это массив: каждый элемент добавляет новую запись.
В шаге 3 поле fm — это объект, и операцию определяет ключ элемента.
|
Ключ |
Что делает |
Что передать в элементе |
|
|
Добавляет новую запись |
|
|
Числовой |
Меняет значение существующей записи |
|
|
Числовой |
Удаляет запись |
|
Внутри каждого элемента передаются три ключа:
-
typeId— тип записи:PHONE,EMAIL,WEB,IM,LINK -
valueType— подтип значения: для телефона —WORK,MOBILE,FAX,HOME,PAGER,MAILING,OTHER; для почты —WORK,HOME,MAILING,OTHER -
value— само значение
typeId обязателен в каждом элементе объекта fm, в том числе при удалении. Без него метод не вернет ошибку, но и не выполнит операцию: ответ придет успешный, а значение останется прежним.
Записи, которых нет в объекте fm, метод не изменяет. Поэтому удаление задают отдельной операцией с пустым value, а не отсутствием записи в запросе.
1. Создадим контакт с почтой и телефонами
Используем метод crm.item.add с параметрами:
-
entityTypeId— идентификатор типа объекта CRM, обязательный параметр. Укажем3— контакт -
fields[name]иfields[lastName]— имя и фамилия контакта -
fields[fm]— массив записей мультиполя. Передадим две почты и два телефона
Как использовать примеры в документации
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
const resultAdd = await $b24.actions.v2.call.make({
method: 'crm.item.add',
params: {
entityTypeId: 3, // 3 — контакт
fields: {
name: 'Иван',
lastName: 'Иванов',
fm: [
{ typeId: 'EMAIL', valueType: 'WORK', value: 'work_email@nomail.com' },
{ typeId: 'EMAIL', valueType: 'HOME', value: 'home_email@nomail.com' },
{ typeId: 'PHONE', valueType: 'WORK', value: '+79991234567' },
{ typeId: 'PHONE', valueType: 'MOBILE', value: '+79997654321' }
]
}
},
requestId: 'item-add'
});
const contactId = resultAdd.getData().result.item.id;
# pip install b24pysdk
from b24pysdk import BitrixWebhook, Client
client = Client(
BitrixWebhook(
domain="your-domain.bitrix24.ru",
webhook_token="USER_ID/TOKEN", # только user_id/token, без https://
)
)
item = client.crm.item.add(
3, # 3 — контакт
{
"name": "Иван",
"lastName": "Иванов",
"fm": [
{"typeId": "EMAIL", "valueType": "WORK", "value": "work_email@nomail.com"},
{"typeId": "EMAIL", "valueType": "HOME", "value": "home_email@nomail.com"},
{"typeId": "PHONE", "valueType": "WORK", "value": "+79991234567"},
{"typeId": "PHONE", "valueType": "MOBILE", "value": "+79997654321"},
],
},
).response.result["item"]
contact_id = item["id"]
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Psr\Log\NullLogger;
$sb = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook('https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/');
$resultAdd = $sb->getCRMScope()->item()->add(
3, // 3 — контакт
[
'name' => 'Иван',
'lastName' => 'Иванов',
'fm' => [
[ 'typeId' => 'EMAIL', 'valueType' => 'WORK', 'value' => 'work_email@nomail.com' ],
[ 'typeId' => 'EMAIL', 'valueType' => 'HOME', 'value' => 'home_email@nomail.com' ],
[ 'typeId' => 'PHONE', 'valueType' => 'WORK', 'value' => '+79991234567' ],
[ 'typeId' => 'PHONE', 'valueType' => 'MOBILE', 'value' => '+79997654321' ]
]
]
);
$contactId = $resultAdd->item()->id;
Метод возвращает объект item с полным набором полей контакта. Ответ сокращен, показаны поля, которые подтверждают результат. Сохраните id контакта — он нужен шагам 2 и 3. В примере id: 2653.
{
"result": {
"item": {
"id": 2653,
"entityTypeId": 3,
"name": "Иван",
"lastName": "Иванов",
"hasPhone": "Y",
"hasEmail": "Y",
"fm": [
{
"id": 8553,
"valueType": "WORK",
"value": "work_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8555,
"valueType": "HOME",
"value": "home_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8557,
"valueType": "WORK",
"value": "+79991234567",
"typeId": "PHONE"
},
{
"id": 8559,
"valueType": "MOBILE",
"value": "+79997654321",
"typeId": "PHONE"
}
]
}
}
}
2. Прочитаем идентификаторы записей мультиполя
Метод crm.item.add уже вернул массив fm с идентификаторами, поэтому в одном скрипте шаг 2 можно пропустить. Отдельный вызов нужен, когда контакт создан раньше и идентификаторов у вас нет.
Используем метод crm.item.get с параметрами:
-
entityTypeId—3для контакта -
id— идентификатор контакта из шага 1, в примере2653
const resultGet = await $b24.actions.v2.call.make({
method: 'crm.item.get',
params: {
entityTypeId: 3,
id: contactId
},
requestId: 'item-get'
});
const multifields = resultGet.getData().result.item.fm;
multifields = client.crm.item.get(
3,
contact_id,
).response.result["item"]["fm"]
$multifields = $sb->getCRMScope()->item()->get(3, $contactId)->item()->fm;
В массиве fm найдите нужные записи по паре typeId и valueType и сохраните их id. В примере рабочая почта — 8553, личная почта — 8555, мобильный телефон — 8559.
{
"result": {
"item": {
"id": 2653,
"name": "Иван",
"lastName": "Иванов",
"fm": [
{
"id": 8553,
"valueType": "WORK",
"value": "work_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8555,
"valueType": "HOME",
"value": "home_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8557,
"valueType": "WORK",
"value": "+79991234567",
"typeId": "PHONE"
},
{
"id": 8559,
"valueType": "MOBILE",
"value": "+79997654321",
"typeId": "PHONE"
}
]
}
}
}
Не записывайте идентификаторы записей из примера в рабочий код. Их выдает Битрикс24 в момент создания записи, поэтому у каждого контакта они свои — запрашивайте их шагом 2 и подставляйте переменными, как в блоке Пример кода.
3. Изменим и удалим записи мультиполя
Используем метод crm.item.update с параметрами:
-
entityTypeId—3для контакта -
id— идентификатор контакта из шага 1, в примере2653 -
fields[fm]— объект с операциями над записями мультиполя. Ключ каждого элемента — этоidзаписи из шага 2, а операцию определяет содержимое, как описано в разделе Как ключ в поле fm определяет операцию
Выполним три операции одним запросом:
-
изменим рабочую почту
8553— передадим новыйvalue -
удалим личную почту
8555— передадим пустойvalue -
изменим мобильный телефон
8559— передадим новыйvalue
Рабочий телефон 8557 в запросе не упоминаем, поэтому он останется прежним.
const resultUpdate = await $b24.actions.v2.call.make({
method: 'crm.item.update',
params: {
entityTypeId: 3,
id: contactId,
fields: {
fm: {
// ключ — id записи из шага 2
8553: { typeId: 'EMAIL', valueType: 'WORK', value: 'new_work_email@nomail.com' }, // меняем рабочую почту
8555: { typeId: 'EMAIL', value: '' }, // пустое значение удаляет личную почту
8559: { typeId: 'PHONE', valueType: 'MOBILE', value: '+79995554433' } // меняем мобильный телефон
}
}
},
requestId: 'item-update'
});
result_update = client.crm.item.update(
3,
contact_id,
{
"fm": {
# ключ — id записи из шага 2
"8553": {"typeId": "EMAIL", "valueType": "WORK", "value": "new_work_email@nomail.com"}, # меняем рабочую почту
"8555": {"typeId": "EMAIL", "value": ""}, # пустое значение удаляет личную почту
"8559": {"typeId": "PHONE", "valueType": "MOBILE", "value": "+79995554433"}, # меняем мобильный телефон
},
},
).response.result["item"]
$resultUpdate = $sb->getCRMScope()->item()->update(
3,
$contactId,
[
'fm' => [
// ключ — id записи из шага 2
8553 => [ 'typeId' => 'EMAIL', 'valueType' => 'WORK', 'value' => 'new_work_email@nomail.com' ], // меняем рабочую почту
8555 => [ 'typeId' => 'EMAIL', 'value' => '' ], // пустое значение удаляет личную почту
8559 => [ 'typeId' => 'PHONE', 'valueType' => 'MOBILE', 'value' => '+79995554433' ] // меняем мобильный телефон
]
]
);
Метод возвращает контакт целиком уже с новым составом записей, поэтому проверять результат отдельным запросом не обязательно. Ответ сокращен.
{
"result": {
"item": {
"id": 2653,
"name": "Иван",
"lastName": "Иванов",
"hasEmail": "Y",
"hasPhone": "Y",
"updatedTime": "2026-08-20T09:10:29+03:00",
"fm": [
{
"id": 8553,
"valueType": "WORK",
"value": "new_work_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8557,
"valueType": "WORK",
"value": "+79991234567",
"typeId": "PHONE"
},
{
"id": 8559,
"valueType": "MOBILE",
"value": "+79995554433",
"typeId": "PHONE"
}
]
}
}
}
Проверим результат
Откройте карточку контакта «Иван Иванов» в CRM. В блоке контактных данных остались рабочая почта new_work_email@nomail.com, рабочий телефон +79991234567 и мобильный +79995554433. Личной почты home_email@nomail.com больше нет. Номера телефонов Битрикс24 показывает в своем формате, поэтому сверяйте их по цифрам, а не по написанию.
Через REST состав мультиполей возвращает метод crm.item.get с теми же параметрами, что в шаге 2.
const checkResult = await $b24.actions.v2.call.make({
method: 'crm.item.get',
params: { entityTypeId: 3, id: contactId },
requestId: 'item-check'
});
console.dir(checkResult.getData().result.item.fm);
print(client.crm.item.get(3, contact_id).response.result["item"]["fm"])
print_r($sb->getCRMScope()->item()->get(3, $contactId)->item()->fm);
Сценарий выполнен, если в массиве fm три записи: у 8553 новый адрес почты, у 8559 новый номер телефона, записи 8555 нет, а 8557 не изменилась.
{
"result": {
"item": {
"id": 2653,
"fm": [
{
"id": 8553,
"valueType": "WORK",
"value": "new_work_email@nomail.com",
"typeId": "EMAIL"
},
{
"id": 8557,
"valueType": "WORK",
"value": "+79991234567",
"typeId": "PHONE"
},
{
"id": 8559,
"valueType": "MOBILE",
"value": "+79995554433",
"typeId": "PHONE"
}
]
}
}
}
Ошибки и диагностика
Если метод вернул ошибку, проверьте данные запроса.
|
Код |
Причина и действие |
|
|
Элемент не найден. Проверьте |
|
|
В |
|
|
У пользователя вебхука нет права изменять элементы объекта с этим |
|
|
Вебхук создан от имени внешнего пользователя. Сценарий доступен только сотрудникам Битрикс24 |
|
|
Неверное значение поля. Текст ошибки называет поле, которое не прошло проверку |
Отдельно проверьте случаи, когда метод отвечает успешно, но результат не тот, которого вы ждали.
-
значение не изменилось, ошибки нет — в элементе объекта
fmне переданtypeId. Добавьте его и повторите шаг 3 -
вместо изменения появилась новая запись — переданного
idу контакта нет. Метод в этом случае не отказывает, а создает новую запись. Сверьтеidс ответом шага 2 -
в карточке появилась запись с неизвестным типом — в
typeIdпередано значение не из спискаPHONE,EMAIL,WEB,IM,LINK. Метод такие значения не проверяет и сохраняет как есть. Удалите лишнюю запись по ееidс пустымvalue
Шаг 2 ничего не меняет, его можно повторять сколько угодно раз. Если crm.item.update вернул ошибку, перечитайте контакт шагом 2 и сверьте состав записей, а потом повторите только те операции, которых в нем нет.
Что важно учитывать
-
если передать в
crm.item.updateполеfmмассивом, а не объектом, метод не заменит состав мультиполей, а добавит новые записи к существующим: элементы массива он читает как ключиn0,n1и так далее -
полностью очистить телефоны или почту одним параметром нельзя. Прочитайте контакт шагом 2 и передайте пустой
valueдля каждой записи нужного типа -
метод crm.item.add не проверяет дубликаты. Повторный запуск примера создаст второй контакт «Иван Иванов» с теми же данными. Перед созданием ищите контакт методом crm.duplicate.findbycomm по телефону или почте
-
если в поле
fmпередать не массив, а строку, метод ошибки не вернет: контакт создастся вообще без телефонов и почты, а поляhasPhoneиhasEmailостанутся со значениемN -
пользовательские поля методы
crm.item.*называют в camelCase —ufCrm_1723209318вместоUF_CRM_1723209318. На мультиполя это не влияет, но если в том же запросе вы меняете пользовательское поле, передавайте параметрuseOriginalUfNames:Y, чтобы работать с привычными именами -
сценарий одинаково работает для контакта, компании и лида. Для компании укажите
entityTypeId:4и вместоnameиlastNameпередайтеtitle, для лида —entityTypeId:1
Пример кода
Скрипт создает контакт с двумя адресами почты и двумя телефонами, читает идентификаторы записей мультиполя, меняет рабочую почту и мобильный телефон, удаляет личную почту и показывает итоговый состав контактных данных.
import { B24Hook } from '@bitrix24/b24jssdk'
const $b24 = B24Hook.fromWebhookUrl(process.env.B24_HOOK)
// B24_HOOK = 'https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/'
const ENTITY_TYPE_ID = 3; // 3 — контакт, компания — 4, лид — 1
async function call(method, params, requestId) {
const result = await $b24.actions.v2.call.make({ method, params, requestId });
if (!result.isSuccess) {
throw new Error(result.getErrorMessages().join('; '));
}
return result.getData().result;
}
// находит id записи мультиполя по типу и подтипу значения
function findId(multifields, typeId, valueType) {
const found = multifields.find(item => item.typeId === typeId && item.valueType === valueType);
return found ? found.id : null;
}
async function changeContacts() {
try {
// Шаг 1: создаем контакт с почтой и телефонами
const created = await call('crm.item.add', {
entityTypeId: ENTITY_TYPE_ID,
fields: {
name: 'Иван',
lastName: 'Иванов',
fm: [
{ typeId: 'EMAIL', valueType: 'WORK', value: 'work_email@nomail.com' },
{ typeId: 'EMAIL', valueType: 'HOME', value: 'home_email@nomail.com' },
{ typeId: 'PHONE', valueType: 'WORK', value: '+79991234567' },
{ typeId: 'PHONE', valueType: 'MOBILE', value: '+79997654321' }
]
}
}, 'item-add');
const contactId = created.item.id;
console.log('Контакт создан, id:', contactId);
// Шаг 2: читаем идентификаторы записей мультиполя
const read = await call('crm.item.get', {
entityTypeId: ENTITY_TYPE_ID,
id: contactId
}, 'item-get');
const multifields = read.item.fm;
const workEmailId = findId(multifields, 'EMAIL', 'WORK');
const homeEmailId = findId(multifields, 'EMAIL', 'HOME');
const mobilePhoneId = findId(multifields, 'PHONE', 'MOBILE');
if (!workEmailId || !homeEmailId || !mobilePhoneId) {
console.error('У контакта нет нужных записей мультиполя');
return;
}
// Шаг 3: меняем одни значения и удаляем другие
// typeId обязателен в каждом элементе, иначе операция молча не выполнится
const updated = await call('crm.item.update', {
entityTypeId: ENTITY_TYPE_ID,
id: contactId,
fields: {
fm: {
[workEmailId]: { typeId: 'EMAIL', valueType: 'WORK', value: 'new_work_email@nomail.com' },
[homeEmailId]: { typeId: 'EMAIL', value: '' },
[mobilePhoneId]: { typeId: 'PHONE', valueType: 'MOBILE', value: '+79995554433' }
}
}
}, 'item-update');
console.log('Контактные данные обновлены:');
console.dir(updated.item.fm);
} catch (error) {
console.error('Контактные данные не обновлены:', error.message);
}
}
changeContacts();
# pip install b24pysdk
from b24pysdk import BitrixWebhook, Client
from b24pysdk.errors import BitrixAPIError
client = Client(
BitrixWebhook(
domain="your-domain.bitrix24.ru",
webhook_token="USER_ID/TOKEN", # только user_id/token, без https://
)
)
ENTITY_TYPE_ID = 3 # 3 — контакт, компания — 4, лид — 1
def find_id(multifields, type_id, value_type):
"""Находит id записи мультиполя по типу и подтипу значения."""
for field in multifields:
if field["typeId"] == type_id and field["valueType"] == value_type:
return field["id"]
return None
try:
# Шаг 1: создаем контакт с почтой и телефонами
created = client.crm.item.add(
ENTITY_TYPE_ID,
{
"name": "Иван",
"lastName": "Иванов",
"fm": [
{"typeId": "EMAIL", "valueType": "WORK", "value": "work_email@nomail.com"},
{"typeId": "EMAIL", "valueType": "HOME", "value": "home_email@nomail.com"},
{"typeId": "PHONE", "valueType": "WORK", "value": "+79991234567"},
{"typeId": "PHONE", "valueType": "MOBILE", "value": "+79997654321"},
],
},
).response.result["item"]
contact_id = created["id"]
print(f"Контакт создан, id: {contact_id}")
# Шаг 2: читаем идентификаторы записей мультиполя
multifields = client.crm.item.get(
ENTITY_TYPE_ID,
contact_id,
).response.result["item"]["fm"]
work_email_id = find_id(multifields, "EMAIL", "WORK")
home_email_id = find_id(multifields, "EMAIL", "HOME")
mobile_phone_id = find_id(multifields, "PHONE", "MOBILE")
if not all((work_email_id, home_email_id, mobile_phone_id)):
print("У контакта нет нужных записей мультиполя")
else:
# Шаг 3: меняем одни значения и удаляем другие
# typeId обязателен в каждом элементе, иначе операция молча не выполнится
updated = client.crm.item.update(
ENTITY_TYPE_ID,
contact_id,
{
"fm": {
str(work_email_id): {"typeId": "EMAIL", "valueType": "WORK", "value": "new_work_email@nomail.com"},
str(home_email_id): {"typeId": "EMAIL", "value": ""},
str(mobile_phone_id): {"typeId": "PHONE", "valueType": "MOBILE", "value": "+79995554433"},
},
},
).response.result["item"]
print("Контактные данные обновлены:")
print(updated["fm"])
except BitrixAPIError as error:
print(f"Контактные данные не обновлены: {error}")
<?php
// composer require bitrix24/b24phpsdk:"^3.0"
require_once 'vendor/autoload.php';
use Bitrix24\SDK\Services\ServiceBuilderFactory;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Psr\Log\NullLogger;
$sb = (new ServiceBuilderFactory(new EventDispatcher(), new NullLogger()))
->initFromWebhook('https://your-domain.bitrix24.ru/rest/USER_ID/TOKEN/');
$entityTypeId = 3; // 3 — контакт, компания — 4, лид — 1
$item = $sb->getCRMScope()->item();
// находит id записи мультиполя по типу и подтипу значения
$findId = static function (array $multifields, string $typeId, string $valueType) {
foreach ($multifields as $field) {
if ($field['typeId'] === $typeId && $field['valueType'] === $valueType) {
return $field['id'];
}
}
return null;
};
try {
// Шаг 1: создаем контакт с почтой и телефонами
$contactId = $item->add(
$entityTypeId,
[
'name' => 'Иван',
'lastName' => 'Иванов',
'fm' => [
[ 'typeId' => 'EMAIL', 'valueType' => 'WORK', 'value' => 'work_email@nomail.com' ],
[ 'typeId' => 'EMAIL', 'valueType' => 'HOME', 'value' => 'home_email@nomail.com' ],
[ 'typeId' => 'PHONE', 'valueType' => 'WORK', 'value' => '+79991234567' ],
[ 'typeId' => 'PHONE', 'valueType' => 'MOBILE', 'value' => '+79997654321' ]
]
]
)->item()->id;
echo 'Контакт создан, id: ' . $contactId . PHP_EOL;
// Шаг 2: читаем идентификаторы записей мультиполя
$multifields = $item->get($entityTypeId, $contactId)->item()->fm;
$workEmailId = $findId($multifields, 'EMAIL', 'WORK');
$homeEmailId = $findId($multifields, 'EMAIL', 'HOME');
$mobilePhoneId = $findId($multifields, 'PHONE', 'MOBILE');
if ($workEmailId === null || $homeEmailId === null || $mobilePhoneId === null) {
echo 'У контакта нет нужных записей мультиполя';
return;
}
// Шаг 3: меняем одни значения и удаляем другие
// typeId обязателен в каждом элементе, иначе операция молча не выполнится
$updated = $item->update(
$entityTypeId,
$contactId,
[
'fm' => [
$workEmailId => [ 'typeId' => 'EMAIL', 'valueType' => 'WORK', 'value' => 'new_work_email@nomail.com' ],
$homeEmailId => [ 'typeId' => 'EMAIL', 'value' => '' ],
$mobilePhoneId => [ 'typeId' => 'PHONE', 'valueType' => 'MOBILE', 'value' => '+79995554433' ]
]
]
);
echo 'Контактные данные обновлены:' . PHP_EOL;
print_r($updated->item()->fm);
} catch (\Throwable $e) {
echo 'Контактные данные не обновлены: ' . $e->getMessage();
}