Подписчики¶
Идентификация подписчика¶
Каждый подписчик имеет свой набор связанных с ним данных и идентифицируется в системе - своими адресом электронной почты - email - номером мобильного телефона - msisdn - номером Viber - viber - клиентским идентификатором - csid - идентификатором (токеном) регистрации - push и pushapp - номером регистрации ВКонтакте - vk - номером мобильного телефона для VK Notify - vknotify - номером регистрации в Телеграм - tg - номером регистрации в MAX - max
Именно их вы указываете в параметре, традиционно называемом "email", и в данных импортирования.
При сохранении, каждому идентификатору система назначает свой внутренний целочисленный номер. Он постоянен (даже если подписчика удалить и потом создать заново) и доступен вам как member.id.
Так как указание адреса или телефона в открытом виде не всегда допустимо, то система предоставляет клиенту две возможности по их сокрытию - "Клиентский идентификатор" и "Заменитель адреса", которые описаны ниже.
Большинство вызовов также понимают тип идентификатора "id" - системный номер уже существующего подписчика.
Набор данных, связанный с идентификатором, тоже имеет свой номер - member.dataset. Но этот номер не постоянен. Если вы создали, удалили и опять создали подписчика с одним и тем же идентификатором, то его системный номер member.id будет в обоих случаях один и тот же, а номер набора данных будет другой. Номер набора данных напрямую не требуется для работы и доступен только для того, чтобы: - можно было сравнить эти номера у двух разных подписчиков и таким образом определить, не объединены ли они в одного (подраздел "Мультиканальность" нижe) - использовать его в вызове member.get для чтения разом всех подписчиков, связанных с данным набором данных (например, для отображения "Карточки подписчика)
Использование адреса электронной почты¶
Система полностью поддерживает национальные доменные имена (IDN) и национальные имена получателей. Вы можете без проблем использовать адреса не только из домена .рф (например проверка@тест.рф), но и из любых других национальных доменов (например, 企业@企业.企业), и записывать из без всяких ухищрений (типа xn--кодирования) просто как есть.
Система нормализует email, приводя их к написанию маленькими буквами (да, формально это не по стандарту, но такова практика всех почтовых систем).
Также производится проверка email-адреса на соответствие правилам RFC и правильности указания его домена верхнего уровня.
Национальные почтовые адреса по умолчанию включены для всех аккаунтов, созданных с 2016-07-26. Для ранее созданных аккаунтов возможность включается через параметр email.utf8 вызова sys.settings.set. Если к моменту включения вы уже имели в базе адреса с xn--кодированием, то обратитесь в Службу поддержки для их преобразования.
Использование номера мобильного телефона¶
Система нормализует номера телефонов к виду +7XXXYYYYYYY.
Также производится проверка номера телефона на наличие в реестре "Российской системы и плана нумерации" Федерального агентства связи.
Использование клиентского идентификатора¶
Клиентский идентификатор регистрозависим и нормализуется только удалением начальных и конечных пробельных символов. Остальное в нём - ваше дело. Для системы это просто набор символов.
Скорее всего у вас есть свой уникальный идентификатор подписчика. Если вы будете вносить его вместе с прочими данными подписчика, то сможете включать его в отчёты наряду или вместо email.
Но кроме такого простого использования вам доступен более продвинутый способ - система может следить за уникальностью вашего клиентского идентификатора при внесении и изменении данных, и вы можете указывать его в "Экспресс-выпуске" и "Транзакционных письмах" вместо реального адреса.
Возможность системы использовать клиентский идентификатор в выпуске рассылки место настоящего адреса позволяет реализовать сложные сценарии работы с рассылками без раскрытия адресов третьим лицам.
Например, по вашему поручению подрядчик собирает какие-то данные о посетителях вашего сайта и должен периодически делать по ним рассылки. Он не знает адресов ваших посетителей, а знает только их идентификаторы, что в обычной ситуации не позволит ему произвести рассылку.
Если же вы подключите в Службе поддержки возможность делать выпуски и импорты по клиентскому идентификатору, то подрядчик сможет производить "Экспресс-Выпуск" и "Транзакционные Письма" с использованием известного ему идентификатора, который система сама превратит в адрес получателя.
Также это даёт возможность импортировать данные с указанием не настоящего адреса, а вашего клиентского идентификатора.
Хранение заменителя адреса¶
Вы можете хранить в системе не настоящие email-адреса, а их заменители. Главное, чтобы по заменителю адреса вы могли однозначно понять о каком вашем подписчике идёт речь.
Во всех отчётах и данных системы будет использоваться именно заменитель.
Реальный адрес необходимо будет указывать только при выпуске рассылки (к сожалению, при использовании заменителя адреса вам будет доступен только "Экспресс-Выпуск" и "Транзакционные Письма").
Данная возможность настраивается по обращению в Службу поддержки.
Мультиканальность¶
Одному подписчику могут соответствовать несколько идентификаторов (member.email), по которым вы получите доступ к одному и тому же набору данных (member.dataset).
Думайте об этом как о Змее-Горыныче: несколько голов (идентификаторов) с одним телом (набором данных).
В данный момент доступны идентификаторы видов: email-адрес, номер мобильного телефона, клиентский идентификатор, номер push-подписки, номер регистрации ВКонтакте, номер регистрации в Телеграм, номер регистрации в MAX.
По какой бы голове-идентификатору вы не вели работу, с подписчиков вы получаете доступ к одному и тому же телу-набору данных.
У набора данных должен быть хотя бы один идентификатор подписчика связанный с ним (тело без головы не живёт).
Участие подписчика в группах-списках учитывается по идентификаторам подписчика. Разные идентификаторы могут быть внесены в разные группы-списки (впрочем, в одну и туже - тоже).
Ещё один параметр индивидуальный для каждой головы - Источник создания - member.origin
Совершаемые подписчиком действия (доставка письма, сообщения; чтение письма и его длительность; переход по ссылке; отписка; подтверждение внесения в базу; ошибки доставки и прочие) запоминаются за тем его идентификатором, от которого произведены эти действия.
Например, если у тела есть почтовая голова с фатальными ошибками доставки, то из email-рассылки такое тело будет исключаться, но на рассылку sms это не повлияет.
Благодаря поддержке нескольких идентификаторов у одного подписчика вам доступны разнообразные сценарии мультиканального взаимодействия с ним. Например, "Выслать письмо, а тем кто за 10 дней так и не прочёл и не сделал ни одного перехода выслать смс".
Форматы хранения¶
В данный момент имеется два формата хранения - старый с моделью "Анкета-Вопрос-Ответ" (АВО) и актуальный с моделью хранения "Ключи Данных" (КД).
Формат АВО проверен временем, но имеет несколько недостатков, которые делают его непригодным для реализации сложных проектов.
Формат КД разработан как замена АВО и может быть использован в любых проектах.
Формат "Анкета-Вопрос-Ответ"¶
Формат АВО хранит данные в жестко структурированной форме "Анкет" которые состоят из "Вопросов" разных типов.
Данные о подписчике могут быть представлены только как "Ответы" на "Вопросы Анкет".
Формат АВО имеет только одно преимущество - при доступе к данным и изменении данных система следит за тем, что указаны существующие "Анкета" и "Вопрос", и проверяет соответствие данных типу "Вопроса".
Недостатки формата АВО более многочисленны и печальны:
-
ограничен набор символов, которые можно хранить
-
невозможно хранить несколько ответов на один "Вопрос" (массив)
-
невозможно хранить структуры данных произвольной сложности - иерархия данных только двухуровневая "Анкета-Вопрос"
-
в перспективе формат будет полностью заменён на КД и объявлен устаревшим
Формат "Ключи Данных"¶
(Изучите отдельную главу, описывающую ключи данных)
Новый формат КД разработан для замены форматы АВО и поддержки хранения сложных структур данных
-
Данные формата АВО полностью доступны через КД
-
Нет ограничения на набор хранимых данных
-
Нет ограничений на сложность иерархии хранения данных и их сочетание (например, "адреса подписчика" могут представлять собой массив из объектов, хранящих структуру одного адреса по компонентам (страна, город, улица, дом, квартира, координаты), а компоненты адреса в свою очередь там же быть объектами - "координаты" это "широта" и "долгота").
-
Нет ограничений на формат данных
-
У разных подписчиков по одному и тому же ключу данных можно хранить разные структуры и типы данных
-
Доступ к данным в выпуске рассылки осуществляется как и прежде путём прямой записи [% anketa.ключ.данных %] или через функцию datakey()
Системная анкета member¶
Через системную анкету member вы можете получить дополнительную служебную информацию о подписчике.
В формате "Ключи Данных" она имеет вид:
{
"member" : {
-- информация от наборе данных (теле) подписчика, общая для всех его идентификаторов (голов)
"create" : {
"time" : "2015-09-12 18:53:39" -- дата создания (Ys) набора данных
,"host" : "1.1.1.1" -- источник создания набора данных
}
,"update" : {
"time" : "2015-09-12 18:53:39" -- дата последнего изменения (Ys) набора данных
,"host" : "1.1.1.1" -- источник последнего изменения набора данных
}
,"import" : {
"time" : "2015-09-12 18:53:39" -- дата последнего изменения (Ys) набора данных при импорте
}
,"dataset" : 1231273891 -- внутренний номер набора данных (тело), с которым связан данный идентификатор (голова)
-- информация о том идентификаторе (голове), через который прочитаны данные, своя для каждого идентификатора
,"addr_type" : "email" -- тип идентификатора (email, msisdn, viber, csid, push, vk, tg, vknotify, pushapp, max)
,"email" : "test@test.ru" -- идентификатор
,"domain" : "test.ru" -- домен почтового адреса, если идентификатор email
,"id" : 1380900 -- внутренний номер идентификатора в системе
,"origin" : 2 -- номер Источника указаный при создании головы или изменении головы.
,"last" : {
"tz" : число -- временная зона последнего клика или чтения. Если устройство подписчика определено как "Робот", то не учитывается
-- хранится смещение от UTC в часах и минутах (HHMM или -HHMM), так как это число, но лидирующих нулей нет
-- подходит автоматически ведомый системой источник данных для выпусков с учётом временной зоны получателя
-- (вызов issue.send, параметр tz_observance)
}
,"mobile_os" : "android | ios| huawei" -- операционная система подписчика для pushapp. для остальных - пусто
-- в фильтрах должны использоваться только сравнение == и !=
,"mobile_app" : номер authext -- номер внешней аутентификации под которой зарегистрирован подписчик pushapp
-- каждому мобильному приложению создаётся своя внешняя аутентификация
-- для не pushapp - пусто
-- в фильтрах должны использоваться только сравнения == и !=
-- информация о блокировках идентификатора (головы), через который прочитаны данные, своя для каждого идентификатора
,"haslock" : 0, -- все блокировки идентификатора в одном параметре. Может ли получать сообщения
-- 0 - нет - может
-- 1 - отписался - не может
-- 2 - не подтверждён - не может
-- 4 - имеет фатальные ошибки доставки - не может получать письма
-- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указанных блокировок
,"confirm" : { -- состояние подтверждения внесения в базу
"lock" : 0, -- 0 - подтверждено, 1 - нет
,"time" : "2015-09-12 18:53:39" -- дата подтверждения (Ys)
,"host" : "1.1.1.1" -- источник подтверждения
}
,"error" : { -- состояние ошибок доставки
"lock" : 1 -- заблокирован из-за ошибок доставки (1) или нет (0)
,"date" : "2015-09-12 18:53:39" -- дата последней ошибки доставки (Ys) (удаляется при первой же успешной доставке)
,"str" : "name=test.ru type=A: Host not found" -- описание последней ошибки доставки (удаляется при первой же успешной доставке)
,"error" : 1 -- общее число ошибок доставки, произошедших подряд (устанавливается в 0 при первой же успешной доставке)
,"issue" : 123 -- выпуск последней ошибки доставки
,"letter" : 123 -- письмо последней ошибки доставки
,"lock_issue" : 456 -- выпуск приведший к блокировке
,"lock_letter" : 456 -- письмо приведшее к блокировке
}
,"lockremove" : 0 -- адрес отписан или в стоп-листе (1) или нет (0)
-- информация об участии в сообществах ВКонктаке для подписчиков с типом vk
"vk" : {
"номер сообщества" : {
"sub" => "дата Ys подписки" -- подписан
,"member" => "дата Ys вступления" -- участник
,"unsub" => "дата Ys отписки" -- отписался
,"left' => "дата Ys покидания" -- покинул
,"err" => "дата Ys последней ошибки" -- ошибки доставки
}
}
-- информация о подписчиках Телеграм для подписчиков с типом tg
"tg" : {
"номер бота" : {
"sub" => "дата Ys подписки" -- подписан
,"unsub" => "дата Ys отписки" -- отписался
,"err" => "дата Ys последней ошибки" -- ошибки доставки
}
}
}
}
В формате АВО анкета member содержит те же поля, но с названиями адаптированными к формату "анкета.вопрос". Например member.confirm.time
Полей member.dataset, member.last.tz member.vk., member.tg., member.max.* в ABO нет.
Псевдо-ключ "-group"¶
Псевдо-ключ "-group" описывает участие и дату внесения идентификатора в группах списка.
Перечисляются коды только тех групп-списков, в которых состоит именно этот идентификатор.
Дата внесения - дата и время с точностью Ys внесения в группу-список.
Фактическая точность - YD, но для совместимости с возможными будущими изменениями она увеличена до Ys добавкой "00:00:00".
{
"-group" : {
"gid1" : "дата-время внесения"
,"gid2" : "дата-время внесения"
.............
,"gidN": "дата-время внесения"
}
В фильтрах сегментов для отбора "Участвует/Не участвует в группе-списке" используйте операции "in_group" и "!in_group".
Для фильтрации по дате внесения - обычные операции сравнение и ключ данных "-group.кодгруппы".
Проверить существование подписчика¶
{
"action": "member.exists"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. Не обязательно, система сама распознает email или msisdn
}
ответ
{
<общие поля>
"list" : {
"адрес электронной почты или номер телефона" : 0|1|null -- подписчик существует (1) или нет (0) в базе, null - ошибка в адресе
-- в случае невалидного адреса запись в warnigns
},
,"warnings" : [ список предупреждений про невалидные адреса ]
}
Все подписчики с данным идентификатором¶
Одна и та же строка символов может быть использована как идентификатор подписчика для разных типов идентификаторов. Также усложняет жизнь то, что идентификаторы типа email и msisdn хранятся в нормализованном виде.
Это означает, что по строке нельзя однозначно сказать какого типа идентификатор она представляет. Например, "test@test.RU" может быть и email-адресом "test@test.ru" и идентификатором типа csid "test@test.RU".
Данный вызов позволяет получить для заданной строки все типы идентификаторов, соответствующих ей (с учётом нормализации), для подписчиков в системе.
ответ
{
<общие поля>
"list" : [
{
"id" : номер подписчика-1
,"addr_type : "тип идентификатора-1"
,"email" : "идентификатор-1" -- нормализованный
},
{
"id" : номер подписчика-2
,"addr_type : "тип идентификатора-2"
,"email" : "идентификатор-2" -- нормализованный
}
......
]
}
Создать подписчика / Обновить данные подписчика (КД)¶
При отсутствии адреса в базе он создаётся автоматически.
Изменяются только указанные данные.
Ещё раз прочтите раздел "Последовательность обработки" - два конкурентных запроса для одного и того же "тела" могут дать не тот результат что ожидается. Значительно снизить вероятность "неожиданного результата" можно запроси в Службе Поддержки включение настройки "Версионирование member.set" - вместо "успеха" один из конкурирующих запросов будет заканчиваться с ошибкой error/member/versioning и будет ясно, что его надо повторить. Это НЕ 100% защита, но версионирование сначительно снижает уровень "неожиданности". Единственное 100% решение - серилизация на вашей стороне.
{
"action" : "member.set"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"source" : "ip-адрес оригинального запроса"
-- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос
,"if_exists" : "error|must" -- не обязательно, по умолчанию существующий подписчик обновляется, а отсутствующий - создаётся
-- error - ошибка при наличии подписчика в базе
-- must - ошибка при отсутствии адреса в базе
,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)"
-- используется только при внесении email-адресов
-- действует лимит внесения без подтверждения
-- подробнее описанный в вызове member.import
,"newbie.letter.confirm" : "номер шаблона информационного письма"
-- высылается, если новый адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения
-- если параметр пуст или отсутствует, то ничего выслано не будет
-- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm
-- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт
-- продолжит вносить уже с подтверждением и этот параметр будет использоваться
-- при внесении номеров телефонов никакие уведомления не высылаются
-- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации
,"newbie.letter.no-confirm" : "номер шаблона информационного письма"
-- высылается? если новый адрес до этого отсутствовал в базе, и внесён с без необходимости подтверждения
-- если параметр пуст или отсутствует, то ничего выслано не будет
-- при внесении номеров телефонов никакие уведомления не высылаются
-- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации
-- записываемые/изменяемые данные
,"datakey" : [
[ "ключ-данных-1", "режим-1", "новое-значение-1" ]
,[ "ключ-данных-2", "режим-2", "новое-значение-2", "тип-2" ]
,[ "ключ-данных-3", "режим-копирования-3", "ключ-данных-из-4" ]
,[ "ключ-данных-4", "режим-копирования-4", "ключ-данных-из-5", "тип-5" ]
,[ "ключ-данных-5", "delete" ]
........
]
."copy_email" : "идентификатор подписчика" -- не обязательно, не совеместимо с copy_data
-- подписчик данные которого будут использоваться в *.copy
,"copy_addr_type" : "тип адреса идентификатора-источника"
,"copy_missing" : "error | do | skip" -- отсутствие в базе copy_email
-- error - по умолчанию - ошибка вызова
-- do - изменение ключей данных по командам *.copy будет записывать значение undef
-- skip - изменение ключей данных по командам *.copy выполнятся не будет - сохранятся прежние значения
,"copy_data" : { -- не обязательно, не совеместимо с copy_email
......
-- данные для копирования
-- позволяет иметь неизменный параметр datakey вынеся сюда сами данные
......
}
-- "режим" имеет следующие значения
-- режимы работы со значениями указанными непосредственно в вызове
-- "set" - полностью и безусловно заменить имеющиеся данные новыми
-- если значение присваивается элементу массива, и элемент ещё не существовал и не первый, то в массиве появится необходимое количество
-- элементов (со значением null), предшествующих присваемому
--
-- "update" - заменить имеющиеся данные новыми, только если указанный ключ уже есть
-- ("есть" это именно есть - null, пустая строка, пустой массив, пустой объект, находящиеся по указанному ключу - это "ключ есть"),
-- иначе изменение игнорируется. Поведение при присвоении не первому элементу массива аналогично set (при условии, что замена реально была
произведена)
--
-- "insert" - добавить данные, только если указанного ключа ещё нет
-- ("нет" это именно нет - null, пустая строка, пустой массив, пустой объект, находящиеся по указанному ключу - это "ключ есть"),
-- иначе изменение игнорируется. Поведение при присвоении не первому элементу массива аналогично set (при условии, что данные реально были
добавлены)
--
-- "merge" - "set" по каждому ключу нового значения "новое-значение" в существующее "ключ-данных", а именно:
-- * если имеющиеся данные - это объект и новое значение тоже объект, то каждый ключ и его величина из нового значения добавляются при
отсутствии
-- или его величина заменяют собой величину существующего такого же ключа в имеющихся данных, если ключ в них уже есть
-- * если данных по указанному ключу нет и новое значение - объект, то новое значение создаст объект по указанному ключу
-- * в других случаях вызов завершится ошибкой
--
-- "merge_update" - "update" по каждому ключу нового значения "новое-значение" в существующее "ключ-данных", а именно:
-- * если имеющиеся данные - это объект и новое значение тоже объект, то величина каждого ключа из нового значения заменяют собой величину
-- существующего такого же ключа в имеющихся данных. Ключи нового значения, отсутствующие в имеющихся данных игнорируются.
-- * если данных по указанному ключу нет и новое значение - объект, то новое значение будет проигнорировано
-- в других случаях вызов завершится ошибкой
--
-- "merge_insert" - "insert" по каждому ключу нового значения "новое-значение" в существующее "ключ-данных", а именно:
-- * если имеющиеся данные - это объект и новое значение тоже объект, то каждый ключ и его величина из нового значения добавляются при
отсутствии такого ключа в имеющихся данных. Ключи нового значения, уже существующие в имеющихся данных, игнорируются.
-- * если данных по указанному ключу нет и новое значение - объект, то новое значение создаст объект по указанному ключу
-- * в других случаях вызов завершится ошибкой
--
-- "push" - * если имеющиеся данные это массив и новое значение тоже массив, то содержимое массива нового значения добавляется в конец имеющегося массива
-- * если имеющиеся данные это массив и не массив, то новое значение добавляется в конец имеющегося массива
-- * если данных по указанному ключу нет и новое значение массив, то новое значение создаст массив по указанному ключу
-- * если данных по указанному ключу нет и новое значение не массив, то массив состоящий из одного нового значения будет присвоен указанному ключу
--
-- "unshift" - * если имеющиеся данные это массив и новое значение тоже массив, то содержимое массива нового значения добавляется в начало имеющегося массива
-- * если имеющиеся данные это массив и не массив, то новое значение добавляется в начало имеющегося массива
-- * если данных по указанному ключу нет и новое значение массив, то новое значение создаст массив по указанному ключу
-- если данных по указанному ключу нет и новое значение не массив, то массив состоящий из одного нового значения будет присвоен указанному ключу
--
-- "delete" - данные будут удалены, "значение" и "тип" игнорируются и должны или отсутствовать или быть пустыми
-- - если удалялся элемент массива и он был последним, то размер массива уменьшится на 1
-- - если удалялся элемент массива и он не был последним, то размер массива не уменьшится, а удаляемый элемент получит значение null
-- режимы, копирующие значения из другого ключа данных
-- "set.copy", "update.copy", "insert.copy", "merge_copy", "merge_update.copy", "merge_insert.copy", "push.copy", "unshift.copy" - работают аналогично
-- режимам без .copy, но значением является то, что хранится в указанном в третьем элементе "ключе-данных-из".
--
-- источником данных для копирования является подписчик указанный в copy_email или непосредственно данные указаные в copy_data или сам же подписчик указанный в email если ни одного copy_* не указано.
--
-- если копируемое значение не скаляр, а структура данных, то создаётся независимая копия структуры данных
-- "тип" не обязателен и предназначен для контроля соответствия "нового-значения" формату данных.
-- В данный момент поддерживается только тип данных "дата-время", так как неверно заданные данные этого типа могут вызвать ложные срабатывания/не срабатывания
-- в фильтре групп операции сравнения дат.
--
-- возможные значения "тип":
--
-- отсутствует - проверки не производятся
--
-- "" - проверки не производятся
--
-- null - проверки не производятся
--
-- "dt" - сокращение для dt:Ys
--
-- "dt:LR" - производится проверка и нормализация "значения" как даты для указанного диапазона точности от L до R,
-- - где L и R - символы Y M D h m s, задающие диапазон компонентов даты
-- - например, "dt:Ys" - дата от года до секунды, "dt:Mh" - дата от месяца до часа
-- - год должен всегда задаваться четырьмя цифрами
-- - остальные компоненты - одной или двумя и они будут автоматически нормализованы до двух цифр
-- - например, дата "1971-5-4 3:2:1" при типе "dt:Ys" станет "1971-05-04 03:02:01"
--
-- другие значения - вызов завершится с ошибкой
--
-- при указании типа данных "дата-время" кроме непосредственно даты, можно указывать время относительно текущего момента
-- используется тот же синтаксис, что и в универсально статистике stat.uni
--
-- current
-- current - 1 month
-- current:YD + 25 days
--
-- в ключ данных будет записан результат вычисления времени с указанной точностью
--
-- если точность указана разная одновременно и в типе (dt:YD), и в выражении (current:Yh), то используется точность из выражения current
--
-- если несколько ключей изменяются с использованием выражения current, то они все вычисляются от какого-то одного и того же времени, запомненного в начале вызова
--
-- при импортировании все вычисления current для всех строк импорта также используют какое-то одно и то же время, запомненное в начале импорта
--
-- внимательно изучите примеры в разделе "Общие замечания"
-- для управления участием указанного идентификатора в группах-списках с помощью псевдо-ключа данных "-group" используйте точное указание группы "-group.КОДГРУППЫ" и:
-- * режим "delete" для удаления из группы
-- * режим "set" и новое значение "1" для добавления в группу
-- * в других случаях вызов завершится ошибкой
-- для удаления ошибок доставки используйте ключ данных "member.error.error" и режим "delete", в других случаях вызов завершится ошибкой
-- для перевода подписчика в состояние "Требуется подтверждение внесения в базу" используйте ключ данных "member.lockconfirm", режим "set" и значение точно "1", в других случаях вызов завершится ошибкой
-- для работы с Данными прохождения триггера используйте @member.sequence_data@ для чтения и @member.sequence_data.store@ для записи
-- для работы с Источником создания используйте member.origin - можно указать как номер так и метку Источника
-- все прочие изменения по ключам данных "member.*" и "-group.*" в данный момент игнорируются, но могут стать ошибками в будущем, лучше не делайте их
-- если изменяемый ключ данных не существует, то он будет создан с учётом влияния "режима"
-- если не существует часть или весь путь изменяемого ключа данных, то все отсутствующие части пути также будут созданы.
-- в контексте создания не существующих частей пути, "не существует" - это действительно не существует, или существует, но равен null.
-- попытки использовать объект или скалярную величину как массив приведут к завершению вызова с ошибкой
-- попытки использовать массив или скалярную величину как объект приведут к завершению вызова с ошибкой
-- данные или изменяются/удаляются для всех указанных ключей (если не было ошибок) или не изменяются/удаляются вообще (при любой ошибке)
-- одновременное с созданием подписчика / внесением данных подписчика
-- добавление к нему дополнительных идентификаторов
-- аналогично последовательному вызову member.set и потом нужное число раз member.head.attach
-- но при данном использовании атомарно - или все действия по созданию/внесению и присоединению
-- завершаться успешно или же любая ошибка отменяет все изменения
--
-- режимы head_rule
--
-- error - отмена запроса с сообщением, что данный идентификатор непригоден
-- none - голова остается где была, запрос возвращает предупреждение
-- transplant - перенос головы от источника к приёмнику
-- decapitate - удалить голову head у источника
-- replace - перенести голову head от источника к приёмнику, а потом удалить голову email у приёмника
-- replace_same_type - перенести голову head от источника к приёмнику, заменив ею голову приёмника того же типа, что и head (если она есть и единственная по типу). Если у приёмника нет головы того же типа, что и head, выполняется режим transplant.
--
-- режим по умолчанию
--
-- для multi и single: error
-- для newbie: attach
--
-- обработка данных при слиянии срабатывает только для head_rule (multi или single в зависимости от присоединяемого идентификатора) = replace|replace_same_type|decapitate
"head_attach" : [ -- не обязательно
{ -- параметры аналогичны одноимённым из вызова member.head.attach
"head" : "дополнительный присоединяемый идентификатор"
,"head_addr_type" : "тип дополнительного присоединяемого идентификатора
,"newbie.confirm" : "режим подтверждения"
,"head_rule": { -- параметры, определяющие обработку голов при слиянии
"multi": error|none|transplant|replace|replace_same_type|decapitate -- для многоголовых пользователей
"single": error|none|transplant|replace|replace_same_type|decapitate -- для одноголовых
"newbie": attach|none|replace|replace_same_type - для новых, несуществующих идентификаторов (без голов)
},
,"data_rule": "обработка данных при слиянии" -- как в member.merge
}
.......
]
-- необязательный
,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )"
-- при "1" данные возвращаются как при запросе member.get c "datakey" : "*"
}
ответ
{
<общие поля>
,"newbie" : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу
,"member" : {
"id" : номер в базе,
"email" : "нормализованный идентификатор",
"addr_type" : "тип идентификатора"
}
-- если "return_fresh_obj" : "1"
-- данные от запроса "member.get" соответствующего адреса
}
Получить данные подписчика (ДК)¶
Обратите внимание, что в зависимости от того, что вы выбираете и имеются ли в ключе шаблоны, "данные для ключа" могут быть и скаляром, и массивом, и объектом, и null.
Обратите внимание, что значением для того, что было создано в модели АВО и называется там "вопрос с выбором" будет объект, а не массив. Ключами массива будут кода ответов, значениями - null.
Обратите внимание, что количество ошибок доставки имеет ключ member.error.error (совместимо со stat.uni), а не member.error как в АВО.
Системный ключ "member" и псевдо-ключ "-group", описывающий участие и дату внесения адреса в группах списка, описаны выше во вводной части раздела.
{
"action" : "member.get"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"with_stoplist" : 0|1|2 - В ключ member.stoplist добавляется информация о нахождении адреса в стоп-листах. Структура как у вызова email.get в member.stoplist
,"with_heads" : 0|1 - В ключ member.heads добавляется информация о всех головах адреса. Структура как у вызова member.head.list
,"missing_too" : 0|1 - Если 0, то ошибка при отсутствии такого подписчика. Если 1 и такой подписчик когда-то был, то возвращается оставшаяся информация (аналогично email.get) и, дополнительно, ключ "missing" : "1" для индикации, что такого подписчика всё же нет
-- один из способов указания интересующих ключей данных
-- или список ключей
,"datakey" : [
"ключ данных-1"
,"ключ данных-2"
.....
]
-- или один ключ
,"datakey" : "ключ данных"
-- или специальный вариант одного ключа для получения всех данных
,"datakey" : "*"
}
ответ
{
<общие поля>
-- при запросе со списком ключей
,"datakey" : {
"ключ данных-1" : данные для ключа-1
,"ключ данных-2" : данные для ключа-2
......
}
-- при запросе с одним ключом или с "*"
,"datakey" : данные для ключа
-- при запросе "*"
,"datakey" : {
данные для имеющихся ключей
}
-- если missing_too = 1
,"missing" : 0|1 - нет или есть всё адрес как подписчик
}
Получить набор данных (ДК)¶
Это специализированный вариант вызова member.get для чтения всех данных подписчиков, связанных с конкретным набором данных
{
"action" : "member.get"
,"email": "номер набора данных"
,"addr_type" : "dataset"
-- один из способов указания интересующих ключей данных, по умолчанию - '*'
-- ключи member и -group недоступны, так как у каждой головы они свои и уже и так имеются в ответе в heads
-- или список ключей
,"datakey" : [
"ключ данных-1"
,"ключ данных-2"
.....
]
-- или один ключ
,"datakey" : "ключ данных"
-- или специальный вариант одного ключа для получения всех данных
,"datakey" : "*"
}
ответ
{
<общие поля>
"dataset" => "номер набора данных" -- member.dataset
,"data" => {
-- общие данные. все или только указанные в datakey
}
,"heads" => [ -- список номеров всех идентификаторов (member.id) связанных с этим набором данных
123
,4567
....
],
,"head" => { -- информация о каждом идентификаторе
-- данные аналогичны таким же полям системной анкеты member и описаны выше
"номер идентификатора-1"
=> {
"id" => номер идентификатора
,"dataset" => номер набора данных
,"addr_type" => "тип идентификатора",
,"email" => "идентификатор",
,"domain" => "домен идентификатора для email"
,"haslock" => "все блокировки идентификатора"
,"lockremove" => "состояние удаления"
,"create" => { -- информация о создании
'time' => "дата (Ys)"
'host' => "источник"
}
,"update" => { -- информация об изменении по АПИ
'time' => "дата (Ys)"
'host' => "источник"
}
,"import" => { -- информация об изменении при импорте
'time' => "дата (Ys)"
}
,"-group" => {
-- участие в группах-списках
}
,"confirm' => {
-- информация о подтверждении регистрации данного идентификатора
},
,"error" => {
-- информация об ошибках доставки для данного идентификатора
}
,"stoplist" => [
-- нахождение данного идентификатора в стоп-листах
-- структура как у вызова email.get
]
}
,"номер идентификатора-2' => {
......................
}
}
}
Создать подписчика / Установить ответы подписчика (АВО)¶
При отсутствии адреса в базе он создаётся автоматически.
Изменяются только указанные данные.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error точно в "0" удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки, если таковая была.
Установка member.lockconfirm точно в "1" переводит подписчика в состояние "Требуется подтверждение внесения в базу".
{
"action" : "member.set"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"source" : "ip-адрес оригинального запроса"
-- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос
,"if_exists" : "error|must|update|overwrite" -- не обязательно, по умолчанию существующий подписчик обновляется в режиме overwrite, а отсутствующий - создаётся.
-- правила учёта есть или нет подписчик
-- error - ошибка при наличии подписчика в базе
-- must - ошибка при отсутствии адреса в базе
--
-- правила изменения ответов анкетных данных. не действует на псевдоанкету "-group"
-- update - если ответ на изменяемый вопрос уже есть, то он остаётся неизменным
-- overwrite - ответ заменяется/создаётся в любом случае
,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)"
-- используется только при внесении email-адресов
-- действует лимит внесения без подтверждения
-- подробнее описанный в вызове member.import
,"newbie.letter.confirm" : "номер шаблона информационного письма"
-- высылается, если новый адрес до этого отсутствовал в базе и внесён с необходимостью подтверждения
-- если параметр пуст или отсутствует, то ничего выслано не будет,
-- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm
-- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт
-- продолжит вносить уже с подтверждением, и этот параметр будет использоваться
-- при внесении номеров телефонов никакие уведомления не высылаются
-- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации
,"newbie.letter.no-confirm" : "номер шаблона информационного письма"
-- высылается, если новый адрес до этого отсутствовал в базе и внесён с без необходимости подтверждения
-- если параметр пуст или отсутствует, то ничего выслано не будет
-- при внесении номеров телефонов никакие уведомления не высылаются
-- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации
,"obj" : {
-- управление анкетными данными подписчика
-- ank - код анкеты
-- quest - код ответа
-- val - значение ответа или код ответа, если вопрос с выбором из списка
-- значение не указанных вопросов не меняется
"ank1" : {
-- установка значения ответа обычного вопроса
"quest" :"val"
-- установка значения ответа для вопроса с типом "дата" в зависимости от заданной в анкете точности
"quest" : "YYYY-MM-DD"
"quest" : "YYYY-MM-DD hh"
"quest" : "YYYY-MM-DD hh:mm"
"quest" : "YYYY-MM-DD hh:mm:ss"
-- установка значения ответа у вопроса с множественным выбором
,"quest" : [ "val", "val", "val"....]
-- установка значения ответа у вопроса с выбором одного из нескольких - всё равно массив
,"quest" : [ "val" ]
-- удаление ответа
,"quest" : null
}
,"ank2" : {
..............
}
-- управление участием указанного идентификатора в группах-списках с помощью псевдо-анкеты
-- параметр "if_exists" не влияет на эту анкету
,"-group" : {
-- 0 - удалить из группы-списка
-- 1 - добавить в группу-список
-- участие в не перечисленных группах не меняется
"id1" : "(0|1)"
,"id2" : "(0|1)"
.............
,"idN" : "(0|1)"
}
}
-- необязательный
,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )"
}
ответ
{
<общие поля>
,"newbie" : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу
-- если "return_fresh_obj" : "1"
данные от запроса "member.get" соответствующего адреса
}
Получить ответы подписчика (АВО)¶
{
"action" : "member.get"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"with_stoplist" : 0|1 - В анкету member добавляется stoplist с информацией о нахождении адреса в стоп-листах. Структура как у вызова email.get в member.stoplist
,"with_heads" : 0|1 - В анкету member добавляется heads с информацией о всех головах адреса. Структура как в member.head.list
,"missing_too" : 0|1 - Если 0, то ошибка при отсутствии такого подписчика. Если 1 и такой подписчик когда-то был, то возвращается оставшаяся информация аналогично email.get c учётом наличия datakey (есть error - структура, нет - набор полей) и, дополнительно, ключ "missing" : "1" для индикации, что такого подписчика всё же нет
}
ответ
{
<общие поля>
-- ответы на вопросы анкет
,"obj" : {
-- ank - код анкеты
-- quest - код ответа
-- val - значение ответа или код ответа, если вопрос с выбором из списка
"ank1" : {
-- обычный вопрос
"quest" : "val"
-- вопрос с множественным выбором
,"quest" : [ "val", "val", "val"....]
-- вопрос с выбором одного из нескольких - всё равно массив
,"quest" : [ "val" ]
}
,"ank2" : {
..............
}
-- псевдо-анкета, описывающая участие в группах-списках
,"-group": {
-- участие в группах-списках
}
}
-- если missing_too = 1
,"missing" : 0|1 - нет или есть всё адрес как подписчик
}
Удалить подписчика¶
Адреса и данные реально удаляются из базы !
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием того, как и какие адреса были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
В зависимости от параметра wipe вызов работает по-разному в случае наличия у подписчика нескольких идентификаторов.
При wipe = 0 (по умолчанию)
- Если у подписчика несколько идентификаторов, то этот вызов удаляет только указанный идентификатор, не трогая сам набор данных и другие идентификаторы.
При wipe = 1
- Подписчик по указанному идентификатору удаляется полностью - удаляются и все прочие его идентификаторы и связанный с ними набор данных.
При любом wipe
- Если удаляемый идентификатор единственный (последний), то вместе с ним удаляется и набор данных (тело без головы не живёт).
В отличии от member.head.detach возможно удаление единственного (последнего) идентификатора.
В отличии от member.head.detach генерируется триггерное событие "Подписчик удалён".
Удаление идентификатора приведёт к прекращению его обработки в триггерных последовательностях. Однако не сразу, а при очередной обработке событий, связанных с удалённым идентификатором.
Одновременно может выполняться только один такой запрос.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.delete"
,"wipe" : 0|1 -- способ удаления, по умолчанию 0
-- указание подписчиков одним из способов
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
или
,"list" : [
"идентификатор подписчика"
,"идентификатор подписчика"
........
]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный
или
,"group" : код группы участники которой будут удалены
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"group.filter" : [
фильтр отбора как у group.filter.set
]
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"stat.uni" : { -- адреса для обработки получаются из запроса универсальной статистики
-- подразумевается unique = 1
,"filter" : [ условие выборки как у запроса в вызове stat.uni ]
,"have" : [ не обязательно. условие отбора поле группировки в фильтре ]
,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ]
,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ "member.email" ]
}
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно
}
ответ
{
<общие поля>
-- для асинхронного запроса
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
-- для синхронного запроса
,"list" : {
"адрес-1" : 0|1 -- результат удаления - 1 - удалён, 0 - нет (например, адрес ошибочен или отсутствует)
,"адрес-2" : 0|1
.................
}
}
Объединение данных двух подписчиков¶
{
"action": "member.merge",
,"email": "идентификатор подписчика" -- подписчик, получающий данные
,"addr_type": email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно
,"head": "идентификатор подписчика" -- подписчик-источник данных
,"head_addr_type": email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора-источника. не обязательно
-- параметры, определяющие обработку голов при слиянии данных
,"head_rule": none|transplant|decapitate -- действие с головами
--
-- Если у подписчика-источника единственная голова, то при выполнении transplant, decapitate или replace
-- перестанет существовать подписчик - будет удалено его тело т.к. у тела должна быть хотя бы одна голова
--
-- none - ничего не делать
-- transplant - перенести голову head от источника к приёмнику
-- decapitate - удалить голову head у источника
-- replace - перенести голову head от источника к приёмнику, а потом удалить голову у приёмника, указанную в email
-- параметры, определяющие обработку данных при слиянии. не обязательно.
-- по умолчанию
-- level = 2
-- hasmiss = set - скопировать из источника ключ, отсутствующий в приёмнике
-- hashas = none - не трогать ключ, имеющийся у обоих
-- misshas = none - не копировать ключ, имеющийся только у источника
,"data_rule": {
"level" : 2 -- уровень иерархии (>=0), для которого выполняется слияние данных
-- по умолчанию - 2 (это коды вопроса в модели АВО или второй уровень элемента ключа данных)
-- режимы для разных ситуаций слияния ключей данных, для которых не описаны индивидуальные режимы в dk_rule
-- для случая, когда ключ есть в источнике и отсутствует в приёмнике
,"hasmiss": set|none|move -- по умолчанию set
-- set -- скопировать данные из источника в приёмник
-- none -- ничего не делать
-- move -- скопировать данные из источника в приёмник и потом удалить из источника
-- для случая когда ключ есть и в источнике и в приёмнике
,"hashas": none|delete|set|move|merge -- по умолчанию none
-- none -- ничего не делать
-- delete-- удалить данные из приёмника
-- set -- скопировать данные из источника в приёмник
-- move -- скопировать данные из источника в приёмник и потом удалить из источника
-- merge -- объединить данные источника с данными приёмника
-- для случая, когда ключ отсутствует в источнике и есть в приёмнике
,"misshas" : none|delete -- по умолчанию none
-- none -- ничего не делать
-- delete-- удалить данные из приёмника
-- значения, указанных здесь ключей данных, будут обработаны в соответствие с заданным именно для них режимом
"dk_rule": {
"ключ-данных-1" : "режим-1",
...
"ключ-данных-N" : "режим-N"
}
}
,"return_fresh_obj" : ....
}
ответ
Список идентификаторов¶
Выводится список всех идентификаторов и сопутствующая им информация для указанного пользователя
{
"action" : "member.head.list"
,"email" : "один из идентификаторов существующего пользователя"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
}
ответ
{
<общие поля>
,"list" : [
{
"email" : "идентификатор пользователя" -- email, номер телефона,....
,"addr_type" : "email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max" -- тип идентификатора
,"dataset" : "номер тела"
-- структуры состояния головы как описано в member.get
,"has_lock" : ...
,"lockerror" : ...
,"confirm" : { ... }
,"error" : { ... }
}
...
]
}
Присоединение идентификатора¶
К уже существующему пользователю, указанному в email, присоединяется идентификатор, указанный в head.
Присоединяемый идентификатор не должен быть связан с другим существующим пользователем.
Возможно присоединение идентификаторов во время импорта пользователей.
{
"action" : "member.head.attach"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"head" : "присоединяемый идентификатор"
,"head_addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max -- тип присоединяемого идентификатора. не обязательно, система сама распознает email или msisdn
,"head_origin" : "номер или метка Источника для member.origin" -- не обязательно
,"newbie.confirm": "подписчик head должен подтвердить внесение в базу (1|0)"
-- используется только при внесении email-адресов
-- действует лимит внесения без подтверждения
-- подробнее описанный в вызове member.import
}
ответ
Удаление идентификатора¶
При split= 0
*Идентификатор, указанный в email, удаляется от пользователя и становится более ни с кем не связан.
*Также прекращается участие указанного идентификатора в группах-списках, в которых он состоял.
При split = 1
*Идентификатор, указанный в email, удаляется от пользователя и становится самостоятельным пользователем.
*За ним остаётся участие в группах-списках, в которых он состоял.
Данные подписчика и другие идентификаторы остаются за пользователем, от которого удаляется идентификатор.
Статистика по действиям (участие в выпусках, доставки, переходы, чтения и их длительность и прочее) остаётся за удалённым идентификатором в части его действий и за пользователем, от которого удаляется идентификатор в оставшейся части.
После удаления у пользователя, от которого удаляется идентификатор, должен остаться ещё хотя бы один другой идентификатор (для удаления всего пользователя есть member.delete).
В отличии от member.delete невозможно удаление единственного (последнего) идентификатора.
В отличии от member.delete не генерируется триггерное событие "Подписчик удалён".
Возможно удаление идентификаторов во время импорта пользователей.
{
"action" : "member.head.detach"
,"email" : "удаляемый один из идентификаторов существующего пользователя"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
,"split" : 0|1 -- создать из удаляемого самостоятельного пользователя. не обязательно. по умолчанию 0.
}
ответ
Замена идентификатора¶
К уже существующему пользователю, указанному в email, присоединяется идентификатор, указанный в head.
После чего идентификатор, указанный в email, удаляется от пользователя и становится более ни с кем не связан.
Этот вызов - аналог последовательного исполнения member.head.attach и member.head.detach, но является атомарным - любая ошибка полностью отменяет все изменения.
{
"action" : "member.head.replace"
,"email": "текущий идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип текущего идентификатора. не обязательно, система сама распознает email или msisdn
,"head" : "новый идентификатор"
,"head_addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max -- тип нового идентификатора. не обязательно, система сама распознает email или msisdn
,"head_origin" : "номер или метка Источника для member.origin" -- не обязательно
,"newbie.confirm": "подписчик head должен подтвердить внесение в базу (1|0)"
-- используется только при внесении email-адресов
-- действует лимит внесения без подтверждения
-- подробнее описанный в вызове member.import
}
ответ
Участие подписчика в группах-фильтрах¶
Списков групп-фильтров, в которых состоит подписчик. Участие в группах-списках и так известно через member.get.
Время работы вызова ограничено 300 секундами для учёта случая, когда есть много групп-фильтров со сложными условиями.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.where"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
-- не обязательно, ограничение проверки
,"group" : "код группы" -- одной
-- или
,"group" : [ "код группы", ... ] -- несколькими группами
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно
}
ответ
{
<общие поля>
,"list" : {
"адрес" : [ список кодов групп-фильтров в которые адрес входит ]
-- или
,"адрес" : null -- адрес не существует или синтаксически не верен
}
}
Список подписчиков¶
НЕ СОВМЕСТИМОЕ ИЗМЕНЕНИЕ С 17 ИЮЛЯ 2017 ГОДА - при result=response размер выдачи не более 1000 строк.
Если формат фильтра у группы group или заданный непосредственно в group.filter использует формат ДК с оператором has c параметром save, то в результатах вызова будут также результаты всех срабатываний save.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.list"
-- источник адресов, одно из трёх или вообще ничего (тогда по всем адресам вообще)
,"group" : "идентификатор группы"
-- или
,"group.filter" : [ фильтр отбора как у group.filter.set ] -- если не будет явно задан параметр addr_type, то подойдут адреса любых типов
-- для всех источников
,"addr_type": "тип выбираемых адресов подписчиков (email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max)"
-- при отсутствии определяется по типу адресов в указанной группе
-- если указан, то должен совпадать с типом адресов в группе, если и та указана
-- если не указан и не указана группа, то выбираются адреса любого типа
,"member.haslock" : "код" -- учёт состояния блокировки подписчика
-- пусто или отсутствует - не учитывать состояние блокировки. может ли получать сообщения
-- -1 - есть хоть какая-то блокировка - не может
-- 0 - нет блокировки - может
-- 1 - заблокирован так как отписался - не может
-- 2 - заблокирован так как не подтверждён - не может
-- 4 - заблокирован так как имеет фатальные ошибки доставки - не может
-- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указанных блокировок
--
-- формально этот параметр можно заменить дополнительными условиями в фильтре группы,
-- но его использование позволяет
-- * не меняя фильтры групп, узнавать сколько в ней всего участников и сколько из них могут получать письма
-- * не создавая группы, узнавать это же для всех свои адресов вообще
-- * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы
-- формат вывода, одно из трёх или вообще ничего
-- если формат вывода не используется, то выводится только идентификатор подписчика
,"format" : "идентификатор формата вывода" -- использование существующего формата
-- или
,"format" : [ -- указание формата в формате Анкета-Вопрос-Ответ прямо в запросе
-- специальная пара aid=member с qid=head.list позволяют получить в ответе список всех голов как в результате member.head.list
{ "anketa" : "код анкеты", "quest" : "код вопроса" }
........
]
-- или
,"format" : [ -- указание объекта Формат прямо в запросе
-- запрос просто по ключу данных
-- специальный ключ данных "member.head.list" позволяет получить в ответе список всех голов как в результате member.head.list
{ "datakey" : "ключ данных" }
-- запрос по ключу из результатов работы save в условии has используемого в вызове фильтра
-- результат null, если save не срабатывал или массив из результатов получения данных по
-- ключу данных относительно каждого значения из результата save с указанным кодом
,{ "save" : "код сохранения", datakey" : "относительный ключ данных" }
-- запрос значение меток из условий фильтрации
,{ "label" : "имя метки" }
........
]
,"sort" : "коданкеты.кодвопроса"
-- сортировка по указанному полю (не важно будет оно в итоговых данных или нет)
-- если параметр отсутствует или пуст, то выдача идёт в неком внутреннем порядке
-- сортировка по произвольной анкете/полю может резко увеличить время выполнения запроса,
-- так как для его выполнения надо отсортировать всю выборку,
-- но сортировка по ниже перечисленным полям практически не влияет на скорость выполнения
-- member.id
-- member.email - при идентификатору подписчика
-- member.domain - сортировка по домену и внутри него по адресу
-- - при выборке телефонов эквивалентно просто member.email
-- member.create.time - дата и время создания
-- member.update.time - дата и время последнего изменения данных по API
-- member.import.time - дата и время последнего изменения данных подписчика при импорте
,"sort.order" : "asc|desc" -- направление сортировки asc - по возрастанию (по умолчанию), desc - по убыванию
,"result" : [ способ возврата результата. Смотрите общее описание ]
-- заголовок списка
-- если параметр отсутствует или пуст, то такая строка не добавляется
,"caption" : "id" -- в первой строке выводить заголовок, содержащий для каждой колонки код анкеты и вопроса
-- или
,"caption" : "name" -- в первой строке выводить заголовок, содержащий для каждой колонки названия анкеты и вопроса
-- или
,"caption" : [ "имя 1", "имя 2" ... ] -- в первой строке выводить заголовок, содержащий собственные указанные названия
,"answers" : "decode" -- для АВО вместо кодов ответов на вопросы в выбором возвращать значения.
-- неизвестные кода возвращаются как есть
,"answers" : "unroll" -- для ДК для ключей совпадающих с вопросам анкет с типом 1m или nm вместо объекта соответствуюшего
-- структуре хранения таких значений возвращается скаляр с кодом ответа для 1m, и массив с кодами ответов для nm
,"answers" : "decode" -- для ДК подразумевает unroll и, далее, значения ответов как для ABO
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно
---- дополнительные параметры запроса зависящие от result
-- *НЕ СОВМЕСТИМОЕ ИЗМЕНЕНИЕ С 17 ИЮЛЯ 2017 ГОДА*
-- ДО 17 ИЮЛЯ 2017 ГОДА
-- для response
,"page" : "номер страницы" -- при отсутствии выдаётся весь список. Должны быть указаны оба параметра или ни одного
,"pagesize": "размер страницы"
-- ПОСЛЕ 17 ИЮЛЯ 2017 ГОДА
-- для response
,"page" : "номер страницы" -- при отсутствии выдаётся 1000 строк
-- должны быть указаны оба параметра или ни одного
-- если размер страницы больше 1000, то ошибка
,"pagesize": "размер страницы"
}
ответ
{
<общие поля>
-- для result != response
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
-- для result = response
,"order" : [ -- описание порядка колонок выводимых результатов
{
anketa : код анкеты
,anketa.name : название анкеты
,quest : код вопроса
,quest.name : название вопроса
}
....
]
,"list" : [ -- по одной записи для каждого адреса
[ значения запрошенных полей в порядке, указанном в параметре ответа order ]
,[ значения запрошенных полей в порядке, указанном в параметре ответа order ]
,[ значения запрошенных полей в порядке, указанном в параметре ответа order ]
.....
]
,"save" : { -- только при result=response
"aдрес" : {
результат (если таковой был) работы save в условии has фильтра
В описании фильтра формата КД описано когда и чем это полезно
}
}
,"label" : { -- только при result=response
"aдрес" : {
список сработавших меток и их значений
В описании фильтра формата КД описано когда и чем это полезно
}
}
}
Специальный фильтр по количеству голов у подписчика¶
{ -- ограничение по количеству голов. один раз
"a" : "size(member.heads)"
,"op" : "<|<=|==|!=|>=|>"
,"v" : "количество голов" -- >= 1
}
Специальный фильтр по типу голов имеющихся у подписчика¶
{ -- ограничение по типу голов. можно несколько раз
"a" : "member.addr_type"
,"op" : "eq"
,"v" : "тип головы" -- email,msisdn,push,viber....
}
Выборка других голов подписчика¶
С использованием указываемого вы вызове формата format.
{
"action" : "member.list"
,"addr_type" : "xxxx" -- обязательно, не "any"
,"group|group.filter" : .... -- не обязательно
,"format" : [
.......
{
'datakey' : "member.head.email" | "member.head.id" | "member.head.addr_type" | "member.head.origin"
,"addr_type" : "xxxx" -- не обязательно. интересующий тип адресов
-- все member.head.* или без addr_type или с addr_type
,"outer" : 0|1 -- не обязательно. по умолчанию 0
-- для одинаковых addr_type значения outer должны быть одинаковы
-- возможность отсутствия такого типа головы у тела
-- 0 - должна быть
-- 1 - может не быть, будет выбрано null
}
.......
]
}
Примеры:
Выбрать головы типа email и к ним данные других голов для тел у которых есть головы email и какие-то другие головы (возможно тоже email)¶
{
"action":"member.list"
,"addr_type":"email"
,"format":[
{ "datakey" : "member.email" }
,{ "datakey" : "member.head.id" }
,{ "datakey" : "member.head.addr_type" }
,{ "datakey" : "member.head.email" }
]
}
Выбрать головы типа email и к ним данные других голов для тел у которых есть головы email¶
Если других голов не одна, то будет несколько строк в ответе - для всех сочетаний
{
"action":"member.list"
,"addr_type":"email"
,"format":[
{ "datakey" : "member.email" }
,{ "datakey" : "member.head.id" ,"outer" : 1 }
,{ "datakey" : "member.head.addr_type" ,"outer" : 1 }
,{ "datakey" : "member.head.email" ,"outer" : 1 }
]
}
Выбрать головы типа email и к ним данные про головы pushapp того же тела когда у тела есть и email и pushapp¶
Если других голов не одна, то будет несколько строк в ответе - для всех сочетаний
{
"action":"member.list"
,"addr_type":"email"
,"format":[
{ "datakey" : "member.email" }
,{ "datakey" : "member.head.id" ,"addr_type" : "pushapp" }
,{ "datakey" : "member.head.addr_type" ,"addr_type" : "pushapp" }
,{ "datakey" : "member.head.email" ,"addr_type" : "pushapp" }
]
}
Выбрать головы типа email и к ним данные про головы pushapp того же тела когда у тела есть email и, возможно, pushapp¶
Если других голов не одна, то будет несколько строк в ответе - для всех сочетаний
{
"action":"member.list"
,"addr_type":"email"
,"format":[
{ "datakey" : "member.email" }
,{ "datakey" : "member.head.id" ,"addr_type" : "pushapp" ,"outer" : 1 }
,{ "datakey" : "member.head.addr_type" ,"addr_type" : "pushapp" ,"outer" : 1 }
,{ "datakey" : "member.head.email" ,"addr_type" : "pushapp" ,"outer" : 1 }
]
}
Выбрать головы типа email и к ним данные про головы pushapp того же тела и про головы umid того же тела когда у тела есть и email и pushapp и umid¶
Если голова pushapp одна и umid одна, то в ответе одна строка
Если чего-то не одна, то в ответе все сочетания разных pushapp и umid
{
"action":"member.list"
,"addr_type":"email"
,"format":[
{ "datakey" : "member.email" }
,{ "datakey" : "member.head.id" ,"addr_type" : "pushapp" }
,{ "datakey" : "member.head.addr_type" ,"addr_type" : "pushapp" }
,{ "datakey" : "member.head.email" ,"addr_type" : "pushapp" }
,{ "datakey" : "member.head.id" ,"addr_type" : "umid" }
,{ "datakey" : "member.head.addr_type" ,"addr_type" : "umid" }
,{ "datakey" : "member.head.email" ,"addr_type" : "umid" }
]
}
Количество подписчиков¶
Расчёт быстр, если ведётся по "всем", по группам-спискам, по группам-фильтрам, состоящим из групп-списков.
Расчёт по группе-фильтру может быть долог - в зависимости от сложности фильтра и общего числа подписчиков.
По умолчанию вызов синхронный. Используйте sync = 0, чтобы сделать его асинхронным.
Для групп-сообществ ВК ответ немного другой для получения дополнительной информации про сообщество.
Если ответ может быть получен из кэша и он там есть, то ответ будет сообщен сразу и асинхронный запрос не начнётся.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.list.count"
-- источник адресов, одно из двух или вообще ничего (тогда по всем адресам вообще)
,"group" : "идентификатор группы"
-- или
,"group.filter" : [ фильтр отбора как у group.filter.set ]
-- для всех источников
,"addr_type": "тип выбираемых адресов подписчиков (email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max)"
-- при отсутствии определяется по типу адресов в указанной группе
-- если указан, то должен совпадать с типом адресов в группе, если и та указана
-- если не указан и не указана группа, то выбираются адреса любого типа
,"member.haslock" : "код" -- учёт состояния блокировки подписчика
-- пусто или отсутствует - не учитывать состояние блокировки. может ли получать сообщения
-- -1 - есть хоть какая-то блокировка - не может
-- 0 - нет блокировки - может
-- 1 - заблокирован так как отписался - не может
-- 2 - заблокирован так как не подтверждён - не может
-- 4 - заблокирован так как имеет фатальные ошибки доставки - не может
-- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указанных блокировок
--
-- формально этот параметр можно заменить дополнительными условиями в фильтре группы,
-- но его использование позволяет
-- * не меняя фильтры групп, узнавать сколько в ней всего участников и сколько из них могут получать письма
-- * не создавая группы, узнавать это же для всех свои адресов вообще
-- * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы
,"cache" : { параметры кэширования }
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно
,"with_minmax" : 0|1 - дополнительно вернуть информацию о минимальных и максимальных номерах подписчиков
}
ответ
{
<общие поля>
-- для асинхронного запроса
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
-- также будет содержать копию ответа obj
-- для синхронного запроса не по сообществу ВК
,"obj" : {
-- общая статитстика
"total" : всего подписчиков
,"active" : количество подписчиков, которые могут участвовать в рассылках писем или смс
,"locked" : уникальное количество заблокированных - не могут быть в рассылке
-- подробности по причинам блокировок (у одного подписчика может быть больше одной блокировки)
,"locked.unsubscribed" : в том числе заблокированные, так как отписались
,"locked.confirm" : в том числе заблокированные, так как не подтвердили внесение в базу
,"locked.stoplist" : в том числе заблокированные, так как находятся в стоп-листе
,"locked.hardbounced" : в том числе заблокированные, так как имеют фатальные ошибки доставки
-- и разбивка по типам адресов
,"total.email" : всего именно email
,"total.msisdn" : всего именно телефонов
,"total.viber" : всего именно Viber-номеров
,"total.csid" : всего именно клиентских идентификаторов
,"total.push" : всего именно push-подписок
,"total.vk" : всего именно vk-подписок
,"total.tg" : всего именно tg-подписок
,"total.pushapp" : всего именно pushapp-подписок
,"total.max" : всего именно max-подписок
,"total.vknotify" : всего именно vknotify-подписок
,"active.email" : способных получать именно адреса
,"active.msisdn" : способных получать именно телефоны
,"active.viber" : способных получать именно viber-номера
,"active.push" : способных получать именно push-подписки
,"active.tg" : способных получать именно tg-подписки
,"active.vknotify" : способных получать именно vknotify-подписки
,"active.pushapp" : способных получать именно pushapp-подписки
,"active.max" : способных получать именно max-подписки
-- минимальный и максимальный номер подписчика
-- при with_minmax :1
-- позволяет организовать перебор подписчиков не малоэффективным способом постраничным first/skip,
-- а эффективным - по диапазонам member.id
,"id_min" : число | null
,"id_max" : число | null
,"id_min.email" : число | null
,"id_min.msisdn" : число | null
,"id_min.csid" : число | null
,"id_min.push" : число | null
,"id_min.umid" : число | null
,"id_min.vk" : число | null
,"id_min.viber" : число | null
,"id_min.tg" : число | null
,"id_min.vknotify" : число | null
,"id_min.pushapp" : число | null
,"id_min.max" : число | null
,"id_max.email" : число | null
,"id_max.msisdn" : число | null
,"id_max.csid" : число | null
,"id_max.push" : число | null
,"id_max.umid" : число | null
,"id_max.vk" : число | null
,"id_max.viber" : число | null
,"id_max.pushapp" : число | null
,"id_max.tg" : число | null
,"id_max.vknotify" : число | null
,"id_max.pushapp" : число | null
,"id_max.max" : число | null
-- при подсчёте по всем
,"active.vk" : способных получать именно vk-подписки
,"confirmed.vk" : подтвердивших vk-подписки
}
-- для синхронного запроса по сообществу ВК
,"obj" : {
"member" : участников сообщества
,"total" : имеют в ВК разрешение на получение сообщений
,"active" : доступны для рассылки vk_DDDD
,"confirmed" : подтвердили желание получать сообщения
,"locked.hardbounced" : с ошибками доставки
,"locked.unsubscribed" : отписавшиеся от сообщений
,"left" : покинувшие сообщество
}
}
Внесение списка подписчиков¶
Вызов предназначен для массового внесения/изменения данных подписчиков на основе данных, указанных в самом вызове или получаемых по указанной ссылке из внешних источников.
Внешние источники могут быть как традиционные (http,https,ftp,ftps,sftp), так и специальные Google Big Query, Siebel, amoCRM, Bitrix24.
Вызовmember.import.probeпредназначается для проверки того, что думает система импорта о ваших входных данных.
В ответ будет сообщено, как произошло авто-определение кодировки (charset), разделителя столбцов, определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких анкет приписаны столбцы данных.
Если вы знаете заранее ответы на эти вопросы, то можете сразу указать эти данные при вызове: тогда они будут иметь приоритет над авто-определением системы.
Вызовmember.importреально импортирует данные. Описанные выше параметры будет определены автоматически, если их не указать сразу при вызове.
Вызов member.import асинхронный- получение положительного ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта - он может не состоятся из ошибок, возникших позже. Следить за его исходом можно по возвращаемому номеру асинхронного запроса.
Обратите внимание:Все возможные проблемы (фатальные или нет - смотрите по cannot_import), связанные именно с импортом (настройки, данные) при вызове member.import.probe сообщаются только через параметр warnings. А параметр errors служит для сообщения о проблемах вызова только с точки зрения API. При вызове же самого импорта, не фатальные ошибки остаются по-прежнему в warnings, а фатальные переносятся в errors. Это может выглядеть не логично, но это так из-за назначения вызова member.import.probe - предупредить вас о возможных ошибках, а не выполнять само импортирование.
Вызов позволяет импортировать данные модели КД при использовании источника данных в формате JSON-объект.
Вызовmember.importсохраняет отчёты о строчках, которые он не смог обработать. Имена файлов с отчётами можно получить из трекера.
Имеется два вида импорта:
Обычный
Данные вносятся в базу, создаются отсутствующие подписчики, внесённые данные доступны до момента удаления подписчика и могут использовать в условиях группах-фильтрах отбора сегментов.
Этот вид импорта используется по умолчанию и подходит, если данные должны храниться долговременно.
В зависимости от количества вносимых адресов и объёма данных этот импорт может быть относительно не быстр.
Импорт Телеграм
Это обычный импорт, но требуется:
- указать тип адресов
addr_type : tg - указать обязательный параметр
basegroup.id-- код базовой группы телеграм-бота - в колонке
member.tgуказывать номера пользователей в Телеграм (номера, не имена) - при желании использовать специальную колонку
/statusдля указания как вносить подписчиков - колонка отсутствует или содержит1,activeили пусто - подписчик добавляется как активный, всё прочее - как отписанный
Экспресс-Импорт
Этот вид импорта предназначен для очень быстрого (сотни тысяч в минуты) внесения реестров с адресами и данными персонализации, которые, в последствии, можно использовать в выпусках рассылок.
В отличии от обычного импорта эти данные хранятся и управляются отдельно, не становясь частью данных подписчика.
Если по каким-то причинам для выпуска рассылок по реестру не используется Экспресс-выпуск, а работа ведётся по сценарию "Импортировать данные, а потом сделать по ним выпуск", то использование Экспресс-импорта вместо обычного импорта как раз то, что лучше всего подходит для этого.
Внесённые в Экспресс-импорте подписчики и их данные сохраняются в отдельную новую группу-список, всегда создаваемую автоматически. Её название и, при желании, код можно указать в задании Экспресс-импорта.
В дальнейшем, именно по этой группе надо выпускать рассылки.
Группа, созданная при Экспресс-импорте ведёт себя в целом как обычная группа. С ней можно выполнять действия подсчёта количества адресов, получения списка, очистки списка, удаление группы, создания снимка.
Однако, такая группа не может участвовать в условиях отбора у групп-фильтров.
Отличить её можно по параметру expimp в group.list и group.get. Дополнительно, group.get, вызванный для одной группы, возвращает параметр caption для понимания структуры данных, а также count с количеством мемберов, например:
Внесённые данные хранятся 30 дней с момента последнего использования в выпуске, а если выпусков по группе не было, то 30 дней с момента внесения.
Для того, чтобы обычный импорт стал Экспресс-импортом достаточно указать в вызове member.import параметр "express": 1.
Обработку импорта прекратить вызовом track.set
Вызов импорта
{
"action" : "member.import"
или
"action" : "member.import.probe"
** данные импортирования
,"addr_type": "тип вносимых адресов подписчиков (email|msisdn|viber|csid|tg|vknotify|pushapp|max)"
,"origin" : "номер или метка Источника для member.origin" -- не обязательно
-- для заполнение member.origin новых подписчиков
-- если в данных импорта есть колонка member.origin, то она имеет приоритет
-- и этот параметр бесполезен
и одни из источников данных:
,"users.list": адреса и данные для импортирования -- непосредственно в JSON, CSV или XSLX
-- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска"
,"encoding" : "base64" -- не обязательно.
-- пусто или отсутствует - данные в users.list представлены непосредственно
-- base64 - данные в users.list закодированы в base64
или
,"users.url": "URL данные для импортирования"
-- Данные забираются в момент вызова для member.import.probe и в момент начала импортирования для member.import
-- При оформлении импорта как действия по расписанию не забудьте, что эту ссылку можно кастомизировать
-- временем и указать количество и интервал попыток получения данных. Подробнее в разделе "Замечания"
-- === Внешние ссылки http / https / ftp / ftps / sftp или из хранилища загрузок rfs://upload/путь-до-файла
-- По ссылке ожидается файл в котором находятся список адресов и данных для импортирования.
-- Но, если ссылка заканчивается на "/", то появляется возможно указать дополнительные параметры импорта
-- Сначала запрашивается json-файл для дополнительный параметров импорта URL/request.json
-- Его файла нет, то это ошибка
-- Потом запрашивается файл с данными для импорта URL/data.EXT, а если его не получить, то URL/import.EXT
-- где EXT это параметр content_type из request.json, а при его отсутствии - csv
-- === Siebel
-- Для запросов по SOAP (например, к Siebel) схемы soap:// и soaps:// - обратитесь в Службу поддержки
-- для получения дополнительной информации
-- === Google Big Query
-- Для запросов из Google Big Query настройте внешнюю аутентификация для схемы gbd:// (описано в вызовах authext.*)
-- Данные получаются полной выборкой из указанной в url вида gbd://authext:AUTHEXT_ID@DATASET_ID/TABLE_ID таблицы.
-- При использовании схемы gbd:// обязательно должно быть указано описание получаемых столбцов через параметр caption (описан ниже)
-- === amoCRM
-- Для получения данных из amoCRM настройте внешнюю аутентификацию для типа amocrm и укажите источником адресов ссылку вида
--
-- amocrm://authext:AUTHEXT_ID@/
--
-- или с указанием дополнительных полей для внесения
--
-- amocrm://authext:AUTHEXT_ID@/?fields=phone,name
-- === Bitrix24
-- Для получения данных из Bitrix24 настройте внешнюю аутентификацию для типа bitrix24 и укажите источником адресов ссылку вида
--
-- bitrix24://authext:AUTHEXT_ID@/
--
-- или вот так пока у вас настроена работа только с одним bitrix24
--
-- bitrix24:///
--
-- или с ограничение списка разделов откуда выбирать адреса - company,lead,contact (по умолчанию изо всех)
--
-- bitrix24://authext:AUTHEXT_ID@/?list=company,contact
или
,"uid": "идентификатор уже загруженных данных"
-- возвращается после первого вызова member.import.probe, используется далее вместо самих данных
** прочие параметры
,"express" : 0|1 - признак Экспресс-Импорта
,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )"
-- указание кодировки символов не обязательно - работает автоопределение
-- для XLSX и JSON смысла не имеет
-- известная особенность - импорт CSV без явного указания кодировки
-- если в первых нескольких килобайтах реестра нет ни одной русской буквы, то автоопределение
-- считает, что это cp-1251. Потом выясняется, что клиент всё же использовал utf-8.
-- редко, но так бывает. Поэтому указывайте кодировку для CSV всё же явно.
,"separator": "разделитель символов ("," | ";" | "|" | "t")", -- где t - табуляция
-- не обязательно - работает автоопределение
-- для XLSX и JSON смысла не имеет
,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )"
,"basegroup.id" -- обязательный код базовой группы телеграм-бота для импорта Телеграм, для остальных - игнорируется
** явное описание столбцов для модели АВО (не обязательны)
,"caption": [ -- по порядку следования столбцов в данных, приписывают каждый столбец одному вопросу одной анкеты
-- приоритетнее, чем описание из первой строки данных для импортирования
-- обязателен при получении данных из Google Big Query
-- при addr_type = email колонка с адресом - это анкета "member" вопрос "email"
-- при addr_type = msisdn колонка с номером телефона это анкета "member" вопрос "cellphone"
-- при addr_type = viber колонка с номером viber - это анкета "member" вопрос "viber"
-- при addr_type = csid колонка с клиентским идентификатором - это анкета "member" вопрос "csid"
-- при addr_type = tg колонка с клиентским идентификатором - это анкета "member" вопрос "tg"
-- при addr_type = vknotify колонка с клиентским идентификатором - это анкета "member" вопрос "vknotify"
-- при addr_type = pushapp колонка с клиентским идентификатором - это анкета "member" вопрос "pushapp"
-- при addr_type = max колонка с клиентским идентификатором - это анкета "member" вопрос "max"
{
"anketa": "id анкеты",
"quest": "id вопроса в анкете",
или
"ignore": "1" -- игнорировать столбец
-- вычислять при внесении. Содержимое колонки не заменит имеющиеся данные, а будет прибавлено к ним.
-- прибавление - целочисленное. всё что не похоже на числа считается нулём.
-- это НЕ конкатенация строчек
--
-- для задания через первую строку данных для импортирования добавьте знак "=" перед названием колонки
"calc" : 1
или
"/status" : "0|1|active|" -- только для Телеграмм. колонка отсутствует или содержит 1, active или пусто - подписчик добавляется как активный, всё прочее - как отписанный
},
......
]
** явное описание столбцов для модели КД (не обязательны)
,"caption": [ -- по порядку следования столбцов в данных. Приписывают каждый столбец одному вопросу одной анкеты
-- приоритетнее, чем описание из первой строки данных для импортирования
-- при addr_type = email колонка с адресом - это member.email
-- при addr_type = msisdn колонка с номером телефона - это member.cellphone
-- при addr_type = viber колонка с номером viber - это member.viber
-- при addr_type = csid колонка с клиентским идентификатором - это member.csid
-- при addr_type = tg колонка с клиентским идентификатором - это анкета "member" вопрос "tg"
-- при addr_type = vknotify колонка с клиентским идентификатором - это анкета "member" вопрос "vknotify"
-- при addr_type = pushapp колонка с клиентским идентификатором - это анкета "member" вопрос "pushapp"
-- при addr_type = max колонка с клиентским идентификатором - это анкета "member" вопрос "max"
{
"datakey": "ключ данных колонки", -- как в member.set
"mode" : "режим внесения", -- как в member.set
"type" : "тип данных", -- как в member.set
"autodetect" : 0|1 -- не обязательно. пытаться автоматически преобразовывать вносимое значение-строку
-- по умолчанию: 1 - для ключей base.*, 0- для прочих
--
-- если включено и существуют анкета и в ней вопрос с id как в datakey
-- и это вопрос с выбором, и вносимое значение не подходит ни под один
-- код ответа, то попробовать найти код ответа. Нужно считать, что вносимое значение
-- - это название ответа в вопросе, если значение не подойдёт и не под одно название,
-- то строка не будет внесена с ошибкой "неизвестный ответ"
--
-- например, для вопроса Пол с ответами "Мужской" - "m" и "Женский" - "w" будет
-- при внесении будут пониматься значения m и w, но и Мужской (преобразуется в m)
-- и Женский (преобразуется в w)
--
-- также, при указании autodecet в строке можно указать несколько ответов (названий
-- ответов) для вопроса с множественным выбором в том же формате, что и при АВО
-- - через вертикальную черту. например "x1|x2|x4"
или
"ignore": "1" -- игнорировать столбец
-- вычислять при внесении. Содержимое колонки не заменит имеющиеся данные, а будет прибавлено к ним.
-- для задания через первую строку данных для импортирования добавьте знак "=" перед названием колонки
"calc" : 1
или
"/status" : "0|1|active|" -- только для Телеграм, колонка отсутствует или содержит 1, active или пусто - подписчик добавляется как активный, всё прочее - как отписанный
},
......
]
** пробный импорт
,"action": "member.import.probe",
** импорт
,"action": "member.import",
,"if_exists" : "error|must|ignore" -- не обязательно, по умолчанию существующий подписчик обновляется, а отсутствующий - создаётся
-- error - ошибка при наличии подписчика в базе
-- must - ошибка при отсутствии адреса в базе
-- ignore - игнорирование строки импорта при наличии подписчика в базе без сообщения об ошибке
,"newbie.confirm" : "подписчик должен подтвердить внесение в базу (1|0)",
-- по умолчанию - внесение без необходимости подтверждения подписчиком (0)
-- внесение email без подтверждения ограничено величиной member.noconfirm.rest
-- (узнать можно через sys.settings.get) при её исчерпании остальные адреса
-- вносятся с подтверждением.
-- если количество адресов в базе превышает member.tarif.limit, то величина member.noconfirm.rest
-- равна нулю, иначе она равна member.noconfirm.limit за вычетом количества уникальных email
-- адресов, внесённых в текущем месяце
-- на внесение номеров телефонов параметр newbie.confirm не влияет (они всегда вносятся без подтверждения)
,"auto_group" : {
-- автоматически создать группу-список для импортируемых адресов
-- или дополнить любую существующую группу-список импортируемыми адресами
-- для обычного импорта отсутствие всего параметра auto_group означает не создавать новую и не пополнять
-- существующую группу
-- наличие auto_group, но без id и без name, означает создание группы со стандартным кодом
-- и со стандартным названием
-- для Экспресс-импорта группа-список создаётся всегда и отсутствие всего параметра auto_group означает
-- только, что код и названия будут автоматические
-- указание в id существующей группы будет ошибкой
-- код созданной группы можно узнать, используя возвращаемый номер track.id и вызов track.get
"id" : "идентификатор группы-списка для пополнения"
-- при отсутствии такой группы она создаётся автоматически
-- если параметр пуст или отсутствует, то используется стандартный
-- код вида importYYYYYMMDDhhmmss или importexYYYYYMMDDhhmmss
,"name" : "название группы"
-- название для создаваемой группы
-- если параметр пуст или отсутствует, то используется стандартное "Внесены <дата-время импорта>"
},
,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список, указанную в auto_group перед началом импортирования
-- позволяет не дополнять группу, а полностью заменять её участников
--
-- сначала проверяются все возможные причины, по которым импорт может не начаться. Если они есть, то импорт заканчивается ошибкой и очистка не происходит
-- иначе импорт начинается с очистки списка участников, а внесение новых происходит только после этого
--
-- не путайте удаление адреса из списка участников с удалением адреса из базы - это разные вещи
--
-- при одновременном импортировании в одну группу несколькими вызовами, у которых хоть у одного clean_group=1, результат
-- зависит от порядка выполнения и может быть неожиданным. Для однозначного результата всегда выполняйте импорт с cleangroup=1
-- только по завершении всех предыдущих импортов в ту же самую группу и не запускайте новый импорт в такую группу до завершения текущего
-- Добавить/удалить импортируемые адреса в/из групп-списков
-- Не применимо
-- к Экспресс-Импорту - "express":1
-- если "no_member":1
--
-- Очерёдность
-- сначала удаляется из групп "member.group.remove"
-- потом, вне зависимости от результата remove, добавляются в "member.group.add"
-- дубли autogroup в member.group.add игнорируются
-- autogroup исполняется ПОСЛЕ remove/add
,"member.group.add" : [ код-группы-списка-1, код-группы-списка-2, .... ] -- не обязательно
-- группы-списки в которые добавить импортируемые адреса (не зависимо от того, поменял импорт данные или нет)
,"member.group.remove" : [ код-группы-списка-1, код-группы-списка-2, .... ] -- не обязательно
-- группы-списки из которых удалить импортируемые адреса (не зависимо от того, поменял импорт данные или нет)
,"head_attach" : { -- не обязательно
--
-- тонкая настройка правил присоединения голов (по аналоги с member.set / member.merge)
-- действует на все колонки member.head.attach одинаково.
--
"newbie.confirm" : "режим подтверждения"
,"head_rule": { -- параметры, определяющие обработку голов при слиянии
"multi": error|none|transplant|replace|replace_same_type|decapitate -- для многоголовых пользователей
"single": error|none|transplant|replace|replace_same_type|decapitate -- для одноголовых
"newbie": attach|none|replace|replace_same_type - для новых, несуществующих идентификаторов (без голов)
}
,"data_rule": "обработка данных при слиянии" -- как в member.merge
}
,"no_member" : 0|1 -- не создавать подписчика. не обязательно, по умолчанию 0 - создавать
-- специфическая настройка, что бы работал безопасный Экспресс-Выпуск по номерам адресов (описано в issue.send)
-- требуется что бы внести только адреса (и у них появится необходимый номер) без создания подписчика (который не требуется для Экспресс-Выпуска)
-- не поддерживается сочетание express и no_member.
-- не поддерживается сочетание no_member и auto_group.
-- в реестре должна быть только одна колонка
,"format" : " id-формата" -- дополнить данные каждого вносимого адреса данным из формата (игнорируется для КД пока форматы не получат поддержку КД)
-- отсутствие или пусто - не дополнять
,"sequence.event" : 0|1 -- будет ли внесение/изменение данных вызывать срабатывание событийных действий
-- отсутствие или пусто - вызова событий не будет
-- остановить и/или начать прохождение последовательности - аналог sequence.member.stop/start для участников импорта
-- касается всех участников импорта, вне зависимости поменялось у них что-то или нет
-- сначала для адреса останавливаются прохождения по тригерам sequence.stop
-- потом, вне зависимости от результата stop, запускаются прохождения по тригерам sequence.start
-- не применимо при Эксрпесс-Импорте
-- не применимо если no_member
,"sequence.stop" : [ номер-триггера-1, номер-триггера-2, .... ] -- не обязательно
,"sequence.start" : [ номер-триггера-1, номер-триггера-2, .... ] -- не обязательно
,"result" : [ способ возврата результата, смотрите общее описание ] -- данный вызов всегда асинхронный и способ "response" означает сохранение отчёта в хранилище отчётов
}
ответ
{
<общие поля>
-- только для member.import.probe
,"uid": "идентификатор уже загруженных данных"
,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )"
,"separator": "разделитель символов ("," | ";" | "|" | "t")"
,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )"
,"caption": [ -- поля конфигурации
{
-- при импорте по модели АВО для колонки которой найдено соответствие анкете/вопросу
"source": "исходное значение кода колонки из CSV/XLSX"
"name": "название анкета и вопроса",
"anketa": "id анкеты",
"quest": "id вопроса в анкете",
"quest.type" : "тип вопроса в анкете"
"quest.subtype" : "под-тип вопроса" -- если применимо к type
"quest.width" : "длина поля" -- если применимо к type
-- при импорте по модели АВО для колонки которой не найдено соответствие
"name": "неопределенное значение из элемента строки конфигурации или null",
-- при импорте по модели ДК
"datakey": "ключ данных колонки",
"mode" : "режим внесения",
"type" : "тип данных",
-- при импорте по модели ДК для колонки с динамическим ключом данных
"dynamic": "1",
-- для колонки, для которой конфигурации задано игнорирование
"ignore" : 1
-- для колонки, для которой конфигурации задано вычислять при внесении
"calc" : 1
}
]
,"rows" : [ -- данные первых 15 значащих строк разбитые по полям с учёном указанного разделителя
[ "колонка-1-строки-1" ,"колонка-2-строки-1" ,"колонка-3-строки-1" ]
,[ "колонка-1-строки-2" ,"колонка-2-строки-2" ,"колонка-3-строки-3"]
.......
]
,"cannot_import" : 0|1 -- может ли быть выполнен импорт с текущими параметрами запроса
-- 0 - может
-- 1 - нет
-- Именно этот параметр, а не описанный далее параметр warnings сигнализирует о возможности/невозможности импорта,
-- т.к. параметр warnings может содержать и не влияющие на запуск процесса импорта предупреждения - например, о том,
-- что в первых строках файла есть неверно указанные адреса подписчиков, что не говорит о том, что во всем
-- списке подписчиков будет так
,"warnings" : [ -- предупреждения о проблемах при анализе данных
-- в первую очередь проверяйте параметр cannot_import
-- если он показывает, что импорт невозможен, то тут содержится описание почему
-- кроме этого, предупреждения могут показывать на проблемы с первыми адресами списка
-- импорта, что не препятствует самому импорту
{ "id":"код ошибки", "explain": "доп. информация (скаляр, массив или хэш)" }
....
]
-- только для member.import
,"queue_position" : "номер в очереди импортирования"
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
}
Массовое изменение данных подписчиков¶
Вызов предназначен для единообразного изменения данных сразу многих адресов по правилам, описанных в "Формате заполнения".
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием того, как и какие адреса были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error в "0" удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки, если таковая была.
В данный момент вызов не позволяет менять данные по модели КД, так как это происходит через указание формата, а форматы пока не совместимы с КД, но вы можете использовать вызов импорта подписчиков.
Одновременно может выполняться только один такой запрос:
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.update"
,"format" : код формата заполнения или универсального, из данных которого будут применены изменения
,"if_has" : что делать, если изменяемый пункт анкеты уже заполнен
-- "overwrite" - заменить старое значение новым из формата
-- "merge" - объединить старое и новое значения
-- "skip" - оставить старое значение
,"if_hasnt" : что делать, если изменяемый пункт анкеты ещё не заполнен
-- "set" - заполнить указанным в формате значением
-- "skip" - оставить пункт незаполненным
-- указание подписчиков одним из способов
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn
или
,"list" : [
"идентификатор подписчика"
,"идентификатор подписчика"
........
]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный
или
,"group" : код группы к участникам которой будут применены изменения
,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный
или
,"group.filter" : [
фильтр отбора как у group.filter.set
]
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной статистики
-- подразумевается unique = 1
"filter" : [ условие выборки как у запроса в вызове stat.uni ]
,"have" : [ не обязательно. условие отбора поле группировки в фильтре ]
,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ]
,"select" : [ ... ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ]
}
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. не обязательно, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
}
ответ
{
<общие поля>
-- для асинхронного запроса
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
-- для синхронного запроса
,"list" : {
"адрес-1" : 0|1 -- результат изменения - 1 - изменение применено, 0 - нет (например, адрес ошибочен или отсутствует)
,"адрес-2" : 0|1
.................
}
}
Выслать письмо-подтверждение¶
Вызов позволяет отправить письма, в которых будут работать специальные команды шаблонизатора для подтверждения внесения в базу ([% param.url_confirm %]) и удаления из стоп-листов ([% param.url_unsub_cancel %]и[% param.url_unsub_sender_cancel %]).
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания прогресса отправки.
При высылке с использованием group/group.filter/stat.uni/url создаётся выпуск, в который группируются отосланные письма.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "member.sendconfirm"
-- одно из
,'confirm' : 1 -- высылка писем для подтверждения внесения в базу
,'unsubcancel' : 1 -- высылка писем для удаления из глобального стоп-листа
,'unsubsendercancel' : 1 -- высылка писем для удаления из стоп-листа по отправителю. отправитель - тот что указан в черновике letter
-- указание шаблона письма
,"letter" : "код информационного письма" -- обязательно
-- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации
,"issue_name" : "название выпуска" -- название создаваемого выпуска. Если отсутствует или пусто, то будет использована тема письма из letter
-- не использутеся для email и list
-- указание подписчиков одним из способов
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. Параметр необязателен, система сама распознает email или msisdn
или
,"list" : [
"идентификатор подписчика"
,"идентификатор подписчика"
........
]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный
или
,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"group.filter" : [
фильтр отбора как у group.filter.set
]
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip.
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной статистики
-- подразумевается unique = 1
"filter" : [ условие выборки как у запроса в вызове stat.uni ]
,"have" : [ параметр необязателен, условие отбора поле группировки в фильтре ]
,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ]
,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ "member.email" ]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
}
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен.
}
ответ
{
<общие поля>
,"issue.id" : номер выпуска -- для group, group.filter, url и stat.uni высылаемые письма будут оформлены отдельным выпуском рассылки,
-- номер которого и будет возвращён. Это позволяет изучить статистику по высланным приглашениям
-- для асинхронного запроса
,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*
-- для синхронного запроса
,"list" : {
"адрес-1" : 0|1 -- результат высылки - 1 - выслано, 0 - нет (например, адрес ошибочен или отсутствует или не нуждается в подтверждении)
,"адрес-2" : 0|1
.................
}
}
Подтвердить внесение в базу¶
При успешном подтверждении подписчик становится доступным для участия в рассылках (при отсутствии других противопоказаний к этому).
Если требуется обратное - заново установить состояние "Требуется подтверждение внесения в базу" - используйте вызовы member.set или member.update с установкой member.lockconfirm в "1".
ответ
{
<общие поля>
,"error" : "error/member/wrongcookie" - неверный код. Если ошибка отсутствует, то подтверждение выполнено или не требовалось.
}
Информация об адресе¶
Вызовы возвращают информацию об адресе, не связанную с существованием подписчика и даже в случае, если подписчик уже удалён.
{
"action" : "email.get"
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. Параметр необязателен, система сама распознает email или msisdn.
,"with_stoplist" : 2 -- параметр необязателен, 2 - в информации о стоп-листе перечислить записи по отправителям
-- при отсутствии или любом другом значении - прежний формат с записями только из глобального стоп-листа
}
ответ
{
<общие поля>
"obj" : {
-- информация об адресе по структуре аналогичная ключу member вызова member.get
"member" : {
"id" : "номер адреса", -- он же номер подписчика
"addr_type" : "email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max" -- тип адреса
"email" : "адрес",
"haslock" : "наличие блокировки", -- 0 - нет, 1 - отписался/в стоп листе, 4 - ошибки доставки, 5 = 1 + 4
-- информация об ошибках доставки
"error" : {
"lock" : 0 -- нет блокировки из-за ошибок доставки, 1 - есть
-- при наличии, информация об ошибках
,"date" : "2015-09-12 18:53:39" -- дата последней ошибки доставки (Ys) (удаляется при первой же успешной доставке)
,"str" : "name=test.ru type=A: Host not found" -- описание последней ошибки доставки (удаляется при первой же успешной доставке)
,"error" : 1 -- общее число ошибок доставки, произошедших подряд (устанавливается в 0 при первой же успешной доставке)
,"issue" : 123 -- выпуск последней ошибки доставки
,"letter" : 123 -- письмо последней ошибки доставки
,"lock_issue" : 456 -- выпуск, который привел к блокировке
,"lock_letter" : 456 -- письмо, которое привело к блокировке
},
-- информация об отписке/стоп листе
"lockremove" : 0|1, -- адрес отписан или в стоп-листе (1) или нет (0)
-- обычный формат - записи только о глобальном стоп-листе
"stoplist" : {
-- в стоп-листе владельца аккаунта, если ключ присутствует в stoplist
"owner" : {
"dt" : "2015-11-17 15:02:45", -- дата внесения (Ys)
"source" : "101.101.201.1" -- источник
},
-- в стоп-листе, так как подписчик отписался, если ключ присутствует в stoplist
"member" : {
"dt" : "2015-11-17 15:02:45", -- дата внесения (Ys)
"source" : "101.101.201.1" -- источник
}
}
-- расширенный формат - with_stoplist = 2 - записи и о глобальном стоп-листе и об отписке от отправителей
"stoplist" : [
{ -- пример записи глобального стоп-листа
"dt" : "2015-11-17 15:02:45", -- дата внесения (Ys)
"source" : "101.101.201.1", -- источник
"type" : "owner", -- запись внесена владельцем аккаунта
"sender" : "" -- пусто - глобальный стоп-лист
},
{ -- пример записи стоп-листа по отправителю
"dt" : "2015-11-17 15:02:45", -- дата внесения (Ys)
"source" : "101.101.201.1", -- источник
"type" : "member", -- запись внесена из-за действий подписчика
"sender" : "test@test.ru" -- не пусто - отписка от этого отправителя
}
]
}
}
}
Проверка адресов¶
Вызов проверяет список адресов на синтаксическую верность, даёт нормализованный вариант написания и (если указано) на то, что про этот адрес думает первичный MX, обслуживающий домен.
В ответе ключами списка являются адреса из исходного списка в неизменном виде. Нормализованный вид доступен в параметре email.
Если проверка SMTP не указана, то в ответе не будет частей, связанных с её результатами.
Стадии, на которых проверка SMTP закончилась ошибкой (параметр status):
resolver - ошибка запроса DNS, описание ошибки в параметре message
nodomain - домен не существует
nomxa - у домена нет ни одной записи MX или А
connref - не удалось соединиться с MX
banner - ошибка в первичном баннере
helo - ошибка в ответ на HELO
mailfrom - ошибка в ответ на MAIL FROM
rcptto - ошибка в ответ на RCPT TO
Для понимания того, как работает SMTP и что значат все эти странные слова, полезно изучить RFC 5321.
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "email.test"
,"result" : [ способ возврата результата, смотрите общее описание ] -- отчёт содержит поля ответа - email,total,syntax,delivery.lock(как "ok" или "error"),smtp.status
,"delivery.error" : 0|1 - выводить данные по ошибкам доставки
,"smtp.test" : "проверять доступность по smtp" -- не обязательное поле
-- 0 - не проверять (по умолчанию)
-- lite - проверять, но без проверки существования адреса
-- full - проверять, включая проверку существования адреса
--
-- !!! Полная проверка "full" не всегда даёт результат
-- Многие системы отвечают "существует" на любой адрес
-- Многие системы примут такую проверку за спам-активность
-- Используйте такую проверку, только если понимаете что делаете
,"smtp.timeout" : "таймаут в секундах" -- не обязательное поле, по умолчанию 15
,"auto_group" : { -- параметр необязателен
-- автоматически создать группу-список для не прошедших проверку подписчиков
-- или дополнить любую существующую группу-список не прошедшими проверку подписчиков
-- в группу заносят только те адреса, у которых нет синтаксических ошибок, но есть ошибки smtp и в базе уже есть подписчик с таким адресом
-- отсутствие всего параметра auto_group означает ни создавать новую, ни пополнять существующую группу
-- наличие auto_group, но без id и без name означает создание группы со стандартным кодом
-- и со стандартным названием. Код созданной группы можно узнать, используя возвращаемый номер track.id
-- и вызов track.get
"id" : "идентификатор группы-списка для пополнения"
-- при отсутствии такой группы она создаётся автоматически
-- если параметр пуст или отсутствует, то используется стандартный
-- код вида importYYYYYMMDDhhmmss
l
,"name" : "название группы"
-- название для создаваемой группы.
-- если параметр пуст или отсутствует, то используется стандартное "Внесены <дата-время импорта>"
},
,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список указанную в auto_group перед началом проверки. Параметр необязателен
-- указание адресов одним из способов
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
или
,"list" : [
"идентификатор подписчика"
,"идентификатор подписчика"
........
]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный
или
,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"group.filter" : [
фильтр отбора как у group.filter.set
]
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip.
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной статистики
-- подразумевается unique = 1
"filter" : [ условие выборки как у запроса в вызове stat.uni ]
,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ]
,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ]
,"select" : [ ... ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ]
}
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен
}
ответ
{
<общие поля>
"list" : { -- ключ - оригинальное значение адреса из запроса
" missing@CityCat.ru" : {
"total" : "ok|bad" -- ok - syntax=ok, delivery.lock=0 (если заказывалось), smtp.status=ok (если заказывалось)
-- bad - в других случаях
,"syntax" : "ok" -- результат синтаксической проверки адреса
-- ok - нормально
-- иначе код ошибки
-- остальные поля не имеют смысла если syntax не "ok"
,"email" : "missing@citycat.ru" -- нормализованная форма адреса
,"email.id" : "номер адреса в системе"
,"delivery" : { -- если заказан вывод ошибок доставки
"str" : "host said: 550 SMTP error from remote mail server after end of data: 552 5.2.2 Mailbox size limit",
"lock" : "0",
"dt" : "2018-07-26 11:58:06",
"error" : "1"
},
,"smtp" : { -- если заказана проверка по smtp
"status" : "rcptto" -- стадия возникновения ошибки
,"domain" : "citycat.ru" -- домен, для которого определялся первичный MX
,"mx" : "smtp.citycat.ru" -- первичный MX, используемый для теста
,"ip" : "81.9.34.192" -- ip-адрес использованного MX
,"ptr" : [ -- список имён, соответствующих ip-адресу
"cat192.subscribe.ru"
]
,"code" : "550" -- код SMTP-ошибки (000 - тайм-аут)
,"dsn" : "5.1.1" -- Enchanced status code SMTP-ошибки (при наличии в ответе)
,"message" : "<missing@citycat.ru>... User unknown"
-- текст SMTP-ошибки или ошибки DNS
}
}
," PRO@subscribe.ru " : { "email" : "pro@subscribe.ru"
,"syntax" : "ok"
,"smtp" : {
"status" : "ok"
,"domain" : "subscribe.ru"
,"mx" : "smtp.subscribe.ru"
,"ip" : "81.9.34.192"
,"ptr" : [
"cat192.subscribe.ru"
]
}
}
,"123@test@test.ru " : { "email" : null
,"syntax" : "error/email/multydog" -- код ошибки
}
}
}
Удаление ошибок доставки¶
Удаляются записи об ошибках доставки указанных адресов.
С подписчика, при наличии, снимается блокировка из-за ошибок доставки.
Но наличие подписчика не обязательно (в отличии от вызова member.set, который работает именно с подписчиками)
При асинхронном запуске обработку можно прекратить вызовом track.set
{
"action" : "email.cleanerror"
-- указание адресов одним из способов
,"email": "идентификатор подписчика"
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификатора. Параметр необязателен, система сама распознает email или msisdn
или
,"list" : [
"идентификатор подписчика"
,"идентификатор подписчика"
........
]
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный
или
,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"group.filter" : [
фильтр отбора как у group.filter.set
]
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip.
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
или
,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной статистики
-- подразумевается unique = 1
"filter" : [ условие выборки как у запроса в вызове stat.uni ]
,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ]
,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ]
,"select" : [ ... ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ]
}
,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|pushapp|max|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn
,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный
,"track.info" : "дополнительная информация которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен
}
ответ