Перейти к основному содержимому
Опубликовано: 

Импорт и добавление контактов через Sendsay API

Sendsay API позволяет управлять базой контактов: добавлять контакты по одному, массово импортировать списки, обновлять данные существующих контактов.

Ключи данных и анкеты

Sendsay поддерживает два формата хранения данных контактов:

  • Ключи данных (КД) — современный формат, используется в member.set / member.get. Данные — произвольные ключи с любым уровнем вложенности (объекты, массивы).
  • Анкета-Вопрос-Ответ (АВО) — устаревший формат с привязкой к анкетам.

Ключи данных — более современный и удобный формат, с которым проще работать. Он более гибкий и поддерживает вложенные структуры.

Добавление одного контакта — member.set

Вызов member.set создаёт новый контакт или обновляет данные существующего. Работает с форматом Ключи данных (КД).

Минимальный запрос

{
"apikey": "ваш-api-ключ",
"action": "member.set",
"addr_type": "email",
"email": "test@test.com",
"datakey": [
["base.firstName", "set", "Анна"],
["base.city", "set", "Москва"]
]
}

Параметры

ПараметрОписание
actionmember.set
addr_typeТип идентификатора: email, msisdn, viber, csid, push, vk, tg, vknotify, pushapp, id и др. Указывать его не обязательно — система сама распознаёт email или msisdn
emailАдрес контакта (для addr_type: email)
datakeyМассив операций над ключами данных. Каждая операция — массив: ["ключ", "режим", "значение"] или ["ключ", "режим", "значение", "тип"]
if_existsПоведение при существующем контакте: overwrite (по умолчанию) — обновить данные; error — вернуть ошибку; must — обновить только существующий, не создавать новый
newbie.confirm1 — требовать подтверждения внесения в базу (по умолчанию 0). Используется только для email-адресов, действует лимит внесения без подтверждения

Режимы изменения данных

РежимОписание
setЗаменить данные новым значением
updateЗаменить, только если ключ уже существует
insertДобавить, только если ключа ещё нет
mergeОбъединить объекты: для каждого ключа нового значения выполняется set в существующий объект
merge_updateОбъединить объекты: заменяются только существующие ключи, новые игнорируются
merge_insertОбъединить объекты: добавляются только отсутствующие ключи, существующие не трогаются
pushДобавить значение в конец массива
unshiftДобавить значение в начало массива
deleteУдалить данные по ключу (значение не указывается)

Каждый из режимов (кроме delete) имеет вариант с суффиксом .copy (например: set.copy, update.copy) — в этом случае вместо значения указывается ключ данных, из которого копируется значение.

Пример: задать несколько полей

{
"apikey": "ваш-api-ключ",
"action": "member.set",
"addr_type": "email",
"email": "test@test.com",
"datakey": [
["base.firstName", "set", "Анна"],
["base.lastName", "set", "Иванова"],
["base.city", "set", "Москва"],
["base.birthDate", "set", "1990-05-15", "dt:YD"]
]
}

Элемент "dt:YD" — необязательный тип данных. Для дат выполняется проверка и приведение к стандартному формату (например, "1990-5-4" станет "1990-05-04").

Добавление с указанием списка

Для управления списками используется псевдо-ключ -group.КОДГРУППЫ с режимом set и значением 1 (включить) или режимом delete (исключить):

{
"apikey": "ваш-api-ключ",
"action": "member.set",
"addr_type": "email",
"email": "test@test.com",
"datakey": [
["base.firstName", "set", "Анна"],
["-group.clients", "set", "1"],
["-group.newsletter", "set", "1"]
]
}

Обновление данных без автосоздания

Если нужно обновить данные только существующего контакта и не создавать новый, используйте if_exists: "must":

{
"apikey": "ваш-api-ключ",
"action": "member.set",
"addr_type": "email",
"email": "test@test.com",
"if_exists": "must",
"datakey": [
["member.cellphone", "set", "+79001234567"],
["loyalty_level", "set", "gold"]
]
}

Если контакта с таким адресом нет — вызов вернёт ошибку, а не создаст новый контакт.

Обновление только отсутствующих данных

Режим insert позволяет записать значение, только если ключ ещё не существует — удобно для первичного внесения данных без перезаписи:

{
"datakey": [
["base.firstName", "insert", "Неизвестный"],
["base.city", "insert", "Не указан"]
]
}

Удаление данных

{
"datakey": [
["loyalty_level", "delete"],
["-group.old_segment", "delete"]
]
}

Ответ

Успешный ответ:

{
"addr_type": "email",
"email": "test@test.com"
}
Важно

Все изменения в datakey применяются вместе — либо все операции выполняются, либо не одна (при любой ошибке).

Получение данных контакта — member.get

{
"apikey": "ваш-api-ключ",
"action": "member.get",
"addr_type": "email",
"email": "test@test.com",
"datakey": ["base.firstName", "base.city", "member.cellphone", "-group"]
}

В datakey перечисляются ключи, которые нужно получить.

Специальный ключ -group вернёт список групп контакта. Чтобы получить все данные, используйте "*":

{
"apikey": "ваш-api-ключ",
"action": "member.get",
"addr_type": "email",
"email": "test@test.com",
"datakey": ["*"]
}

Проверка существования контакта — member.exists

{
"apikey": "ваш-api-ключ",
"action": "member.exists",
"email": "test@test.com"
}

Ответ:

{
"list": {
"test@test.com": 1
}
}

Значение 1 — контакт существует, 0 — не существует, null — ошибка в адресе (невалидный формат).

Поиск контакта по всем типам идентификаторов — member.find

Одна и та же строка может соответствовать разным типам идентификаторов (email, csid и др.). Вызов member.find возвращает все совпадения:

{
"apikey": "ваш-api-ключ",
"action": "member.find",
"email": "test@test.com"
}

Ответ:

{
"list": [
{
"id": 12345,
"addr_type": "email",
"email": "test@test.com"
}
]
}

Информация об адресе — email.get

Запрос возвращает информацию об адресе, не связанную с существованием контакта — включая данные об ошибках доставки, стоп-листе и отписках. Работает, даже если контакт уже удалён.

{
"apikey": "ваш-api-ключ",
"action": "email.get",
"email": "test@test.com",
"with_stoplist": 2
}

Параметр with_stoplist: 2 возвращает расширенный формат стоп-листа с записями и по глобальному стоп-листу, и по отпискам от отдельных отправителей.

Стоп-листы

В ответе придёт блок member с информацией:

  • номер адреса (id),
  • наличие блокировки (haslock),
  • ошибки доставки (error),
  • статус отписки (lockremove),
  • записи стоп-листа (stoplist).

Удаление контакта — member.delete

{
"apikey": "ваш-api-ключ",
"action": "member.delete",
"addr_type": "email",
"email": "test@test.com"
}

Массовый импорт — member.import

Вызов member.import позволяет загрузить список контактов одним запросом. Адреса и данные передаются прямо в запросе через users.list или по ссылке через users.url. Параметр users.list поддерживает несколько форматов.

Формат определяется автоматически по типу значения:

  • Если значение — объект → JSON-объект (АВО или КД, в зависимости от структуры caption).
  • Если значение — строка ZIP с файлом workbook.xml → XLSX.
  • Если значение — строка ZIP без workbook.xml → CSV (первый файл архива).
  • Если значение — строка без ZIP → CSV.

При использовании users.url формат определяется по Content-Type ответа:

  • если application/json — данные должны быть объектом,
  • иначе — по правилам для строки.
Важно

JSON-массив доступен только для экспресс-выпуска. Для импорта контактов (member.import) этот формат не поддерживается.

Формат: CSV (строка)

Текстовые данные в формате CSV. Разделитель — запятая или точка с запятой. Первая строка — заголовок с описанием столбцов (в формате коданкеты.кодвопроса для модели АВО).

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": "member.email,base.firstName,base.city\nclient1@example.com,Анна,Москва\nclient2@example.com,Иван,Санкт-Петербург\nclient3@example.com,Ольга,Казань"
}

Если в значении ячейки встречается разделитель или кавычки, значение берётся в кавычки, а кавычки внутри удваиваются:

member.email,base.lastName,member.cellphone
test@test.ru,"ЗАО ""Рога и копыта""",+70000000000
test2@test.ru,"Рога, копыта и хвосты",+70000000000

Формат: JSON-объект-АВО

Объект с массивом caption (описание соответствия столбцов анкетам и вопросам) и массивом rows (данные). Каждая ячейка содержит одно значение: не массив и не объект.

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": {
"caption": [
{ "anketa": "member", "quest": "email" },
{ "anketa": "base", "quest": "firstName" },
{ "anketa": "base", "quest": "city" }
],
"rows": [
["client1@example.com", "Анна", "Москва"],
["client2@example.com", "Иван", "Санкт-Петербург"],
["client3@example.com", "Ольга", "Казань"]
]
}
}

Формат: JSON-объект-КД

Аналогичная структура с caption и rows, но caption описывает ключи данных (datakey) и режим изменения (mode). Данные в ячейках могут быть любой структуры — строки, числа, массивы, объекты.

Импорт в формате JSON-объект-КД — это массовый member.set с индивидуальными данными для каждого контакта.

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": {
"caption": [
{ "datakey": "member.email" },
{ "datakey": "base.firstName" },
{ "datakey": "base.city" },
{ "datakey": "tags" }
],
"rows": [
["client1@example.com", "Анна", "Москва", ["vip", "active"]],
["client2@example.com", "Иван", "Санкт-Петербург", ["new"]],
["client3ga@example.com", "Ольга", "Казань", { "level": "gold", "score": 150 }]
]
}
}

В caption также можно использовать:

  • { "ignore": 1 } для пропуска столбца,
  • { "dynamic": 1 } для динамического ключа (в ячейке — структура аналогичная записи member.set с datakey или null).

Параметры

ПараметрОписание
actionmember.import
addr_typeТип идентификатора: email, msisdn, viber, csid, push, vk, tg, vknotify, pushapp, id и др. Не обязательно — система сама распознаёт email или msisdn
users.listДанные контактов: строка (CSV/XLSX) или JSON-объект (АВО/КД). JSON-массив не поддерживается
users.urlАльтернатива users.list — ссылка на внешний файл с данными
users.list.encodingКодировка данных (для CSV)
separatorРазделитель полей в CSV (,, ;, \t и др.)
captionОписание столбцов (альтернатива первой строке CSV или заголовку XLSX)
if_existsoverwrite — обновить существующих; error — пропустить существующих; must — обновить только существующих, не создавать новых
newbie.confirm1 — требовать подтверждения внесения в базу (по умолчанию 0). Внесение email без подтверждения ограничено лимитом member.noconfirm.rest (можно проверить через sys.settings.get). Не влияет на номера телефонов — они всегда вносятся без подтверждения
auto_groupОбъект. Автоматически создать список для импортируемых адресов или дополнить существующую. Содержит id (код списка) и name (название). Если id не указан — создаётся список со стандартным кодом importYYYYMMDDhhmmss. Код созданного списка можно узнать через track.get
clean_group1 — очистить список из auto_group перед импортом (полная замена участников). По умолчанию 0
member.group.addМассив кодов списков, в которые нужно добавить импортируемые адреса
member.group.removeМассив кодов списков, из которых нужно удалить импортируемые адреса
sequence.event1 — внесение/изменение данных будет вызывать срабатывание событийных действий. По умолчанию 0
sequence.startМассив номеров триггеров, прохождение которых нужно запустить для всех участников импорта
sequence.stopМассив номеров триггеров, прохождение которых нужно остановить для всех участников импорта

Порядок обработки списков:

  1. сначала удаление из member.group.remove,
  2. затем добавление в member.group.add,
  3. затем auto_group.

Порядок обработки последовательностей:

  1. сначала остановка по sequence.stop,
  2. затем запуск по sequence.start.

Действует на всех участников импорта, независимо от того, изменились ли их данные.

Импорт с автосозданием списка

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": "member.email,base.firstName\nclient1@example.com,Анна\nclient2@example.com,Иван",
"auto_group": {
"id": "march_import",
"name": "Импорт март 2026"
}
}

Импорт с добавлением и удалением из списка (CSV)

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": "member.email,base.firstName\nclient1@example.com,Анна\nclient2@example.com,Иван",
"member.group.add": ["newsletter", "clients"],
"member.group.remove": ["old_segment"]
}

Импорт с добавлением и удалением из списков (JSON-объект-КД)

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.list": {
"caption": [{ "datakey": "member.email" }, { "datakey": "base.firstName" }],
"rows": [
["client1@example.com", "Анна"],
["client2@example.com", "Иван"]
]
},
"member.group.add": ["newsletter", "clients"],
"member.group.remove": ["old_segment"]
}

Импорт из файла

Если список контактов большой, данные можно загрузить как файл в хранилище CDP Sendsay (rfs.file.put) и указать путь:

{
"apikey": "ваш-api-ключ",
"action": "member.import",
"addr_type": "email",
"users.file": "путь/к/файлу.csv",
"separator": ";",
"auto_group": {
"id": "newsletter"
}
}

Ответ

Импорт — асинхронный вызов. В ответе возвращается трекер:

{
"track.id": 11111
}

Результат импорта проверяется вызовом track.get:

{
"apikey": "ваш-api-ключ",
"action": "track.get",
"id": 11111
}

В финальном ответе трекера будет информация о количестве обработанных, созданных, обновлённых, пропущенных контактов и ошибках.

Пробный импорт — member.import.probe

Перед массовым импортом вы можете проверить формат данных, без реального внесения:

{
"apikey": "ваш-api-ключ",
"action": "member.import.probe",
"addr_type": "email",
"users.list": "email;name\nclient1@example.com;Анна",
"separator": ";"
}

Запрос вернёт информацию о распознанных столбцах, типах данных и возможных ошибках.

Отправка письма-подтверждения — member.sendconfirm

Вызов позволяет отправить письма, в которых работают специальные команды шаблонизатора:

  • [% param.url_confirm %] для подтверждения внесения в базу,
  • [% param.url_unsub_cancel %] и [% param.url_unsub_sender_cancel %] для удаления из стоп-листов.

Типы подтверждений

ПараметрОписание
confirm: 1Подтверждение внесения в базу
unsubcancel: 1Удаление из глобального стоп-листа
unsubsendercancel: 1Удаление из стоп-листа по отправителю (отправитель берётся из черновика letter)

Пример: подтверждение для одного контакта

{
"apikey": "ваш-api-ключ",
"action": "member.sendconfirm",
"confirm": 1,
"letter": "confirm_letter",
"email": "client1@example.com"
}

Параметр letter — это код информационного письма, который обязательно нужно указать. Письмо должно иметь заполненный адрес отправителя и не находиться на модерации.

Способы указания получателей

СпособОписаниеСинхронность по умолчанию
emailОдин контактСинхронно
listМассив идентификаторовСинхронно
groupКод спискаАсинхронно
group.filterФильтр отбораАсинхронно
urlСсылка на файл с даннымиАсинхронно
stat.uniВыборка из универсальной статистикиАсинхронно

Синхронность можно изменить параметром sync: 0|1.

Пример: подтверждение для списка контактов

{
"apikey": "ваш-api-ключ",
"action": "member.sendconfirm",
"confirm": 1,
"letter": "confirm_letter",
"list": ["client1@example.com", "client2@example.com"]
}

Пример: подтверждение для списка

{
"apikey": "ваш-api-ключ",
"action": "member.sendconfirm",
"confirm": 1,
"letter": "confirm_letter",
"group": "unconfirmed_users",
"issue_name": "Повторное приглашение"
}

При использовании group, group.filter, url или stat.uni создаётся выпуск, номер которого возвращается в issue.id. Асинхронные запросы также возвращают track.id для отслеживания.

Особенности добавления контактов через Sendsay API

  • При импорте система проверяет адреса и может отклонить некорректные.
  • Результаты импорта доступны в «Журнале заданий».
  • Повторный импорт с if_exists: "overwrite" обновит данные существующих контактов, а не создаст дубликаты.
  • Для работы с триггерными сценариями можно указать, на какие последовательности запустить участников, а на каких остановить.
  • Максимальные лимиты на размер users.list и количество записей зависят от тарифа. Для очень больших списков рекомендуется использовать загрузку через файл.