Транспорт - HTTP ovet TLS (https) - RFC 2616 http://tools.ietf.org/html/rfc2616, RFC 2818 http://tools.ietf.org/html/rfc2818
Метод вызова - POST.
Не забывайте, что у метода POST есть два типа передачи данных:
- application/x-www-form-urlencoded - все параметры вызова передаются как в query-string и их значение надо передавать в кодировке urlencode (RFC 1738 http://tools.ietf.org/html/rfc1738)
- multipart/form-data - (RFC 2388 http://tools.ietf.org/html/rfc2388) - каждый параметр вызова передаётся в отдельной части и urlencoding не применяется
Описание формата JSON вы найдёте в RFC 4627 http://tools.ietf.org/html/rfc4627
Последовательность обработки вызовов не гарантирована, так как они выполняются параллельно.
Если вам требуется твёрдая уверенность в том, что вызов Б нормально воспользуется результатами более раннего вызова А, то вы должны дождаться явного окончания вызова А и только потом посылать вызов Б.
Например, два вызова anketa.quest.add в случае, когда они сделаны для одной и той же анкета и второй вызов послан до окончания первого, могут дать три разных результата
- добавятся оба вопроса
- только первый
- только второй
Так же следует помнить о порядке обработки при удалении сложных объектов. Например, если удаляемый объект ссылается на другие необходимые ему объекты и они так же при этом должны быть удалены, то сначала следует удалить основной объект и явно дождаться результата и только после этого удалять объекты на которые он ссылался. Иначе, при параллельной обработке может сложиться ситуация, когда вспомогательный объект не будет удалён, так как ещё будет существовать основной (вызов удаления вспомогательного объекта дошёл до обработки ранее завершения удаления основного).
Ответ выдаётся в формате JSON и кодировке UTF-8
Если иного не описано, то вызов является синхронным - запрошенное действие будет выполнено (или не выполнено при ошибке) к моменту ответа на вызов.
Если вызов помечен как асинхронный, то успешный ответ обозначает что запрошенное действие принято и будет выполнено позже в порядке обработки очереди запросов на такое же действие.
Асинхронный вызов возвращает track.id - номер запроса для отслеживания с помощью track.get
{ "request.id" : "то что было в запросе в параметре request.id" ,"duration" : null или "время обработки запроса в секундах" }
{ <общие поля> ,<поля специфические для конкретного запроса> }
При наличии ошибки (ошибок) препятствующих полному или частичному выполнению запроса в ответе появится массив errors со списком описаний каждой ошибки.
Обратите внимание, что, зависимости от вызова и самой ошибки, поле explain может быть не только строкой, но и массивом и объектом.
Часть вызовов может возвращать массив warnings аналогичный структуры для того что бы сообщить о событиях помешавших выполнить вызов в какой-либо его части, но не позволяющих считать что вызов ошибочен.
{ <общие поля> ."errors" => [ { "id" : "код ошибки-1" ,"explain" : "возможное более развёрнутое описание-1" ,<возможно поля специфические для конкретного запроса-1> } ,{ "id" : "код ошибки-2" ,"explain" : "возможное более развёрнутое описание-2" ,<возможно поля специфические для конкретного запроса-2> } ...... ] }
При наличии в ответе поля REDIRECT необходимо
Так же стоит иметь счётчик перенаправлений что бы избежать зацикливания.
В данный момент ограничение максимальной глубины перенаправлений десятью выглядит достаточным.
{ <общие поля> ,"REDIRECT" : "/xxx/yyy" }
Получение ответа с ошибкой 'error/auth/failed' и уточнением 'force_change_password' означает, что для продолжения работы данной комбинацией login/sublogin требуется сменить пароль.
Это может быть вызвано как автоматическими событиями (например истёк срок действия пароля), так и прямой установкой такого требования через вызов user.set или sys.password.set
Для продолжения работы необходимо:
{ <общие поля> ,"errors" : [ { "id: : "error/auth/failed" ,"explain" : "force_change_password" } ] }
Часть вызовов поддерживает кэширование ответов, что позволяет быстрее получать ответ если вы уверены, что данные не изменились и не придумывать свою собственную систему кэширования. В данный момент это вызовы stat.uni и member.list.count
Кэширование применяется только для вызовов завершившихся без ошибок.
Для использования кэширования в вызове передаётся параметр cache с как минимум значениями mode и key.
В ответ вызова использующего кэширование с режимами "use" или "fetch" будет добавляться параметр cache с информацией о результате использования кэша.
Если вызов асинхронный, то параметр cache будет отсутствовать в ответе на основной вызов:Если вызов асинхронный, то при режиме "fetch" и при отсутствии данных основной вызов сразу завершиться с hit == 0, а асинхронная часть даже не начнётся и её действия не будут выполнены. Проверяйте на наличие hit и его равенство 0 для установления факта не вызова асинхронной части.
Вызов:
{ "action: "xxx" ,"cache" : { "mode" : режим -- обязательно -- -- ignore - не использовать -- -- use - при наличии кэша - ответ из него -- - при отсутствии - получить новый результат и закэшировать его -- -- refresh - получить новый результат и закэшировать его -- -- fetch - при наличии кэша - ответ из него -- - при отсутствии - зависит от вызова, но в общем случае нет даже самих ключей ответа -- проверяйте сначала на hit == 0 -- - в зависимости от вызова, не требуется передача всех или почти всех параметров необходимых -- для работы вызова так как, при отсутствии данных в кэше, они не вычисляются заново. ,"key" : ключ кэша -- обязательно -- -- до 64 печатных символов ASCII кроме пробела -- для каждого вызова набор уникальных ключей свой -- можно использовать один и тот же ключ с разными вызовами, они не будут смешаны -- -- каждый ключ виден всем суб-логинам одного обшего логина - один может что-то посчитать -- и закэшировать, а остальные воспользоваться результатом ,"ttl" : желаемое максимальное время жизни кэша в секундах -- не обязательно, применимо для use и refresh при записи к кэш -- -- при отсутствии - теоретически время не ограничено -- -- практически - любая запись в кэше может перестать существовать в любой момент -- и данные будут получены путём обычного выполнения запроса } <прочие параметры вызова> }
При отсутствии данных в кэше в ответе будет:
{ .... "cache" : { "hit" : 0 } .... }
При использовании данных иэ кэша в ответе будет:
{ .... "cache" : { "hit" : 1 ,"created" : "YYYY-MM-DD hh:mm:ss" -- дата и время занесения записи в кэш ,"expired" : null или "YYYY-MM-DD hh:mm:ss" -- дата и время окончания времени жизни записи. -- null - бесконечно, но прочитайте выше примечания к параметру ttl } .... }
Все способы авторизации работают только в основном запросе и игнорируются во вложенных.
Выполняемы запросы изолированы друг от друга и ничего не знают о результатах работы своих соседей. Т.е. схема "в одном запросе создать объект, а в следующем его изменить" в общем случае работать не будет.
{ "action" : "batch" ,"stop_on_error" : 0|1 -- прекращать выполнение после первого же запроса закончившегося с ошибками -- не обязательно. по умолчанию 0 ,"do" : [ { один запрос } ,{ другой запрос } .... ] }
ответ
{ <общие поля> ,"result" : [ { один ответ } ,{ другой ответ } .... ] }
{ "action" : "ping" }
ответ
{ <общие поля> ,"pong" : "что-то каждый раз разное" }
{ "action" : "pong" }
ответ
{ <общие поля> ,"ping" : "что-то каждый раз разное" }
Настоятельно рекомендуется для вашей же безопасности при реализации автоматической работы по API создавать для этих целей отдельный суб-логин с максимально органиченными правами !
Полученный в ответ номер сессии должен передаваться во всех запросах в json-параметре "session", кроме запросов "ping" и "login".
Время жизни сессии несколько часов. Рекомендуется завершать явным вызовом "logout".
В случае окончания времени действия сессии вы получите ответ об ошибке авторизации, а запрошенное действие выполнено не будет.
Для продолжения работы будет необходимо:
{ "action" : "login" ,"login" : "общий логин" ,"sublogin" : "личный логин" ,"passwd" : "пароль" }
ответ
{ <общие поля> ,"session" : "номер сессии" ,"login" : "общий логин для которого выдана авторизация" ,"sublogin" : "личный логин для которого выдана авторизация" }
Авторизация биометрических карт AGSES происходит в два этапа.
На этапе запроса вы получаете flicker-код, на этапе ответа сообщаете код полученный клиентом от своей карты
и, в случае успеха, в ответ получаете номер сессии.
{ "action" : "login.agses.challenge" ,"card" : номер карты, наличие лидирующих 0 не обязательно }
ответ
{ <общие поля> ,"flicker" : код фликера ,"hedgeid" : номер запроса }
Сессия, полученная в этом вызове точно такая же по своим свойствам как и сессия
от обычного вызова login
Храните её в надёжном, cухом, светлом месте вдали от детей.
{ "action" : "login.agses.response" ,"card" : номер карты, наличие лидирующих 0 не обязательно ,"hedgeid" : номер запроса ,"response" : ответ клиента }
ответ
{ <общие поля> ,"session" : "номер сессии" ,"login" : "общий логин для которого выдана авторизация" ,"sublogin" : "личный логин для которого выдана авторизация" }
Настоятельно не рекомендуется для вашей же безопасности не реализовывать автоматическую работу по API с использоватением этого вызова !
Не ленитесь реализовать нормальную работу с помощью сессий, вместо простой постоянной пересылки логина и пароля !
Единственный разумный повод использования разовой авторизации - смена пароля в ответ на ошибку force_change_password.
Указанный параметр передаётся во параметрах вызова вместо "session" и может использоваться с любым вызовом требующим авторизации.
Авторизация заканчивается в окончанием вызова и завершения вызовом "logout" не требует.
Процессы порождённые асинхронными вызовами продолжают работать-и-работать до их естественного завершения.
{ "one_time_auth" : { "login" : "общий логин" ,"sublogin" : "личный логин" ,"passwd" : "пароль" } }
Текущая сессия становится не действительной
{ "action" : "logout" }
ответ
{ <общие поля> }
Список всех или отобраных по фильтру запросов. Информация о запросах старше двух месяцев регулярно автоматически удаляется из системы.
{ "action" : "track.list" ,"filter" : { -- обязателен как минимум один параметр фильтра "action" : тип запроса -- или ,"status" : интересующее состояние запроса -- одно число или список чисел но в массиве -- или ,"!status" : состояние запроса которое исключить -- одно число или список чисел но в массиве ,"dt.from" : "YYYY-MM-DD hh:mm:ss" -- самая ранняя дата создания запроса на отслеживание ,"status.dt.from" : "YYYY-MM-DD hh:mm:ss" -- самая ранняя дата изменени статуса запроса на отслеживание } }
ответ
{ <общие поля> "list" : [ { объект как возвращается track.get } ......... ] }
{ "action" : "track.get" ,"id" : номер трекера }
ответ
{ obj : { "id" : номер запроса ,"dt" : дата-время создания (YYYY-MM-DD hh:mm:ss) ,"action" : -- тип запроса "issue.send" "stat.uni" "member.list" "member.list.count" "member.import" "member.sendconfirm" "member.update" "member.delete" "stat.activity" "stat.issue" "stat.group.portrait" "stat.group.common" "issue.split.create" "stoplist.add" "stoplist.delete" ,"status" : состояние запроса -- -4 - отложенное действие (например отложенный выпуск рассылки) -- -3 - отменён -- -2 - закончился ошибкой -- -1 - закончился успешно -- 0 - принят -- 1 - запущен -- 2 - начата обработка -- 3 - сортировка -- 4 - форматирование -- 5 - генерация отчёта -- остальное - зависит от типа запроса ,"status.dt" : дата-время установки текущего состояния (YYYY-MM-DD hh:mm:ss) ,"error" : код ошибки -- не обязательно -- смысл зависит от типа запроса -- дополнительные параметры в зависимости от запроса и его состояния ,"param" : { -- === issue.send === ,"group.id" : код группы -- характеристики выпуска, если они уже известны ,"issue.id" : номер выпуска ,"issue.dt" : время начала выпуска ,"issue.size" : количество смсок или примерный размер письма в байтах ,"issue.members" : количество получателей для которых уже сформированы письма ,"issue.format" : "email" или "sms" -- в состоянии "начата обработка" примерная информация о достигнутом прогрессе ,"eta" : { "rest' : примерное количество секунд до окончания ,"perc" : примерный процент обработки ,"dt.finished" : примерное дата-время окончания ,"dt.updated : дата-время последнего обновления информации eta } -- отчёт и статистика после завершения работы для Экспресс-Выпуска ,"report_file" : "название файла" -- если были ошибки, то название файла с отчётом для вызова rfs.get ,"statistic" : { "total" : всего строк ,"taked" : верных строк ,"erroneous" : строк с ошибками ,"repeated" : повторов адресов ,"only_unique" : 0|1 -- был ли выпуск запущен с запретом повторной -- рассылки по дублирующимся адресам } -- === stat.uni === "report_file" : "название файла" -- пусто до окончания запроса -- после окончания - название файла с отчётом для вызова rfs.get -- или пусто если заказывалась высылка на почту -- === stat.activity === -- === stat.issue === "group.id" : "код группы" -- пусто если считалось без указания группы -- иначе код группы указанной для расчёта ,"report_file" : "название файла" -- === stat.group.portrait === -- === stat.group.common === -- === member.list === "group.id" : "код группы" -- пусто если считалось без указания группы -- иначе код группы указанной для расчёта ,"report_file" : "название файла" ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } -- === member.import === "group.id" : "код группы" -- пусто если при импорте не указывалась автосоздание новой -- или заполнение существующей группы иначе код автосозданой -- существующей группы ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } -- отчёты и статистика после завершения работы ,"report_file" : "название файла" -- файл в формате xlsx с отчётом в хранилище отчётов если были ошибки. -- первые 1000 ошибок для просмотра человеком ,"report_file.json" : "название файла" -- файл в формате json запакованый zip с отчётом в хранилище отчётов если были ошибки. -- все ошибки в машиноразбираемом виде ,"statistic" : { "inserted" : добавлено новых адрес ,"updated" : обновлено адресов ,"erroneous" : строк с ошибками ,"unconfirmed" : новых адресов внесённых без подтверждения ,"repeated" : повторов адресов } -- === member.list.count === -- === member.sendconfirm === -- === member.update === -- === member.delete === -- === stoplist.add === -- === stoplist.delete === -- === group.snapshot === -- === group.clean === "group.id" : "код группы" -- пусто если считается без указания группы -- иначе код группы указанной для расчёта ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } -- === issue.split.create === -- отслеживается не "создание" (как формально следует из названия) -- а процесс формирования списка получателей и назначения им того или иного варианта -- соответственно, трекер отслеживает тестирование в состояние "подготавливается к запуску" "split.id" : "код группы" -- номер сплит-тестирования ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } } } }
{ "action" : "anketa.list" }
ответ
{ <общие поля> ,"list" : [ { "system" : "системная, да, нет (1, 0)" -- системные анкеты не доступны для изменения ,"id" : "уникальный идентификатор" ,"name" : "название", } ... ] }
{ "action" : "anketa.get" ,"id" : код-анкеты }
ответ
{ <общие поля> ,"obj" : { "id" : код-анкеты, "param" : { "name" : название анкеты, "system" : анкета системная да/нет }, "order" : [ -- порядок вопросов "код-вопроса3", "код-вопроса8", ..... "код-вопроса4" ] "quests" : { -- вопросы анкеты "код-вопроса" : { "id" : код-вопроса, "@" : номер по порядку, "name" : формулировка вопроса, "type" : тип вопроса, -- для типа "dt" "subtype" : под-тип вопроса -- yd - Дата и время с точностью от года до дня -- yh - Дата и время с точностью от года до часа -- ym - Дата и время с точностью от года до минуты -- ys - Дата и время с точностью от года до секунды -- для типа "free" "width" : ширина поля в байтах для типа free -- для типа "1m" или "nm" "answers" : { -- ответы вопроса "код ответа1" : "название ответа1", "код ответа2" : "название ответа2", ..... "код ответа3" : "название ответа3", }, "order" : [ -- порядок ответов "код ответа3", "код ответа1", ..... "код ответа2" ], "form" : { -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных } }, ............ }, }
{ "action" : "anketa.delete" ,"id" : "уникальный идентификатор анкеты" }
ответ
{ <общие поля> }
{ "action" : "anketa.create" ,"name" : "Название анкеты", необязательные: ,"copy_from" : "уникальный идентификатор анкеты (не нужен для создаваемой с нуля, а не копируемой анкеты)" ,"id" : "уникальный код анкеты" ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> ,"id" : "код анкеты" } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
{ "action" : "anketa.set" ,"id" : "идентификатор анкеты" ,"name" : "название анкеты" необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
{ "action" : "anketa.quest.add" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию) -- добавление одного вопроса ,obj : { -- описание вопроса "name" : "Текст вопроса" ,"type" : "Тип вопроса" -- free - свободный ввод -- dt - дата и время -- 1m - выбор одного из списка -- nm - выбор нескольких из списк -- int - целое число -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода" -- обязателен, > 0 -- для type=dt: ,"dtsubtype" : "точность для даты и времени" -- обязателен -- yd - от года до дня. в данных записывается и выводится в формате "YYYY-MM-DD" -- yh - от года до часа. в данных записывается и выводится в формате "YYYY-MM-DD hh" -- ym - от года до минуты. в данных записывается и выводится в формате "YYYY-MM-DD hh:mm" -- ys - от года до секунды. в данных записывается и выводится в формате "YYYY-MM-DD hh:mm:ss" -- для type=1m или nm (выбор из списка): ,"answers" : { -- ответы вопроса "код ответа 1" : "название ответа1" ,"код ответа 2" : "название ответа2" ..... ,"код ответа N" : "название ответаN" } ,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" ..... ,"код ответа 4" ] -- необязательные для любого типа ,"id" : "уникальный идентификатор вопроса" -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных -- не обязательно ,"form" : { -- Видимость в форме "hidden" : 0|1 -- 0 - по умолчанию - поле в форме будет полем ввода 1 - поле в форме будет иметь тип hidden и значение default -- Обязательность заполнения ,"mustbe" : 0|1 -- 0 - по умолчанию - поле не обязательно для заполнения (игнорируется для hidden=1) -- при первоначальном отображении формы в поле будет значение default -- 1 - поле обязательно для заполнения -- Значение по умолчанию ,"default" : "значение по умолчанию" -- для всех вопросов кроме 1m и nm ,"default" : [код ответа] -- для вопросов 1m ,"default" : [код ответа1 , код ответа 2, ... ] -- для вопросов nm -- В какой вопрос какой анкеты-хранилища копируется результат при подтверждении заполнения формы -- параметры или оба отсутствуют или оба указаны и не пустые -- анкета не может быть системной или показывать на саму себя -- тип вопроса в который будет идти копирование должен совпадать с типом вопроса в obj -- для вопросов 1m и nm все возможные ответы текущего вопроса должны быть в ответах вопроса в который будет идти копирование ,"trans.ank" : "код анкеты" ,"trans.quest' : "код вопроса" } } -- добавление нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все добавлены или все не добавлены ,obj : [ { описание вопроса-1 } ,{ описание вопроса-2 } ,............... ] }
ответ
{ <общие поля> ,"obj" : { объект анкета как из ответа anketa.get } -- если "return_fresh_obj" : "1" -- в зависимости от вида параметра obj в вызове ,"id" : "id-добавленного вопроса" -- или ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове "id-добавленного вопроса-1" ,"id-добавленного вопроса-2" ....... ] }
{ "action" : "anketa.quest.set" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию) -- добавление одного вопроса ,"obj" : { -- описание вопроса "id" : "уникальный идентификатор вопроса" ,"name" : "Текст вопроса" -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода, обязателен, > 0" -- для type=1m или nm: ,"answers" : { -- ответы вопроса "код ответа 1" : "название ответа 1" ,"код ответа 2" : "название ответа 2" ..... ,"код ответа N" : "название ответа N" } ,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" ..... ,"код ответа 4" ] ,"form" : { -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных -- не обязательно -- при указании "form" в запросе все параметры вопроса связанные с ним заменяются на новые указанные или удаляются } -- изменение нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все изменены или все не изменены ,obj : [ { описание вопроса-1 } ,{ описание вопроса-2 } ,............... ] }
ответ
{ <общие поля> ,"obj" : { объект анкета как из ответа anketa.get } -- если "return_fresh_obj" : "1" -- в зависимости от вида параметра obj в вызове ,"id" : "id-добавленного вопроса" -- или ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове "id-добавленного вопроса-1" ,"id-добавленного вопроса-2" ....... ] }
Удалении нескольких вопроса транхакционно - удаляются или все (не ошибок) или ни ничего (хоть одна ошибка).
{ "action" : "anketa.quest.delete" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"id" : "уникальный идентификатор вопроса" -- или ,"id" : [ "id1", "id2", ..... ] --- необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
{ "action" : "anketa.quest.order" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"order" : [ -- новый порядок вопросов "код-вопроса3" ,"код-вопроса8" ..... ,"код-вопроса4" ] необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Для вопросов типа "1m" и "nm"
{ "action" : "anketa.quest.response.delete" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"quest.id" : "уникальный идентификатор вопроса" ,"id" : "уникальный идентификатор ответа" необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Для вопросов типа "1m" и "nm"
{ "action" : "anketa.quest.response.order" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"id" : "уникальный идентификатор вопроса" ,"order" : [ -- новый порядок ответов "код-ответа3" ,"код-ответа8" ..... ,"код-ответа4" ] необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Вызов проверяет список адресов на синтаксическую верность, даёт нормализованый вариант написания и (если указано) на то, что про этот адрес думает первичный MX обслуживающий домен.
В ответе ключами списка являются адреса из исходного списка в неизменном виде. Номарлизованый вид доступен в параметре email.
Если проверка SMTP не указана, то в ответе не будет частей связаных с её результатами.
Стадии на которых проверка SMTP закончилась ошибкой (параметр status):
resolver - определение MX nomxa - у домена нет ни одной записи MX или А connref - не удалось соединиться с MX banner - ошибка в первичном банере helo - ошибка в ответ на HELO mailfrom - ошибка в ответ на MAIL FROM rcptto - ошибка в ответ на RCPT TO
Для принимания как работает SMTP и что значат все эти странные слова полезно изучить RFC 5321.
{ "action" : "email.test" "smtp.test" : "проверять доступность по smtp - 0|1" -- не обязательное поле ,"smtp.timeout" : "таймаут в секундах" -- не обязательное поле. по умолчанию 15. ,"list" : [ -- список адресов для проверки " missing@CityCat.ru" ," PRO@subscribe.ru " ,"123@test@test.ru " ...... ] }
ответ
{ <общие поля> "list" : { " missing@CityCat.ru" : { "email" : "missing@citycat.ru" -- нормализованая форма адреса ,"syntax" : "ok" -- результат синтаксической проверки адреса ,"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" -- DSN-код 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" -- код ошибки } } }
{ "action" : "member.get" ,"email" : "адрес подписчика" }
ответ
{ <общие поля> -- ответы на вопросы анкет ,"obj" : { -- ank - код анкеты -- quest - код ответа -- val - значение ответа или код ответа если вопрос с выбором из списка "ank1" : { -- обычный вопрос "quest" : "val" -- вопрос с множественным выбором ,"quest" : [ "val", "val", "val"....] -- вопрос с выбором одного из нескольких - всё равно массив ,"quest" : [ "val" ] } ,"ank2" : { .............. } -- псевдо-анкета описывающая участие в группах-списках ,"-group": { -- перечисляются кода только тех групп-списков, в которых адрес состоит "id1" : 1 ,"id2" : 1 ............. ,"idN": 1 } } }
При отсутствии адреса в базе он автоматически создаётся.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error в "0" удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки если таковая была.
{ "action" : "member.set" ,"email" : "адрес подписчика" ,"addr_type": "тип адреса подписчика (email | msisdn)" ,"source" : "ip-адрес оригинального запроса" -- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос ,"if_exists" : "error|update|overwrite" -- правило изменения ответов анкетных данных. не действует на псевдоанкету "-group" -- error - при наличии адреса в базе возвращается ошибка -- 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 )" -- по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> ,"newbie" : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу -- если "return_fresh_obj" : "1" данные от запроса "member.get" соответствующего адреса }
{ "action" : "member.confirm" ,"email" : "адрес подписчика" ,'cookie' : "код подтверждения" }
ответ
{ <общие поля> ,'error' : 'error/member/wrongcookie' - не верный код. отсутстви ошибки - подтверждение выполнено или не требовалось }
Адреса реально удаляются из базы !
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
{ "action" : "member.delete" -- указание подписчиков одним из способов ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1 -- результат удаления - 1 - удалён, 0 - нет (например адрес ошибочен или отсутствует) ,"адрес-2" : 0|1 ................. } }
Списков групп-фильтров в которых состоит подписчик
А участие в группах-списках и так известена через member.get
{ "action" : "member.where" ,"email" : "адрес подписчика" }
ответ
{ <общие поля> ,"list" : { "адрес" : [ список кодов групп-фильтров в которые адрес входит ] -- или ,"адрес" : null -- адрес не существует или синтаксически не верен } }
{ "action" : "member.list" ,"addr_type": "тип выбираемых адресов подписчиков (email | msisdn)" -- при отсутвии определяется по типу адресов в указанной группе -- если указан, то должен совпадать с типом адресов в группе, если и та указана -- если не указан и не указана группа, то выбираются еmail-адреса ,"group" : "идентификатор группы" -- задает фильтр по списку подписчиков группы-фильтра или группы-списка (необязателен) ,"member.haslock" : "код" -- учёт состояния блокировки подписчика -- пусто или отсутствует - не учитывать состояние блокировки -- -1 - есть хоть какая-то блокировка - не может получать письма или sms -- 0 - нет блокировки - может получать письма или sms -- 1 - заблокирован так как отписался - не может получать письма или sms -- 2 - заблокирован так как не подтверждён - не может получать письма или sms -- 4 - заблокирован так как имеет фатальные ошибки доставки - не может получать письма или sms -- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указаных блокировок -- -- формально этот параметр можно заменить дополнительными условиями в фильтре группы -- но его использование позволяет -- * не меняя фильтра групп узнавать сколько в ней всего участников и сколько из них могут получать письма -- * не создавая группы узнавать это же для всех свои адресов вообще -- * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы ,"format" : "идентификатор формата вывода" -- если формат вывода не используется, то выводится только адрес (member.email) или номер телефона (member.cellphone) ,"sort" : "коданкеты.кодвопроса" -- сортировка по указаному полю (не важно будет оно в итоговых данных или нет) -- если параметр отсутствует или пуст, то выдача идёт в неком внутреннем порядке -- сортировка по произвольной анкете/полю может резко увеличить время выполнения запроса -- так как для его выполнения надо отсортировать всю выборку -- но сортировка по ниже перечисленным полям практически не влияет на скорость выполнения -- member.id -- member.email - при выборке адресов (email) -- member.cellphone - при выборке телефонов (msisdn) -- member.domain - сортировка по домену и внутри него по адресу -- - при выборке телефонов эквивалентно просто member.cellphone ,"sort.order" : "asc|desc" -- направление сортировки asc - по возрастанию (по умолчанию), desc - по убыванию ,"result" : "response|email|save" -- cпособ возврата результата: (по умолчанию - response) -- response - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id ---- дополнительные параметры запроса зависящие от result -- для response ,"page" : "номер страницы" -- при отсутвии выдаётся всь список. должны быть указаны оба параметра или ни одного ,"pagesize": "размер страницы" -- email или save ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) ,"caption" :"id|name" -- в первой строке выводить заголовок, содержащий для каждой колонки код анкеты и вопроса (id) -- или их названия (name) -- если параметр отсутствует или пуст, то такая строка не добавляется -- email ,email : [ e@mail1 ,e@mail2 ... ] -- адреса получателей списка подписчиков -- }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,order : [ -- описание порядка колонок выводимых результатов { anketa : код анкеты ,anketa.name : название анкеты ,quest : код вопроса ,quest.name : названи вопроса } .... ] ,list : [ -- по одной записи для каждого адреса [ значения запрошеных полей в порядке указанном в параметре ответа order ] ,[ значения запрошеных полей в порядке указанном в параметре ответа order ] ,[ значения запрошеных полей в порядке указанном в параметре ответа order ] ..... ] }
Расчёт быстр если ведётся по "всем", по группам-спискам, по группам-фильтрам состоящим из групп-списков.
Расчёт по группе-фильтру может быть долог - в зависимости от сложности фильтра и общего числа подписчиков.
По умолчанию вызов синхронный. Используйте sync = 0, что бы сделать его асинхронным.
Если ответ может быть получен из кэша и он там есть, то ответ будет сообщен сразу и асинхронный запрос не начнётся.
{ "action" : "member.list.count" ,"group" : "идентификатор группы" -- задает фильтр по списку подписчиков группы -- если пусто или отсутствует, то подсчёт идёт по всем подписчикам ,"cache" : { параметры кэширования } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"obj" : { "total" : всего подписчиков ,"active" : количество подписчиков которые могут участвовать в рассылках писем или смс ,"locked" : уникальное количество заблокированных - не могут быть в рассылке. -- подробности по причинам блокировок (у одного подписчика может быть больше одной блокировки) ,"locked.unsubscribed" : в том числе заблокированные так как отписались ,"locked.confirm" : в том числе заблокированные так как не подтвердили внесение в базу ,"locked.stoplist" : в том числе заблокированные так как находятся в стоп-листе ,"locked.hardbounced" : в том числе заблокированные так как имеют фатальные ошибки доставки -- при подсчёте по всем подписчикам, дополнительно появляются поля ,"total.email" : всего именно email ,"total.msisdn" : всего именно телефонов ,"active.email" : способных получать именно адреса ,"active.msisdn" : способных получать именно телефоны } }
Вызов member.import.probe предназначет для проверки что думает система импорта о ваших входных данных.
В ответ будет сообщено как произошло авто-определение кодировки (сharset), разделителя столбцов, определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких анкет приписаны столбцы данных
Если вы знаете зарание ответы на эти вопросы, то можете сразу указать эти данные при вызове тогда выше указание будет иметь приоритет над авто-определением системы.
Вызов member.import реально импортирует данные, описаные выше параметры будет определены автоматически если их не указать сразу при вызове.
Вызов member.import асинхронный - получение положительного ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта - он может не состоятся из ошибок возникших позже. Следить за его исходом можно по возвращаемому номеру асинхронного запроса.
Обратите внимание: Все возможные проблемы (фатальные или нет - смотрите по cannot_import) связанные именно с импортом (настройки, данные) при вызове member.import.probe сообщаются только через параметр warnings. А параметр errors служит только для сообщения о проблемах вызова только с точки зрения API. При вызове же самого импорта, не фатальные ошибки остаются по прежнему в warnings, а фатальные переносятся в errors. Это может выглядеть не логично, но это так из-за назначения вызова member.import.probe - предупредить вас о возможных ошибках, а не выполнять само импортирование.
{ "action" : "member.import" или "action" : "member.import.probe" ** данные импортирования ,"addr_type": "тип вносимых адресов подписчиков (email | msisdn)" и одни из источников данных: ,"users.list": адреса и данные для импортирования -- непосредственно в JSON или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" или ,"users.url": "URL по которому находятся список адресов и данных для импортирования ftp:// или http(s)://" -- данные забираются в момент вызова или ,"uid": "идентификатор уже загруженных данных" -- возвращается после первого вызова member.import.probe, используется далее вместо cамих данных ** параметры (не обязательны) ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )", ,"separator": "разделитель символов ("," | ";" | "|" | "t")", -- t - табуляция ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )", ,"caption": [ -- по порядку следования столбцов в данных. приписывают каждый столбец одному вопросу одной анкеты -- при addr_type = email колонка с адресом это анкета member вопрос email -- при addr_type = msisdn колонка с номером телефона это анкета member вопрос cellphone { "anketa": "id анкеты", "quest": "id вопроса в анкете", или "ignore": "1" -- игнорировать столбец }, ...... ] ** пробный импорт ,"action": "member.import.probe", ** импорт ,"action": "member.import", ,"if_exists": "overwrite|ignore|error" -- обязателен -- что делать если адрес уже существует -- overwrite - перезаписывать данные -- ignore - не вносить -- error - не вносить и считать строку ошибочной ,"newbie.confirm" : "подписчик должен подтвердить внесение в базу (1|0)", -- по умолчанию - внесение без необходимости подтверждения подписчиком (0) -- внесение email без подтверждения ограничено величиной member.noconfirm.rest -- (узнать можно через sys.settings.get) при её исчерпании остальные адреса -- вносятся с подтверждением. -- если количество адресов в базе превышает member.tarif.limit, то величина member.noconfirm.rest -- равна нулю, иначе она равна member.noconfirm.limit за вычетом количества уникальных email -- адресов внесённых в текущем месяце -- на внесение номеров телефонов параметр newbie.confirm не влияет (они всегда вносятся без подтверждения) ,"newbie.letter.confirm" : "номер шаблона информационного письма" -- высылается если новый адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения -- если параметр пуст или отсутствует, то ничего выслано не будет -- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm -- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт -- продолжит вносить уже с подтверждением и этот параметр будет использоваться -- при внесении номеров телефонов ни какие уведомления не высылаются -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации ,"auto_group" : { -- автоматически создать группу-список для импортируемых адресов -- или дополнить любую существующую группу-список импортируемыми адресами -- отсутствие всего параметра auto_group означает ни создавать новую ни пополнять существующую группу -- наличие auto_group но без id и без name означает создание группы со стандартным кодом -- и со стандартным названием. код созданый группы можно узнать используя возвращаемый номер track.id -- и вызов track.get "id" : "идентификатор группы-списка для пополнения" -- при отсутствии такой группы она создаётся автоматически -- если параметр пуст или отсутствует то используется стандартный -- код вида importYYYYYMMDDhhmmss ,"name" : "название группы" -- название для создаваемой группы. -- если параметр пуст или отсутвует то используется стандартное "Внесены <дата-время импорта>" }, ,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список указанную в auto_group перед началом импортирования -- позволяет не дополнять группу, а полностью заменять её участников -- -- сначал проверяются все возможные причины по которым импорт может не начаться. если они есть, то импорт заканчивается ошибкой и очистка не происходит -- иначе импорт начинается с очистки списка участников, а внесение новых происходит только после этого -- -- не путайте удаление адреса из списка участников с удалением адреса из базы - это разные вещи -- -- при одновременном импортировании в одну группу несколькими вызовами у которых хоть у одного clean_group=1 результат -- зависит от порядка выполнения и может быть неожиданным. для однозначного результата всегда выполняйте импорт с cleangroup=1 -- только по завершении всех предыдущих импортов в ту же самую группу и не запускайте новый импорт в такую группу до завершения текущего. ,"format" : " id-формата" -- дополнить данные каждого вносимого адреса данным из формата -- отсутствие или пусто - не дополнять ,"sequence.event" : 0|1 -- будет ли внесение/изменение данных вызывать срабатывание событийных действий -- отсутствие или пусто - вызова событий не будет ,"result": [ -- один или несколько адресов для высылки отчёта с результатами импорта -- обратите внимание на обязательность mailto: "mailto:your@email.tld" ,..... ] }
ответ
{ <общие поля> -- только для member.import.probe ,"uid": "идентификатор уже загруженных данных" ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )" ,"separator": "разделитель символов ("," | ";" | "|" | "t")" ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )" ,"caption": [ -- поля конфигурации { -- для колонки которой найдено соответствие анкете/вопросу "name": "отображаемое имя колонки", "anketa": "id анкеты", "quest": "id вопроса в анкете", -- для колонки которой не найдено соответствие "name": "неопределенное начение из элемента строки конфигурации или null", -- для колонки для которой конфигурации задано игнорирование "ignore" : 1 } ] ,"rows" : [ -- данные первых 15 значащих строк разбитые по полям с учёном указанного разделителя [ "колонка-1-строки-1" ,"колонка-2-строки-1" ,"колонка-3-строки-1" ] ,[ "колонка-1-строки-2" ,"колонка-2-строки-2" ,"колонка-3-строки-3"] ....... ] ,"cannot_import" : 0|1 -- может ли быть выполнен импорт с текущими параметрами запроса -- 1 - может -- 0 - нет -- Именно этот параметр, а не описанный далее параметр warnings сигнализирует о возможности/невозможности импорта, -- т.к. параметр warnings может содержать и не влияющие на запуск процесса импорта предупреждения - например о том, -- что в первых строках файла есть неверно указанные адреса подписчиков, что не говорит о том, что во всем -- списке подписчиков будет так. ,"warnings" : [ -- предупреждения о проблемах при анализе данных -- в первую очередь проверяйте параметр cannot_import -- если он показывает, что импорт невозможен, то тут содержится описание почему -- кроме этого, предупреждения могут показывать на проблемы с первыми адресами списка -- импорта, что не препятствует самому импорту. { "id":"код ошибки", "explain": "доп. информация (скаляр, массив или хэш)" } .... ] -- только для member.import ,"queue_position" : "номер в очереди импортирования" ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* }
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
{ "action" : "member.sendconfirm" ,"letter" : "код информационного письма" -- обязательно -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации -- указание подписчиков одним из способов ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1 -- результат высылки - 1 - выслано, 0 - нет (например адрес ошибочен или отсутствует или не нуждается в подтверждении) ,"адрес-2" : 0|1 ................. } }
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error в "0" удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки если таковая была.
{ "action" : "member.update" -- указание подписчиков одним из способов ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы к участникам которой будут применены изменения ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный -- общее для все способов указания ,"format" : код формата заполнения или универсального, из данных которого будут применены изменения ,"if_has" : что делать, если изменяемый пункт анкеты уже заполнен -- "overwrite" - заменить старое значение новым из формата -- "merge" - объединить старое и новое значения -- "skip" - оставить старое значение ,"if_hasnt" : что делать, если изменяемый пункт анкеты ещё не заполнен -- "set" - заполнить указанным в формате значением -- "skip" - оставить пункт незаполненным }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1 -- результат изменения - 1 - изменение применено, 0 - нет (например адрес ошибочен или отсутствует) ,"адрес-2" : 0|1 ................. } }
Хранилище файлов имеющееся в вашем распоряжении позволяет держать в нём изображения и файлы на которые вы ссылаетесь из писем или прикрепляете к ним (хранилище картинок) и получать от системы отчёты которые вы заказывали с параметром "сохранить на сервере" (хранилище отчётов).
Хранилище файлов доступно через веб-ссылки, что бы на него можно было ссылаться из писем.
К хранилищу отчётов публичного доступа нет. Его файлы доступны только через API.
Параметр path используемый в вызовах это абсолютный путь по хранилищу начинающийся со слэша.
Если path указывает на файл, то возвращается информация только о нём - можно использовать для проверки существования этого файла.
Если path указывает на каталог, то возвращается список его файлов и подкаталогов.
Параметр domain указывает на используемую область - хранилище картинок (image) или хранилище отчётов (report)
{ "action" : "rfs.list" ,"domain" : "image|report" ,"path" : "полный путь - каталог или файл" }
ответ
{ <общие поля> ,"file" : [ { "name" : название ,"path" : полный путь c названием ,"size" : размер ,"date" : дата изменения (в формате yyyy-mm-dd hh:mm:ss) ,"url" : публичная веб-ссылка для доступа. только если domain=image } ......... ] ,"dir" : [ { "name" : название ,"path" : полный пусть с названием } ......... ] }
{ "action" : "rfs.file.get" ,"domain" : "image|report" ,"path" : "полный путь с названием файла" ,"encoding" : "желаемая кодировка данных в ответе" -- пусто или не указана - обычная Unicode/UTF-8 -- base64 - содержимое будет возвращено в base64 }
ответ
{ <общие поля> ,"datа" : "содержимое файла" -- предполагается что файл двоичный и : -- без заказа кодировки значение октетов 0x00 - 0xFF отображено как U+0000-U+00FF -- при заказе base64 данные будет возвращены в base64 }
Только для domain = image
{ "action" : "rfs.file.put" ,"domain" : "image" ,"path" : "полный путь с названием файла (отсутствующие попутные подкаталоги НЕ создаются автоматически)" ,"datа" : "содержимое файла" -- предполагается что файл двоичный и: -- без указания кодировки значение октетов 0x00 - 0xFF заданы как U+0000-U+00FF -- при указании base64 данные считаются закодированы в base64 ,"encoding" : "кодировка данных" -- пусто или не указана - обычная Unicode/UTF-8 -- base64 - содержимое date закодировано в base64 }
ответ
{ <общие поля> ,"url" : публичная веб-ссылка для доступа. только если domain=image }
{ "action" : "rfs.file.delete" ,"domain" : "image|report" ,"path" : "полный путь с названием файла" }
ответ
{ <общие поля> }
Только для domain = image
{ "action" : "rfs.dir.make" ,"domain" : "image" ,"path" : полный путь с названием каталога (отсутствующие попутные подкаталоги создаются автоматически)" }
ответ
{ <общие поля> ,"url" : публичная веб-ссылка для доступа. только если domain=image }
Только пустой каталог
Только для domain = image
{ "action" : "rfs.dir.delete" ,"domain" : "image" ,"path" : "полный путь с названием каталога" }
ответ
{ <общие поля> }
Все рассылки (и email и sms) выпускаются через вызов issue.send
Есть четыре варианта его использования.
Группа-спискок | Группа-фильтр | Экспресс-Выпуск | Транзакционное письмо | |
Адреса получателей | Зарнее созданые в базе список | Динамический поиск по всей (!) базе адресов данные которых удовлетворяют фильтру | Указываются при выпуске или забираются по ссылке | Указывается при выпуске |
Данные для персонализации | Из базы | Из базы | Указываются при выпуске | Из базы если не указаны при выпуске |
Количество переменных | Не ограничено | Не ограничено | Не ограничено | Не ограничено |
Шаблонизатор | Продвинутый | Продвинутый | Продвинутый | Продвинутый |
Собственные функции-плагины к шаблонизатору | Да | Да | Да | Да |
Сложные вложенные структуры данных | Нет | Нет | Да | Да, если указаные сразу |
Подтверждение от владельца адреса | Требуется | Требуется | Требуется | Не обязательно |
Разбор жалоб на спам | Согласно договора | Согласно договора | Согласно договора | С особым пристрастием |
Лимит в месяц | Не ограничено | Не ограничено | Не ограничено | Первоначально равен максимально допустимому количеству адресов в базе. Далее в зависимости от репутации |
Этот вызов асинхронный - получение положительного ответа означает, что задание на рассылку поставлено в очередь. Используйте возвращаемый track.id для отслеживания выпуска.
Это не гарантирует выпуск - он может не состоятся по причинам которые не проверить на момент вызова (например недоступность на момент преобразования ссылки для которой производится преобразование для учёта переходов).
Данные персонализации могут быть дополнены внешними данными в процессе выпуска подробнее в разделе "Внешние данные для персонализации"
Из списка участников группы или списка Экспресс-Выпуска система автоматически отсеевает адреса не подтвердившие регистрацию, отписавшиеся, находящиеся в стоп-листе или имеющие постоянные ошибки доставки.
Вам не надо предпринимать ни каких дополнительных усилий для этого - всё происходит автоматически.
{ "action" : "issue.send", * параметры содержимого выпуска. Для Транзакционных писем - только указание черновика и прикреплённых файлов. "letter" : { * текст письма "subject" : "Тема письма" -- игнорируется для SMS ,"from.name" : "Имя отправителя" -- по умолчанию название аккаунта -- для SMS обязителен и имя отправителя должно быть в списке уже промодерированных имён (вызовы issue.smssender.*) ,"from.email" : "Адрес отправителя (email)" -- обязателен для email, игнорируется для SMS ,"reply.email" : "Обратный адрес для ответа (email)" -- игнорируется для SMS ,"reply.name" : "Имя для обратного адреса для ответа" -- игнорируется для SMS ,"to.name" : "Имя получателя" -- в этом поле уместна персонализация для подстановки имени и фамилии получателя. игнорируется для SMS ,"message": { -- для выпуска по email-адресам одна или обе версии письма "html" : "html-версия письма" ,"text" : "текстовая версия письма" -- для выпуска по SMS "sms" : "sms cообщение" } или черновик из которого их взять. при указании черновика другие параметры содержимого игнорируются "draft.id": "номер черновика содержимое которого даст выпуск", -- тип черновика определит вид и формат рассылки (email или sms) -- черновик должен иметь заполненный адрес отправителя * прикреплённые файлы письма. тип файла определяется по расширению. (игнорируется для SMS) -- следующие имена файлов зарезервированы для внутренних нужд и не должны использоваться -- message.text -- -- index.html -- index.htm -- index.shtml -- index.shtm -- -- attach.html -- attach.htm -- attach.shtml -- attach.shtm -- -- message.html -- message.htm -- message.shtml -- message.shtm ,"attaches": [ { "name": "имя файла", "content": "содержимое файла" }, { "name": "имя файла", "content": "содержимое файла" }, { "url": "url откуда заборать" }, { "url": "url откуда заборать" }, ... ] } * параметры способа выпуска. Тестовый выпуск не доступен для Экспресс-Выпуска, Транзакционных писем и SMS "group" : "id группы | masssending - если это Экспресс-Выпуск | personal - Транзакционное письмо", -- старый параметр gid переименован в group для совместимости с другими вызовами -- можно продолжать указывать gid - он будет использоваться при отсутствии group "mute": "не высылать уведомление об успешном постановке выпуска в очередь на обработку (1 - да|0 - нет)", "sendwhen": "Когда выпустить (now - сейчас | later - отложенный | delay - задержаные | save - отложить на хранение | test - тестовый)", при отложеном выпуске (later) указывается дополнительно дата, час и минута не ранее которых выпускать -- Если на дату выпуска уже запланирован выпуск по такой же группе, то НОВОЕ ЗАДАНИЕ ЗАМЕНИТ СОБОЙ СТАРОЕ. -- ИСКЛЮЧЕНИЕ - Экспресс-Выпуск и Транзакционные Письма. -- Выпуски по этим группам могут быть запланированы на одну и ту же дату в любом количестве. "later.time" : "YYYY-MM-DD hh:mm" при задержаном выпуске (delay) указывается дополнительно на сколько минут задержать выпуск -- Так как "задерка" реализуется созданием отложенного выпуска на "текущее время + delay.time", -- то действуют ТАКИЕ ЖЕ ОГРАНИЧЕНИЯ на одновременные выпуски одной рассылки, что и при использовании later.time "delay.time" : "mm" при выпуске теста (test) указываются адреса получателей. не более пяти. "mca": [ "e@mail.1", "e@mail.2", ...... ] * параметры преобразования ссылок для учёта перехода по ним (игнорируются для SMS) "relink" : 0|1 -- Преобразовывать ссылки автоматически -- 1 - да, 0 - нет "relink.param" : { "link" : 0|1 -- преобразовывать ссылки тега <A> -- 1 - да, 0 - нет "image": 0|1 -- преобразовывать ссылка на внешние картинки для тега <IMG> -- и фоновых изображений в <BODY> и <TABLE> -- 1 - да, 0 - нет "test": 0|1 -- проверять существование адресов -- при включённой проверке выпуск не выйдет если ссылка -- не действительна (ответ не 200, не 301 и не 302) -- 1 - да, 0 - нет } если relink = 1, а какой то из параметров relink.param не указан, то считается что: link=1, image=0 и test=1 соответственно. "link.qsid": "Параметр для отслеживания переходов по ссылкам" -- добавляется ко всем ссылкам через query-string. -- значение должно быть уже url-encoded * список получателей для Экпресс-Выпуска "users.list": адреса и данные персонализации -- непосредственно в JSON (два варианта) или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" или "users.url": "url" -- по которому находятся список адресов с данными для персонализации ftp:// или http(s)://" -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" * параметры списка получателей для Экпресс-Выпуска "only_unique": 0|1 -- Следить за уникальностью адресов в списке -- 1 - да, повторно встреченные адреса исключаются из выпуска -- 0 - нет, повторно встреченные адреса участвуют в рассылке * получатель для Транзакционных писем "email" : "адрес получателя" -- данные для персонализации берутся из базы -- -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" -- -- при этом способе указания получателя он сразу проверяется на возможность отсылки ему письма -- (синтаксическая верность адреса, стоп-лист, ошибки доставки, отписался) и вы сразу получите в ответ описание ошибки. -- при других способах задания получателя, проверка на возможность выпуска происходит -- только при формировании рассылки или "users.list": один адрес и данные персонализации -- непосредственно в JSON (два варианта) или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" -- при указании только адреса данные персонализации берутся из базы -- при нескольких адресах используется только первый -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" * Для email ограничение на частоту отправки -- -- все ограничения касаются только первой попытки отправки сообщения. -- если сообщение не принято сразу, то ограничения могут не быть соблюдены. ,"tz_limit" { "default" : { -- ограничение на частоту отправки сообщений -- за rate минут будет передано в доставку в не более number сообщений -- -- если параметр отсутствует или пуст или обе величины равны 0, -- то ограничения нет "batch" : { -- или отсутствуют или указаны оба значения "number" : "сколько cообщений" -- обязательно, >= 0 ,"rate" : "за сколько минут" -- обязательно, >= 0 } } } * Для sms ограничение на частоту и время отправки -- -- все ограничения касаются только первой попытки отправки сообщения в sms-центр. -- если sms-центр не принял сообщение сразу или принял, но внутри себя -- по какой-то причине не пытался доставить сразу, то ограничения могут не быть соблюдены. -- допустимы временные зоны относительно GMT от -23 до +23 и default. знаки "+" и "-" обязательны. -- временная зона телефонного номера сотовой связи определяется по базе Федерального Агентства Связи. ,"tz_limit" { "default" : { -- настройки по умолчанию для не описанных зон или отсутствующих описаний с описанной зоне -- ограничение на частоту отправки сообщений -- за rate минут будет передано в доставку в sms-центр не более number сообщений -- -- если параметр отсутствует или пуст или обе величины равны 0, -- то ограничения нет "batch" : { -- или отсутствуют или указаны оба значения "number" : "сколько cообщений" -- обязательно, >= 0 ,"rate" : "за сколько минут" -- обязательно, >= 0 } -- ограничение по времени отправки -- *все даты и часы по местному времени временной зоны !!!* ,"time" : { "dt" : "YYYY-MM-DD" -- отправка начнётся не ранее указанного дня. -- если не указано или пусто или в прошлом, -- то используется текущая даты зоны MSK/MSD ,"hour" : [ час, час, час, ... ] -- разрешённые часы местного времени (0-23) в которые будет осуществлять отправка -- если не указано или пусто, то разрешены часы с 9 по 21 -- подумайте, стоит ли расширять этот диапазон на утреннее и ночное время ! -- -- порядок следования часов важен для первого дня отправки ! -- запись -- { -- "dt" : "2012-09-17" -- ,"hour" : [ 20, 21, 22, 23, 06 08 07 ] -- } -- задаёт разрешённые часы с 6, 7, 8, 20, 22 и 23 и начало рассылки 17го декабря -- но именно 17го она начнётся не в 6 часов, а в 20, так как 20 указано первым -- а 18го и далее - начиная с 6 -- -- разрешается весь час - последняя отправка в нём может быть -- даже в 59 минут 59 секунд, что может выглядеть как уже "не разрешённый" час -- т.к. сообщение будет доставлено уже явно в следующем часе. } } ,"+4" : { -- ограничение для временной зоны GMT+4 -- полностью отсутствующий или пустой компонент берётся из default "batch" : { .... } -- используйте 0 для rate и number что-бы снять ограничение из default ,"time" : { .... } -- *дата и часы по местному времени временной зоны !!!* -- -- если задано только dt, то действуют стандартные разрешённые часы с 9 по 21 -- подумайте, стоит ли расширять этот диапазон на утреннее и ночное время ! -- -- если задано только time, то то используется текущая даты зоны MSK/MSD -- -- если не задано ни dt ни time, то действуют ограничения из default } ,"-2" : { -- ограничение для зоны GMT-2 .......... } .......... } * данные произвольной структуры одинаковые для всех подписчиков -- -- эти данные будут доступны для шаблонизатора выпуска как переменные с именем совпадающим с именем ключа хэша -- эти данные могут быть дополнены внешними данными в процессе выпуска - подробнее в разделе "Внешние данные для персонализации" -- в настоящий момент зарезервированы имена: -- anketa - данные о конкретном подписчике -- lenta - данные для подстановки rss/atom каналов -- date - интерфейс к функциям работы с датой и временем -- form - форма опроса -- во избежание пересечений с новыми стандартными именами рекомендуется -- свои имена начинать с большой буквы ,"extra" : { "Key1" : [ 12, 34 ,56 ] -- пример использования [% Key1[2] %] ,"City" : { -- пример использования [% City.rus.long %] "rus" : { "long" : "Санкт-Петербург" ,"short" : "СПБ" ,"eng" : { "long" : "Leningrad" ,"short" : "LED" } } }
ответ
{ <общие поля> ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* }
{ "action" : "issue.later.list", ,"from" : "YYYY-MM-DD" -- от даты (не обязательно) ,"upto" : "YYYY-MM-DD" -- до даты (не обязательно) ,"group" : [ -- фильтр по группам (не обязательно) код-группы-1 ,код-группы-2 ... ] ,"format" : "email|sms|html|text" -- фильтр по формату (не обязательно). -- email это "html или text" }
ответ
{ <общие поля> ,"list" : [ { "id" : "код выпуска" ,"create.date" : "YYYY-MM-DD hh:mm:ss" -- дата постановки задания ,"status" : "статус задания" -- hold - отложено на хранение -- later - отложено для выпуска -- error - ошибка выпуска -- если статус "отложено из-за ошибки" ,"status.reason" : код ошибки -- если статус "отложено для выпуска" ,"sendwhen" : "later" -- всегда later, так как вы смотрите отложенные выпуски ,"later.time" : "YYYY-MM-DD hh:mm" -- запланированная дата выпуска -- базовые настроки выпуска ,"group" : код группы для которой отложен выпуск ,"letter" : { ,"subject" : "тема выпуска" -- для sms совпадает с именем отправителя ,"draft.id" : код черновика используемого для выпуска ,"from.email" : адрес отправителя ,"from.name" : имя отправителя } -- следующие параметры заменены новыми для совместимости с issue.send, но некоторое время ещё будут выдаваться -- "format" - параметр не покрывает всех варинатов. определяйте форматы по message -- "name" - совпадает c letter::subject -- "draft.id" - совпадает с letter::draft.id -- "issue.date" - cовпадает с later.time }, ... ] }
{ "action" : "issue.later.get", "id" : "код выпуска", }
ответ
{ <общие поля> ,"obj" : { "id" : "код выпуска" ,"create.date" : "YYYY-MM-DD hh:mm:ss" -- дата постановки задания ,"status" : "статус задания" -- hold - отложено на хранение -- later - отложено для выпуска -- error - ошибка выпуска -- если статус "отложено из-за ошибки" ,"status.reason" : код ошибки -- следующие параметры одноимённы c issue.send и значения obj можно использовать для создания нового выпуска -- необходимо будет добавить action -- уточнить значения sendwhen и later.time -- и настоятельно рекомендуется удалить "лишнее" : id, create.date, status, status.reason, format, name, issue.date -- но для просто смены даты выпуска или отсылки немедленно используйте специализированный выпуск issue.later.send -- при использовании выпуска по черновику (указан draft.id) параметры message, subject, from.name, from.email, reply.email, reply.name и to.name -- берутся из черновика и заполняются только для справки -- при выпуске по черновику перед вызовом issue.send необходимо проверить параметры -- subject, from.name и from.email черновика, так как они в черновике не обязательны ,"group" : код группы для которой отложен выпуск ,"letter" : { "from.email" : адрес отправителя ,"from.name" : имя отправителя ,"reply.email" : обратный адрес для ответа ,"reply.name" : имя для обратного адреса для ответа ,"to.name" : имя получателя ,"subject" : тема выпуска -- для sms совпадает с именем отправителя ,"message": { тексты пуска } ,"attaches" : [ прикрепляемые файлы ] ,"draft.id" : код черновика используемого для выпуска } ,"relink" : отслеживание переходов ,"relink.param" : параметры отслеживания ,"link.qsid" : трекинг ссылок на стороне клиента ,"users.list" : список получателей ,"users.url" : адрес списка получателей ,"email" : получатель ,"only_unique" : подавление дублей ,"tz_limit" : { параметры доставки по временным зонам } ,"extra" : { дополнительные параметры } ,"mute" : отчёт о выпуске -- если статус "отложено для выпуска" ,"sendwhen" : "later" -- всегда later, так как вы смотрите отложенные выпуски ,"later.time" : "YYYY-MM-DD hh:mm" -- запланированная дата выпуска -- следующие параметры заменены новыми для совместимости с issue.send, но некоторое время ещё будут выдаваться -- "format" - параметр не покрывает всех варинатов. определяйте форматы по message -- "name" - совпадает c letter::subject -- "draft.id" - совпадает с letter::draft.id -- "issue.date" - cовпадает с later.time } }
Если на новую дату выпуска уже запланирован выпуск по такой же группе, то изменение даты закончится ошибкой.
Исключение - Экспресс-Выпуск и Транзакционные Письма. Выпуски по этим группам могут быть запланированы на одну и ту же дату в любом количестве.
{ "action" : "issue.later.send", "id" : "код выпуска", "issue.date" : "YYYY-MM-DD hh:mm" -- Новая дата выпуска -- Если параметр отсутствует или указана дата в прошлом, -- то выпуск выйдет сразу }
ответ
{ <общие поля> }
{ "action" : "issue.later.delete", "id" : "код выпуска" }
ответ
{ <общие поля> }
{ "action" : "issue.smssender.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор" ,"name" : "отправитель" ,"onmoderation" : 0|1 -- 0 - имя одобрено, 1 - имя ещё на модерации } ... ] }
{ "action" : "issue.smssender.get" ,"id" : "идентификатор sms-отправителя" }
ответ
{ <общие поля> "obj" : { "id" : "идентификатор sms-отправителя" ,"name" : "отправитель" ,"onmoderation" : 0|1 } }
Создание или изменённо имя автоматически попадает на модерацию
Если имя состоит из одних только цифр, то его длина не должна превышать 15 символов.
Иначе имя может содержать от 1 до 13 символов больших и маленьких латинских букв и цифр.
{ "action" : "issue.smssender.set" ,"obj" : { "name" : "отправитель" } необязательные ,"id" : "идентификатор sms-отправителя" -- если не указан, создается новый ,"return_fresh_obj": "" -- вернуть объект в формате issue.smssender.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате issue.smssender.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "issue.smssender.delete" ,"id" : "идентификатор sms-отправителя" }
ответ
{ <общие поля> }
Динамический контент позволяет вам задавать содержимое части выпуска или всего выпуска как текст забираемый готовым со страницы какого-либо сайта или собираемый на основе новостей из различных видов источников с помощью Лент Новостей.
Во всех ссылках поддерживается авторизация HTTP-Basic - укажите её обычным образов в самой ссылке.
Во всём содержимом подставляемым в текст письма с помощью динамического контента работает шаблонизатор - подставляемы части могут содержать любые его команды.
"Готовая страница сайта" это доступная веб-страница любого сайта.
При использовании в выпуске рассылки команды шаблонизатора [% wget("url") %] указаная страница забирается с сайта и подставляется в текст письма. Это происходит в момент формирования текста выпуска рассылки и по этому адрес страницы может быть задан только как константа.
От страницы используется только содержимое между тегами <body></body>.
На странице можно дополнительно расставить метки фильтрации позволяющие указать только определённyю часть/части которую надо использовать в выпуске.
Такие части отмечаются в своём начале добавлением строки начинающейся с <!-- issueBegin --> и в конце добавлением строки начинающейся с <!-- issueEnd -->
В случае неудачи при получении страницы (не найдена, проблема связи и т.д.) выпуск не выйдет.
"Лента новостей" это набор от одного до бесконечности каналов новостей, сообщения из которых собираются и могут быть использованы для формирования индивидуальных писем или общих рассылок.
Один источник новостей может входить в несколько лент - фактически он опрашивается один раз в 1-2 часа и все найденные свежие новости собираются в базу и становятся независимо доступны во всех лента и использование определенной новости в одной из них никак не повлияет на ее состояние в другой ленте.
Одна и та же лента может использоваться в выпуске несколько раз. Например первый раз для формирования "меню" из списка заголовков новостей, а второй для вывода полной новости.
В выпуске может быть использовано несколько лент.
Лента хранит отметку времени последнего использования в рассылке и основываясь на нём система включает в письма только те новости, которые были получены после этой даты.
После формирования рассылки (или индивидуального письма) отметка времени у всех использованных в рассылке лент устанавливается в текущее время. Таким образом новости одной ленты уже использованные в рассылке повторно использованы не будут.
Старые новости регулярно удаляются из базы как только проходит 15 дней с момента получения новости.
Индивидуальные письма подписчикам формируются из новостей накопившихся в их личных лентах которые к подписчикам привязаны владельцем ПРО при их создании (lenta.set).
Письмо формируется по указанному в ленте расписанию с оформлением по указанному шаблону выпуска с использованием новостей накопившихся с прошлой рассылки.
Если свежих новостей нет, то письмо не высылается.
Это позволяет организовать индивидуальное оповещение клиентов персонализированными подборками информации. Например, организовать на сайт подписку на результаты поиска по каталогу товаром - пользователи будут автоматически получать обновления в интересующих их разделах.
Предоставляются простые базовые шаблоны которые можно модифицировать на свой вкус. Они доступны по адресу https://pro.subscribe.ru/resources/help/lenta/drafts.html
Для использовании в рассылке новостей одной или нескольких лент надо воспользоваться функциям шаблонизатора news() или lenta().
Функция news() не требует специальной обработки и результатом её работы становится содержимо полей "content" всех свежих новостей. Это упрощает работу с лентами если готового источника у вас ещё нет и вы можете легко формировать его как нравится. Или когда имеющийся источник выдаёт в "content" новости то, что надо для выпуска.
Функция lenta() только присваивает переменной lenta специальную структуру данных описывающую все свежие на данный момент новости и их источники. Для их отображение требуется использование в теле письма оператора [% FOREACH %] для обработки каждой новости. Это сложнее, но вы можете оформить вывод новостей самым гибким образом.
Обе функции могут работать как с заранее созданной лентой новостей (указывается её номер), так и напрямую с каналом новостей (указывается его url).
При указании url механизм исключения уже использованных новостей не применим и в выпуск всегда попадают все новости канала имеющиеся в нём на момент выпуска.
Если свежих новостей нет ни в одной используемой в шаблоне ленте и новостей нет вообще ни в одном используемом в шаблоне источнике указанным напрямую, то выпуск рассылки не высылается.
По умолчанию новости отсортированы в порядке убывания и даты публикации. Задать свой порядок и группировку по источникам можно с помощью щаблонизатора - рассмотрите пример "Новости по источникам" по адресу https://pro.subscribe.ru/resources/help/lenta/drafts.html
Базовые шаблоны от индивидуальных писем применимы и тут - как отправная точка для кастомизации под ваши нужды.
Структура данных ленты в индивидуальных письмах и после вызовов lenta() и news() содержит информаци о ленте новостей, всех источниках новостей новости которых попали в ленту и содержимое всех свежих новостей.
"lenta" : { "id" : "id ленты в базе" ,"name" : "название ленты" -- описания всех источников ленты, чьи новости попали в письмо ,"sources" : { "id-источника" : { описание источника } ,"id-источника" : { описание источника } ...... } -- id источников упорядоченные так же как упорядочены новости ,"sources_order" : [ "id-источника", "id-источника" .........] -- описание новостей в заказаном порядке (по умолчанию по убыванию даты публикации новости) ,"news" : [ { описание новости } ,{ описание новости } ,{ описание новости } ] }
{ "id" : "id источника в базе" -- индексы в lenta.news[] новостей именно этого источника в порядке совпадающем с порядком lenta.news[] ,"news' => [ индекс, индекс, индекс ....] -- параметры источника как получены из описания RSS/Atom-канала при его последнем анализе -- названия параметров совпадают с названиями тегов XML ,"title" : "название источника" ,"descr" : "описание источника" ,"link" : "ссылка на обычную версию источника" ,"logo" : "ссылка на логотип источника" ,"author" : "информация об авторе" ,"copyright" : "информация об авторских правах" }
{ "ID" : "id новости в базе" ,"source" : "id в базе источника из которого получена новость. ключ в lenta.sources{}" ,"n" : "номер по порядку в lenta.news[]" -- параметры новости как получены из описания RSS/Atom-канала при его последнем анализе -- названия параметров в основном совпадают с названиями тегов XML ,"title" : "название источника", ,"content" : "содежимое новости" -- тег <description> или <yandex:full-text> ,"link" : "ссылка на обычную версию новости" -- тег <link>, если пусто и isPermaLink="true" и guid похож на урл, то guid ,"dt" : "YYYY-MM-DD hh:mm:ss" -- дата публикации новости (тег <pubDate> или <dc:creator>) ,"id" : "идентификатор новости" -- тег <guid> ,"author" : "информация об авторе новости" ,"category" : { -- категории новости "домен" : { "категория" : "метка" ,.... } ,... } ,"enclosure" : [ -- приложения к новости на основании тегов <enclosure> и <media:thumbnail> -- обычно так указывают картинки и звуковые файлы { "url" : "ссылка" ,"type" : "mime-type" ,"length" : "длина" } ,.... ] -- дополнительные параметры полученые из dt ,"ymd" => "YYYY-MM-DD" ,"hm" => "hh:mm" }
{ "action" : "lenta.list" }
ответ
{ "list" : [ { "id" : номер ленты ,"name" : название ленты -- если лента привязана к подписчику ,"member" : "получатель" } ........... ] }
{ "action" : "lenta.get" ."id" : номер ленты }
ответ
{ "obj" : { "id" : номер ленты ,"name" : название ленты ,"source" : [ -- информация об RSS/Atom каналах входящих в ленту { "url" => "адрес канала" ,"dt.fetched" => "YYYY-MM-DD hh:mm:ss" -- дата последнего чтения канала ,"dt.updated" => "YYYY-MM-DD hh:mm:ss" -- дата последнего пополнения новостей из канала ,"error" : { 'count': количество ошибок работы с каналом ,'dt' : "YYYY-MM-DD hh:mm:ss" - дата последней ошибки ,'str' : описание послденей ошибки } } ... ] -- если лента привязана к подписчику ,"member" : "адрес получателя" ,"decor" : "черновик" -- номер черновика выпуска рассылки который будет использоваться -- при выпуске накопившихся новостей -- расписание выпусков ,"schedule" : { -- часы по которым высылать письма 'hour' : [ час, час, ... ] -- номера дней недели по которым высылать письма -- от 1 (Пн) до 7 (Вс) ,'weekday' : [ номер, номер, ... ] } } }
Создает ленту (при отсутствии id) или изменяет некоторые её параметры.
{ "action" : "lenta.set" ,"obj" : { "name" : "название ленты" ,"member" : "адрес получателя" -- только при создании. измененить нельзя -- для лент привязаных к получателю ,"decor" : "черновик" -- расписание выпусков -- если параметр полностью отсутствует, то с 8 по 18 с понедельника по пятницу ,"schedule" : { -- часы по которым высылать письма. если не указано, то с 8 по 18 'hour' : [ час, час, ... ] -- номера дней недели по которым высылать письма, если не указано, то с Пн по Пт -- от 1 (Пн) до 7 (Вс) ,'weekday' : [ номер, номер, ... ] } } -- необязательные ,"id" : номер ленты ,"return_fresh_obj": "" -- вернуть объект в формате issue.draft.get }
ответ
{ <общие поля> ,"id" : номер ленты -- при отсутствии в запросе параметра "return_fresh_obj" ,obj { ... } -- объект в формате lenta.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "lenta.delete" ,"id" : номер ленты }
ответ
{ <общие поля> }
{ "action" : "lenta.source.add" ,"lenta.id" : номер ленты ,"url" : "адрес источника добавляемого в ленту" }
ответ
{ <общие поля> }
{ "action" : "lenta.source.delete" ,"lenta.id" : номер ленты ,"url" : "адрес источника удаляемого из ленты" }
ответ
{ <общие поля> }
Указаный источник опрашивается вне расписания в поиске свежих новостей.
Если с момента прошлой провеки (плановой и этим вызовом) прошло меньше 15 минут, то опрос произведён не будет и количество свежих новостей будет возвращено как -1.
{ "action" : "lenta.source.refresh" ,"url" : "адрес обновляемого источника" }
ответ
{ <общие поля> ,"news" : "количество найденех свежих новостей" }
Вызов отправляет тестовое письмо с указанным количеством последних новостей ленты на указанный адрес (а не на адрес для которого создана лента).
В отличии от реального выпуска, отосланные новости не отмечаются как использованные и потом будут в итоге использованы при реальной отсылке.
Если количество последних новостей указано, то отметка их использования в предыдущих выпусках игнорируется.
Вызов предназначен только для тестирования шаблона оформления указанной ленты, чему помогает возможность явно указать нужное количество новостей, а не ждать пока свежие новости появятся в ленте.
Если в итоге новостей нет, то письмо не отправляется
Для тестирования выпуска рассылки с лентой есть альтернативные вариант - тестовый выпуск через issue.send
{ "action" : "lenta.send" ."id" : номер ленты ,"email" : адрес для отсылки тестового письма ,"n" : количество последних новостей для теста -- если не указано, то используются все ещё не отосланные новости (их может не быть) ,"decor" : "черновик" -- если лента привязана к подписчику, то можно не указывать - будет взят черновик указанный в ленте -- если лента не привязана к подписчику, то черновик указать необходимо }
ответ
{ "news" : "количество новостей попавших в письмо" < параметры ответа issue.send если письмо было выслано > }
Сплит-тестирование (A/B-тестирование) позволяет выпустить по некоторой части выбранной аудитории несколько писем различающихся между собой чем-либо и по результатам (если охват не 100%) выбрать в ручную или автоматически "лучший" вариант и послать его оставшейся не охваченной части аудитории.
Традиционный вариант использования - A/B-тестирование - предусматривает только два тестовых варинта писем и выпуск победителя.
Но данная реализация позволяет иметь произвольное количество тестовых вариантов и при желании не выпускать победителя, а покрыть тестами сразу всю аудиторию.
Тестирование начинается автоматически не ранее даты указанной для запуска самого раннего варианта и если вариантов к этому моменту не менее двух.
Дата запуска какого-либо тестового выпуска или выпуска-победителя может быть пропущена если тестирование в приостановленном состоянии или не хватает вариантов.
Пропущенные запуски будут выполнены как только тестирование будет переведено в активное состояние или добавлен недостающий вариант.
В любом случае запуск победителя возможен только после выпуска всех тестовых частей даже если это потребует пропуска назначенного времени.
Список участников тестирования определяется как все участники указанной группы и формируется в момент или перед запуском первого варианта. В дальнейшем список неизменен вне зависимости от изменения списка участников группы за исключением адресов удаливших себя или внесённых в стоп-лист.
На время формирования списка тестирование находится в состоянии "подготавливается к запуску" и прогресс формирования может быть отслежен через вызов track.get
Данные персонализации каждого участника берутся на момент выпуска варианта.
Каждому варианту писем достанется процент аудитории равный Процент тестового охвата / Количество вариантов. Варианту победителю при повторном выпуске достанется оставшаяся часть аудитории.
Если участников меньше количества вариантов (при охвате 100%) или меньше количества вариантов + 1 (при охвате не 100%), то тестирование при запуске сразу перейдёт в состояние "завершено". Другими словами - каждому варианту и победителю должен достаться хотя бы один получатель.
Если процент тестового охвата равен 100, то выпуска-победителя не предусматривается.
Если тестирование НЕ в состоянии "ожидает запуска" то менять процент и группу уже нельзя.
Если тестирование НЕ в состоянии "ожидает запуска" то добавлять или удалять варианты писем уже нельзя.
Если тестирование НЕ в состоянии "ожидает запуска", то его нельзя удалить.
Изменить вариант письма можно только если тестирование в состоянии "ожидает запуска" или дата запуска варианта письма ещё не прошла или и тестирование не активно и изменяемый вариант ещё не выпущен.
Пока тестирование не в состоянии "победитель выбран" или "завершено" можно поменять способ выбора победителя.
Если тестирование в состоянии "завершено", то можно изменить только его название.
{ "action" : "issue.split.list" }
ответ
{ "list" : [ { "id" : "номер тестирования" ,"name" : "название" ,"group" : код группы ,"group.name" : название группы ,"active" : "активность" ,"state" : "состояние" } ] }
{ "action" : "issue.split.create" ,"name" : "название" ,"group" : "код группы" -- группа для получения аудитории. только группы c типом адресов email. не masssending и не personal. ,"percent" : процент аудитории для тестового охвата. от 1 до 100. целое число. ,"winner.by" : manual | read | click | unsub -- способ выбора победителя -- manual - в ручную -- read - больше чтений -- click - больше кликов -- unsub - меньше отписок -- игнорируется, если процент равен 100 ,"winner.after" : "DD hh" -- момент запуска победителя - через сколько дней (DD) и часов (hh) после выпуска последнего -- теста автоматически выбрать победителя -- игнорируется, если процент равен 100 или способ выбора победителя manual ,"active" : 0|1 -- активность. 0 - приостановлено. 1 - активно ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" }
ответ
{ <общие поля> ,"id" : номер тестирования } если "return_fresh_obj" : "1" ответ -- как на запрос "issue.split.get" соответствующего тестирования
{ "action" : "issue.split.get" ,"id" : номер тестирования }
ответ
{ <общие поля> ,"id" : номер тестирования ,"name" : "название" ,"group" : код группы для получения аудитории ,"group.name" : название группы ,"percent" : процент аудитории для тестирования ,"winner.after" : "DD hh" -- момент выбора победителя. ,"winner.by" : "способ выбора победителя" ,"active" : "активность" ,"state" : "состояние тестирования" -- назначается автоматически -- 0 - ожидает запуска -- 1 - подготавливается к запуску -- 2 - запущено -- 3 - ожидает выбора победителя -- 5 - победитель выбран (да именно 5, а не 4) -- 4 - завершено -- -1 - ошибки ,"parts" : [ -- список вариантов тестовых писем { "id" : "номер варианта" ,"start.at" : "время запуска" ,"issue.at" : "номер выпуска" -- если вариант уже выпущен для теста ,"issue.winner" : "номер выпуска" -- если вариант уже выпущен как победитель ,"is_winner" : 0|1 - вариант выбран как победитель } ,{ ...... } ....... ] }
{ "action" : "issue.split.set" ,"id" : номер тестирования -- не обязательные поля. не указанное поле сохранит прежнее значение ,"name" : название ,"group" : группа для получения аудитории. не masssending и не personal -- изменение игнорируется если состояние тестирования не "ожидает запуска" ,"percent" : процент аудитории для тестового охвата. -- изменение игнорируется если состояние тестирования не "ожидает запуска" -- при установке в 100 очищаются поля winner.by и winner.after ,"winner.by" : способ выбора победителя -- изменение игнорируется, если процент равен 100 -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено". -- при установке в manual очищается поле winner.after ,"winner.after" : момент запуска победителя -- изменение игнорируется, если процент равен 100 или способ выбора победителя manual -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено". ,"active" : активность -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено". ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос "issue.split.get" соответствующего тестирования
Нельзя удалять тестирование в состоянии "запущено" и выше, так как при таком состоянии уже был как минимум один выпуск.
{ "action" : "issue.split.delete" ,"id" : номер тестирования }
ответ
{ <общие поля> }
Указывает какой вариант считать победителем и сразу выпускает его.
Допустимо при ручном способе выбора победителя если уже вышли все варианты, но победитель ещё не выбран.
Допустимо при автоматическом способе выбора победителя если уже вышли все варианты и не прошло время автоматического выбора.
Не допустимо если процент тестирования 100.
{ "action" : "issue.split.winner" ,"variant.id" : номер варианта }
ответ
{ <общие поля> }
{ "action" : "issue.split.variant.list" ,"split.id" : номер тестирования }
ответ
{ <общие поля> ,"list" : [ { "id" : номер варианта ,"start.at" : время запуска ,"issue.at" : "номер выпуска" ,"issue.winner" : "номер выпуска" ,"is_winner" : 0|1 - вариант выбран как победитель } ,........ ] }
Нельзя создать новый вариант если тестирование не в состоянии "ожидает выпуска"
{ "action" : "issue.split.variant.create" ,"split.id" : номер тестирования -- параметры варианта ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты ,"letter" : { -- высылаемое письмо ,"format" : "html|sms|text" -- формат письма. в данный момент поддерживается только html ,"from" : "email отправителя", -- обязательно ,"sender" : "имя отправителя", ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма", ,"text" : "текст письма в соответствующем формате" ,"link.qsid" : "параметр отслеживания переходов" -- аналогичен параметру issue,send } ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" }
ответ
{ <общие поля> ,"id" : номер варианта тестирования } если "return_fresh_obj" : "1" ответ -- как на запрос "issue.split.variant.get" соответствующего варианта
{ "action" : "issue.split.variant.get" ,"id" : номер варианта }
ответ
{ <общие поля> ,"id" : номер варианта ,"split.id" : номер тестирования куда входит этот вариант ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты ,"letter" : { -- высылаемое письмо ,"format" : "формат письма" ,"from" : "email отправителя", ,"sender" : "имя отправителя", ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма", ,"text" : "текст письма в соответствующем формате" ,"link.qsid" : "параметр отслеживания переходов" } ,"issue.at" : "номер выпуска" -- если вариант уже выпущен для теста ,"issue.winner" : "номер выпуска" -- если вариант уже выпущен как победитель ,"is_winner" : 0|1 - вариант выбран как победитель }
Изменить вариант письма можно только если тестирование в состоянии "ожидает запуска" или дата запуска варианта письма ещё не прошла или и тестирование не активно и изменяемый вариант ещё не выпущен.
{ "action" : "issue.split.variant.set" ,"id" : номер варианта -- параметры варианта, изменятся только явно указанные. параметр letter заменяется полностью ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты ,"letter" : { -- высылаемое письмо ,"format" : "формат письма" ,"from" : "email отправителя" -- обязательно ,"sender" : "имя отправителя" ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма" ,"text" : "текст письма в соответствующем формате" ,"link.qsid" : "параметр отслеживания переходов" } ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" }
ответ
{ <общие поля> ,"id" : номер варианта тестирования } если "return_fresh_obj" : "1" ответ -- как на запрос "issue.split.variant.get" соответствующего варианта
Нельзя удалять вариант если тестирование не в состоянии "ожидает выпуска"
{ "action" : "issue.split.variant.delete" ,"id" : номер варианта }
ответ
{ <общие поля> }
В большинстве случаев вызов issue.list + несколько issue.get можно заменить одним более быстрым вызовом stat.uni для объекта issue.
{ "action" : "issue.list" ,"from" : "YYYY-MM-DD" -- от даты (не обязательно) ,"upto" : "YYYY-MM-DD" -- до даты (не обязательно) ,"group" : [ -- фильтр по группам (не обязательно) код-группы-1 ,код-группы-2 ... ] ,"format" : "email|sms|html|text" -- фильтр по формату (не обязательно). -- email это "html или text" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор выпуска" } ... ] }
Если не нужен текст выпуска, то вызов issue.get можно заменить более быстрым вызовом stat.uni для объекта issue.
{ "action" : "issue.get" ,"id" : "уникальный идентификатор выпуска" }
ответ
{ <общие поля> "obj" : { "id" : "уникальный идентификатор выпуска", ,"date" : "дата выпуска", ,"group" : "уникальный идентификатор группы выпуска", ,"format" : "html|text|sms", -- формат выпуска ,"title" : "тема письма" ,"issue.access" : { "права доступа у выпуску. структура аналогичная параметру access вызова issue.set.access, за исключением отсутствия варианта default" } ,"text" : "содержимое выпуска" ,"draft.id" : "уникальный идентификатор черновика, по которому сделан выпуск", ,"sequence.id" : "уникальный идентификатор последовательности, событие в которой вызвало выпуск", ,"variant.id" : "уникальный варианта сплит-тестирования для которого сделан выпуск", ,"attach" : [ -- прикрепленные файлы "aaa.doc" ,"bbb.doc" ... ] ,"archive" : "ссылка на выпуск в архиве" -- ссылки на изображения письма выпуска -- только для html выпусков, и только для групп отличных от personal -- в настоящий момент поддерживаются картинки 640x1100 и 150x180 -- надо учитывать что ссылка может вести на отсутствующее изображение -- например, из-за сбоя при её формировании ,"thumbnail" : [ { "url" : "ссылка на изображение" ,"width" : ширина в пикселах, ,"height" : высота в пикселах }, ............... ], } }
{ "action" : "issue.get.attach" ,"id" : "уникальный идентификатор выпуска" ,"attach" : [ -- имена файлов вложений, которые необходимо получить (если параметр не указан - все вложения) "aaa.doc" ,"bbb.doc" ... ] }
ответ
{ <общие поля> ,"list" : [ "aaa.doc" : "содержимое файла|null - если файл не найден", "bbb.doc" : "содержимое файла|null - если файл не найден", ... ] }
{ "action" : "issue.set.acсess" ,"id" : "уникальный идентификатор выпуска" ,'access' : { -- доступ к выпуску на вебе разрешён "who" : default -- использовать значение из глобальной настройки "issue.access" вызова sys.settings.get all -- всем member -- внесённым в базу issue -- участникам группы по который был выпуск group -- участникам группы с кодом в параметре "group" none -- никому ,"passwd" : "индивидуальный пароль для доступа к выпуску" -- дополнительно для доступа запрашивается этот пароль -- не применим если who = default или none ,"group" : код группы -- обязателен для who = group } }
ответ
{ <общие поля> }
{ "action" : "issue.draft.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор черновика" ,"format" : "html|sms|text" -- формат черновика ,"name" : "название" ,"template" : "0|1" -- признак шаблона (шаблон - заренее предустановленный черновик с оформлением) } ... ] }
{ "action" : "issue.draft.get", "id" : "код черновика", }
ответ
{ <общие поля> "obj" : { "id" : "идентификатор черновика" ,"name" : "название черновика" ,"format" : "html|sms|text" -- формат черновика ,"division" : "идентификатор подразделения, имеющего доступ к черновику" ,"from" : "email отправителя", ,"sender" : "имя отправителя", ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма", ,"text" : "текст" ,"template" : "0|1" -- признак шаблона (шаблон - заранее предустановленный черновик с оформлением) -- У предустановленных черновиков (при template = 1) ,"template.thumbnail" : "http://.." -- расположение (URL) изображения шаблона }
Создает или изменяет параметры и содержимое черновиков. Вызов не может быть применён к шаблонам (предустановленным черновикам) с оформлением.
{ "action" : "issue.draft.set" ,"obj" : { "name" : "название черновика" ,"format" : "html|sms|text" -- формат черновика ,"division" : "идентификатор подразделения, имеющего доступ к черновику" (не обязательно) ,"from" : "email отправителя" -- не обязателен для сохранения, но черновик не получится использовать -- в дальнейшем если не заполнить это поле ,"sender" : "имя отправителя", ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма", ,"text" : "текст черновика в соответствующем формате" } необязательные "id" : "идентификатор черновика" -- если не указан, создается новый ,"return_fresh_obj": "" -- вернуть объект в формате issue.draft.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате issue.draft.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "issue.draft.delete" -- одного ,"id" : "код черновика" --- или нескольких ,"id" : ["код черновика1", "код черновика2", .. ] }
ответ
{ <общие поля> }
{ "action" : "issue.draft.preview" ,"email" : "адрес для параметеризации подстановок" -- не обязательно -- одно из "id" : "номер черновика" -- или ,"obj" : { -- можно передавать объект из issue.draft.get - лишние поля проигнорируются ,"format" : "html|sms|text" -- формат черновика ,"text" : "текст черновика в соответствующем формате" } }
ответ
{ <общие поля>, "text" : "текст выпуска" }
{ "action" : "infolett.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор" ,"format" : "html|sms|text" -- формат ,"name" : "название" ,"onmoderation" : 0|1 -- 0 - шаблон одобрен для использования, 1 - шаблон на модерации } ... ] }
{ "action" : "infolett.get" ,"id" : "идентификатор шаблона" }
ответ
{ <общие поля> "obj" : { "id" : "идентификатор шаблона" ,"name" : "название" ,"onmoderation" : 0|1 -- 0 - шаблон одобрен для использования, 1 - шаблон на модерации ,"format" : "html|sms|text" -- формат ,"from" : "email отправителя" ,"sender" : "имя отправителя" ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма" ,"text" : "текст" } }
При создании или изменении шаблона он автоматически попадает на модерацию и использовать его при высылке писем нельзя. Но его можно повтороно менять и удалять.
По результатам модерации вам придёт уведомление.
{ "action" : "infolett.set" ,"obj" : { ,"name" : "название" ,"format" : "html|sms|text" -- формат ,"from" : "email отправителя" -- не обязателен для сохранения, но информационное письмо не получится использовать -- в дальнейшем если не заполнить это поле ,"sender" : "имя отправителя" ,"reply.email" : "обратный адрес для ответа" ,"reply.name" : "имя для обратного адреса для ответа" ,"to.name" : "имя получателя" ,"subject" : "тема письма" ,"text" : "текст" } -- необязательные ,"id" : "идентификатор шаблона" -- если не указан, создается новый ,"return_fresh_obj": "" -- вернуть объект в формате infolett.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате infolett.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "infolett.delete" ,"id" : "идентификатор шаблона" }
ответ
{ <общие поля> }
{ "action" : "infolett.preview" ,"email" : "адрес для параметеризации подстановок" -- не обязательно -- одно из ,"id" : "номер письма" -- или ,"obj" : { -- можно передавать объект из infolett.get - лишние поля проигнорируются ,"format" : "html|sms|text" -- формат черновика ,"text" : "текст черновика в соответствующем формате" } }
ответ
{ <общие поля>, "text" : "текст письма" }
{ "action" : "group.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "код группы" ,"name" : "название" ,"type" : "тип группы" -- list или filter ,"addr_type" : "тип адресов" -- email или msisdn } ... ] }
При создании группы типа filter она первоначально получит пустой набор правил отбора.
И до явной установки желаемых правил отбор по такой группе всегда будет давать пусто.
{ "action" : "group.create" ,"id" : "смысловой код группы. символы a-zA-Z0-9" -- например "clients2011" -- не обязателен. при отсутвии будет назначен автоматически ,"name" : "название группы" -- обязательно ,"issue.passwd" : "пароль выпуска по почте" -- не обязательно, используйте только если будете отсылать задания -- на выпуск рассылки через почтовый интерфейс ,"type" : "list | filter" -- обязательно. тип группы. -- list - группа является заранее создаваемым списком -- filter - группа является набором фильтров для отбора по всей базе ,"addr_type" : "email | msisdn" -- обязательно, тип адресов на работу с которыми будет ориентирована группа -- email - адреса электронной почты -- msisdn - номера телефонов }
ответ
{ <общие поля> , "id" : "код созданой группы" }
Обратите внимание, что при вызове со списком групп, сообщения об ошибочных кодах групп будут возвращены не в errors (как это было бы при одиночном вызове), а в warnings, так как в целом считается что вызов закончился успешно.
{ "action" : "group.get" ,"with_filter" : 0 | 1 -- вернуть в ответе так же и фильтр группы ,"id" : "код группы" - для одной группы -- или ,"id" : [ "код группы", "код группы", ... ] - для списка групп -- или ,"id" : [ "*" ] - для всех групп }
ответ
{ <общие поля> -- для одной группы ,"obj" : { ,"id" : "код группы" ,"name" : "название группы" ,"type" : "тип группы" -- list или filter ,"addr_type" : "тип адресов" -- email или msisdn ,"issue.passwd" : "пароль выпуска по почте" ,"filter" : [ -- если запрошено фильтр группы как в вызове group.filter.get ] } -- или для нескольких групп ,"list" : [ { содержимое obj для одной группы } ,{ содержимое obj для другой группы } ..... ] ,"warnings" : [ -- может отсутствовать массив аналогичный по структуре массиву errors содержит ошибки для тех кодов групп из списка, которые ошибочны по тем или иным причинам ] }
{ "action" : "group.set" , "id" : "код группы" ,"name" : "название группы" - не обязательно ,"issue.passwd" : "пароль выпуска по почте" - не обязательно необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "group.get" соответствующей анкеты
{ "action" : "group.delete" , "id" : "код группы" }
ответ
{ <общие поля> }
Только для групп с типом filter
{ "action" : "group.filter.get" , "id" : "код группы" }
ответ
{ <общие поля> ,"filter" : [ массив описывающий фильтр ] }
Только для групп с типом filter
{ "action" : "group.filter.set" ,"id" : "код группы" ,"filter" : [ массив описывающий фильтр ] }
ответ
{ <общие поля> }
В указанную группу вносятся адреса из другой группы, условия созданного на ходу фильтра или прочих возможных источников.
Так как источником может быть группа-фильтр или просто фильтр, то вы получаете неизменный "снимок" состояния группы на момент вызова.
Это полезно, например, если требуется провести несколько статистических анализов (не надо для каждого анализа заново искать подписчиков по фильтру и их состав не изменен) или для быстрого выхода рассылки с очень сложным филтром (можно заранее сделать снимок, скажем ночью, и потом днём очень быстро по нему выпустить рассылку).
Так же с помощью этого вызова можно добавлять группу-список участников из других групп, условий фильтра или прочих доступных источников
{ "action" : "group.snapshot" "to" : { -- получатель данных "id" : "код группы" -- группа-список в которую будут внесены адреса -- обратите внимание, что это не вызов импорта списков ! -- если адреса указанные в источниках email, list, stat.uni на момент -- вызова отсутствуют в базе, то они не будут созданы и добавлены. -- для этого есть импорт подписчиков. ,"clean" : 0|1 -- очистить группу перед началом внесения } ,"from" : { -- источник данных одно из "email" : "адрес подписчика" -- или "list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный -- или "group" : код группы ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный -- или "group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный -- или "stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный} }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса -- ничего дополнительного }
Вызов удаляет из участников группы-списка заданные адреса.
Сами адреса в базе остаются ! Удалением адресов из базы занимается вызов member.delete
{ "action" : "group.clean" ,"id" : "код группы" -- группа-список из которой будут удалены адреса -- указание подписчиков одним из способов ,"all" : 1 -- все адреса. быстрый синхронный вызов. -- для получения трекинга или асинхронности используйте источник "group" c таким же значением что и "id" (более медленно) или ,"email" : "адрес подписчика" -- вызов синхронный или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса -- ничего дополнительного }
{ "action" : "format.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор" ,"name" : "название" ,"type" : "uni|fill|view" -- соответственно тип: универсальный | шаблон заполнения | формат просмотра } ... ] }
{ "action" : "format.get" "id" : "уникальный идентификатор" }
ответ
{ <общие поля> ,"obj" : { "id" : "уникальный идентификатор" ,"name" : "название" ,"type" : "uni|fill|view" -- соответственно тип: универсальный | шаблон заполнения | формат просмотра ,"fields" : [ -- список полей ответов анкет в том порядке, в котором они будут использоваться при отображении { "aid" : "код анкеты" ,"qid" : "код ответа" -- поля для шаблона заполнения данных ,"unused" : "1|0" - использовать это поле или нет при заполнении ,"answer" : "значение ответа используемое при заполнении" } ... ] } }
{ "action" : "format.set" ,"obj" : { ,"name" : "название" ,"type" : "uni|fill|view" -- соответственно тип: универсальный | шаблон заполнения | формат просмотра ,"fields" : [ -- список полей ответов анкет в том порядке, в котором они будут использоваться при отображении { "aid" : "код анкеты" ,"qid" : "код ответа" -- поля для шаблона заполнения данных "unused" : "1|0" -- использовать это поле или нет при заполнении "answer" : "значение ответа используемое при заполнении" } ... ] } необязательные "id" : "уникальный идентификатор" -- если не указан, создается новый ,"return_fresh_obj": "1" -- вернуть объект в формате format.get }
ответ
{ <общие поля> ,obj : { ... } -- объект в формате format.get, если в запросе "return_fresh_obj" : "1" }
{ "action" : "format.delete" ,"id" : "уникальный идентификатор" }
ответ
{ <общие поля> }
Новые ссылки и группы ссылок появляются с системе автомитически c каждым новым выпуском issue.send в зависимости от настроек relink и relink.param.
Если в выпуске есть ссылки для отслеживания переходов, то, при необходимости, создаются соответствующие им объекты "ссылка".
Поддерживаются пользовательские метки reltype/relref (смотрите описание в Общих Замечаниях)
{ ,"action" : "link.list" ,"filter" : { -- не обязательно "group" : "идентификатор группы" -- не обязательно -- при наличии ограничивает список только ссылками указанной группы ,"group.reltype" : число -- не обязательно -- при наличии ограничивает список только ссылками групп с указанным reltype ,"group.relref" : число -- не обязательно -- при наличии ограничивает список только ссылками групп с указанным relref ,"reltype" : число -- не обязательно -- при наличии ограничивает список только ccылками с указанным reltype ,"relref" : число -- не обязательно -- при наличии ограничивает список только ссылками с указанным relref } } ответ { <общие поля> ,"list" : [ { "id" : "идентификатор ссылки" ,"url" : "url ссылки" ,"group" : [ { "id" : "идентификатор группы ссылок" ,"name" : "название группы ссылок" } ... ] } ... ] ,"group" : { -- присутствует в ответе, только если в запросе был указан идентификатор группы "id" : "идентификатор группы" ,"name" : "название группы" ,"reltype" : .... ,"relref" : .... } }
{ ,"action" : "link.get" ,"id" : "идентификатор ссылки" } ответ { <общие поля> "obj" : { "id" : "идентификатор ссылки" ,"url" : "url ссылки" ,"reltype" : ...... ,"relref" : ...... } }
Ссылки не уникальны. С одним и тем же url может быть несколько ссылок с разным id.
{ "action" : "link.create" ,"url" : "url ссылки" ,"test" : "0|1" -- проверять запросом доступность ссылки ,"reltype" : число -- не обязательно, по умолчанию 0 -- отрицательные значения зарезервированы для системы -- в данный момент: -- -1 - ссылка из выпуска рассылки -- -2 - ссылка - целевая страница достигнутая подписчиком ,"relref" : число -- не обязательно, по умолчанию 0 }
ответ
{ <общие поля> "id" : "идентификатор ссылки" }
При изменении нескольких ссылок все изменения будут проигнорированы если проверка (GET) хоть одной ссылки для которой указано 1 вернёт HTTP код ответа не 2xxx и не 301, 302, 303, 401
{ "action" : "link.set" -- не указанные поля остаются не изменёнными. test учитывается только при наличии url или одна ссылка ,"id" : "идентификатор ссылки" ,"url" : "новое значение" ,"test" : "1/0 - проверять доступность ссылки" ,"name" : "новое название группы" ,"reltype" : "новое значение" ,"relref" : "новое значение" или несколько ссылок ,"list" : [ { "id" : .... ,"url" : .... ,"test" : .... ,"reltype" : .... ,"relref" : .... } .. ] } ответ { <общие поля> }
{ "action" : "link.delete" ,"id" : "идентификатор ссылки" }
ответ
{ <общие поля> }
{ "action" : "link.set.group" ,"id" : "идентификатор ссылки" ,"group" : { -- участие в не указанных группах не изменяется "id1" : "0 - удалить из группы. 1 -добавть в группу" ,"id2" : "0|1" ,"id3" : "0|1" ... } } ответ { <общие поля> }
Группы ссылок позволяют объединять несколько ссылок в одно целое. Например для более простого получения по ним суммарной статистики.
Поддерживаются пользовательские метки reltype/relref (смотрите описание в Общих Замечаниях)
{ "action" : "link.group.list" ,"filter" : { -- не обязательно ,"reltype" : число -- не обязательно -- при наличии ограничивает список только группами с указанным reltype ,"relref" : число -- не обязательно -- при наличии ограничивает список только группами с указанным relref } } ответ { <общие поля> ,"list" : [ { "id" : "идентификатор группы ссылок" ,"name" : "название группы ссылок" ,"reltype" : .... ,"relref" : .... } ... ] }
{ ,"action" : "link.group.get" ,"id" : "идентификатор группы" } ответ { <общие поля> "obj" : { "id" : "идентификатор группы" ,"name" : "название группы" ,"reltype" : ...... ,"relref" : ...... } }
{ ,"action" : "link.group.set" -- для создания ,"name" : "название группы" -- обязательно ,"reltype" : число - не обязательно, по умолчанию 0 ,"reltype" : число -- не обязательно, по умолчанию 0 -- отрицательные значения зарезервированы для системы -- в данный момент: -- -2 - ссылка - целевая страниц ,"relref" : число - не обязательно, по умолчанию 0 -- для изменения ,"id" : "идентификатор группы" -- не указанные поля остаются не изменёнными ,"name" : "новое название группы" ,"reltype" : "новое значение" ,"relref" : "новое значение" } ответ { <общие поля> ,"id" : "идентификатор группы" }
Удаляется именно группа ссылок как объект обеспечивающий группировку ссылок.
Входящие в нёё ссылки не удаляются.
{ ,"action" : "link.group.delete" ,"id" : "идентификатор группы" } ответ { <общие поля> }
Сервис "Целевые страницы" предназначен для отслеживания страниц вашего сайта по которым прошёл подписчик после перехода из письма рассылки и определения дошёл ли он до куда вы планировали.
Сервис "Целевые страницы" не имеет своих специальных вызовов API, но используя вызовы issue.send, stat.uni и sys.settings.* вы получите всю интересующую вас информацию.
Использовать "Целевые страницы очень просто":
Возможно вы захотите дополнительно настроить параметр "Время отслеживания после перехода" (sys.settings.get/set, параметр target.cookie.ttl) - он хранит значение в минутах как долго после перехода из письма система будет отслеживать посещение страниц вашего сайта.
В данный момент значение этого параметра по умолчанию равно 360 - 6 часов.
Дополнительно, вы можете оформить включение создаваемой ссылки сразу в ту или иную группу ссылок - для этого задайте параметр link.group.id при получении значения настройки target.script. Это можно использовать для автоматической группировки целевых страниц сайта, скажем, по их пренадлежности к тому или иному разделу сайта. Настоятельно рекомендуется при создании таких групп указывать им reltype = -2.
Прочие дополнительные параметры для target.script описаны в вызове sys.settings.get
Мы используем Cookiе для обеспечения работы данного сервиса. Пользователи не принимающие их не смогут быть отслежены. Пользователи у которых наша отметка будет по какой-либо причине удалена раньше отведённого времени не могут быть отслежены всё запланированное время.
Существует два стоп-листа: владельца (A) - вы им полностью управляете и подписчика (M) - вносит в него себя подписчик сам и вы не можете повлиять на имеющиеся там записи.
{ "action" : "stoplist.get" ,"type" : "тип листа" (A - внесенные владельцем, M - внесенные подписчиками, пусть - любой) ,"list" : [ -- отсутсвие параметра - дать всех "email-1" -- есть в А и М ,"email-2" -- нет ни в одном ,"email-3" -- есть в А ..... ] }
ответ
<общие поля> list : { "email-1" : { "A": 1 ,"M": 1 } ,"email-3" : { "A": 1 } } }
Внесение в стоп-лист владельца означает только то, что на указанный адрес/телефон будет автоматически исключаться из всех рассылок в которых они могли бы участвовать.
Но вся информация связанная с адресом/телефоном остаётся в базе.
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
{ "action" : "stoplist.add" -- указание подписчиков одним из способов ,"email" : "адрес или телефон" -- телефон в полном формате +7XXXYYYYYYY или ,"list" : [ "адрес/телефон" ,"адрес/телефон" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1|кодошибки -- результат внесения - 1 - удалён, 0 - нет, кодошибки - синтаксическая ошибка в адресе/телефоне ,"адрес-2" : 0|1|кодошибки ................. } }
Внесение в стоп-лист владельца означает только то, что на указанный адрес/телефон перестанет автоматически исключаться из всех рассылок в которых они могли бы участвовать если только он при этом не остался в стоп-листе владельца.
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
{ "action" : "stoplist.delete" -- указание подписчиков одним из способов ,"email" : "адрес или телефон" -- телефон в полном формате +7XXXYYYYYYY или ,"list" : [ "адрес/телефон" ,"адрес/телефон" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"stat.uni" : { -- адреса для обработки получаются из запроса Универсальной Cтатистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.email' ] } ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1|кодошибки -- результат удаления - 1 - удалён, 0 - нет, кодошибки - синтаксическая ошибка в адресе/телефоне ,"адрес-2" : 0|1|кодошибки ................. } }
Удаляются все записи из стоп-листа владельца
{ "action" : "stoplist.erase" }
ответ
{ <общие поля> }
Вызов устарел и будет удалён 01-01-2014.
Используйте вызовы stoplist.add и stoplist.delete обладающие большей функциональностью.
Для каждого выпуска система определяет географию, тип устройства, операционную систему, браузер и версию браузера подписчика с помощью который он перешёл по ссылке письма и открыл письмо.
Эта информация доступна через объекты issue.geo.* и issue.gadget.* вызова Универсальной Статистики.
Для устройства подписчика определяются:
- Тип устройства - Desktop, Mobile, Tablet или Robot
- Операционную систему - Linux, Android, Windows, iOS, Mac, Blackberry или Other
- Семейство браузера - Firefox, Chrome, Opera, Safari, IE, Blackberry или Other
- Старшую часть версии браузера
Если устройство определено как Robot, то его операционная система всегда Other, браузер - Other, версия - 0.
Используйте issue.geo.* вызова Универсальной Статистики.
География определяется с точностью до зарубежной страны и с точностью до субъекта федерации для России.
География хранится как одно число совмещающее в себе номер страны и номер региона в виде СССRR000
Для нумерации стран (CCC) используется ISO 3166-1.
Для нумерации субъектов федерации России (RR) - первый уровень классификатора ОКАТО/ОКТМО.
Таким образом код зарубежной страны это код по ISO * 100000, а код для России это 64300000 + код региона * 1000
Не определившаяся страна имеет код 0. Не определившийся регион России имеет код региона 0.
Имеются дополнительные функции по получению из кода географии буквеных кодов стран и регионов и рускоязычных названий.
Используйте issue.gadget.* вызова Универсальной Статистики.
Ссылки с полезной информацией и таблицами кодов:
http://www.iso.org/iso/ru/country_codes
https://www.iso.org/obp/ui/#search
http://ru.wikipedia.org/wiki/ISO_3166-1
http://ru.wikipedia.org/wiki/Субъекты_Российской_Федерации
http://ru.wikipedia.org/wiki/ОКАТО
http://ru.wikipedia.org/wiki/Общероссийский_классификатор_территорий_муниципальных_образований
{ "action" : "stat.activity", "gid" : "id группы", "pagesize": "строк на странице (по умолчанию 20)", "page": "текущая страница (по умолчанию 1)", "sort": "сортировать: 'date' - по дате, 'email' - по адресу (по умолчанию по дате)", "desc": "1 - сортировать в обратном порядке", "from": "событие произошло начиная с даты (включительно, в формате ГГГГ-ММ-ДД)", "to": "событие произошло не позже даты (включительно, в формате ГГГГ-ММ-ДД)", "issue.from": "событие произошло из выпуска вышедшего начиная с даты (включительно, в формате ГГГГ-ММ-ДД)", "issue.to": "событие произошло из выпуска вышедшего не позже даты (включительно, в формате ГГГГ-ММ-ДД)", -- из следующих параметров можно указать только один (исключение - можно совместить with_deliver и with_errs) "with_deliver": "1 - если нужно включать тех, кому доставлено", "with_errs": "1 - если нужно включать тех, у кого ошибки", "with_links": "1 - если нужно включать тех, кто переходил по ссылкам", "with_remove": "1 - если нужно включать тех, кто отписался", "with_read": "1 - если нужно включать тех, кто открыл выпуск", "result" : "response|email|save", -- cпособ возврата результата: -- response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id ---- дополнительные параметры запроса зависящие от result -- email email : [ e@mail1 ,e@mail2 ... ] -- адреса получателей отчета -- email или save "result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"obj" : [ [ "адрес подписчика", "дата (время) события", "тип события", -- типы событий: -- l - переход по ссылке -- d - доставка -- r - открытие выпуска -- u - отписка "id группы", "подробности", -- содержимое зависит от типа события (url ссылки, статус доставки, причина отписки) ], }, }
Похожую и более обширную статистику по выпускам можно получить с помощью вызова "Универсальная Статистика"
{ "action" : "stat.issue", "issue.from" : "дата выпуска от (включительно, в формате ГГГГ-ММ-ДД)", "issue.upto" : "дата выпуска по (включительно, в формате ГГГГ-ММ-ДД)", "group" : [ "код группы", ... ], -- кода групп. Если пусто - по всем "groupby" : "способ группировки по времени" -- по умолчанию - YM, -- Варианты значения groupby: -- Total только итог по группе -- YY с шагом 1 год -- YM с шагом 1 месяц -- YD с шагом 1 день -- Yh с шагом 1 час -- Ym с шагом 1 минута -- Ys с шагом 1 секунда -- -- MM по интервалу Месяц - Месяц -- MD по интервалу Месяц - День -- Mh по интервалу Месяц - Час -- Mm по интервалу Месяц - Минута -- Ms по интервалу Месяц - Секунда -- -- DD по интервалу День - День -- Dh по интервалу День - Час -- Dm по интервалу День - Минута -- Ds по интервалу День - Секунда -- -- hh по интервалу Час - Час -- hm по интервалу Час - Минута -- hs по интервалу Час - Секунда -- -- mm по интервалу Минута - Минута -- ms по интервалу Минута - Секунда -- -- ss по интервалу Секунда - Секунда -- "total" : "none | yes | only", -- итог по всем записям: не нужен | нужен | только он и нужен "withempty" : "0 | 1", -- Не отображать статистику по тем группам подписчиков, по которым не было отправлено ни одного выпуска "result" : "response|email|save", -- cпособ возврата результата: -- response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id ---- дополнительные параметры запроса зависящие от result -- email ,email : [ e@mail1 ,e@mail2 ... ] -- адреса получателей -- email или save ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"list" : { "код группы" -- если пусто ("") - это итог по всем записям; ANY - если было выбрано по всем : { "дата" -- если пусто ("") - это итог по группе : { "html.issue" : "выпусков в формате HTML", ,"html.receiver" : "получателей в формате HTML", ,"text.issue" : "выпусков в текстовом формате", ,"text.receiver" : "получателей в текстовом формате", ,"sms.issue" : "выпусков смс", ,"sms.receiver" : "получателей сообщений", ,"sms.sms" : "всего выпущено смс" ,"sms.cost" : "цена выпущенных смс в единицах тарификации" - в данный момент это копейки ,"total.issue" : "Итого выпусков", ,"total.receiver" : "Итого получателей", } ............. } ........... } }
{ "action" : "stat.group.portrait", "group" : "код группы", -- если пусто - по всем "empty_resp" : "0|1", -- включить в статистику ответы не выбранные ни кем "empty_quest" : "0|1", -- включить в статистику вопросы не отвеченные ни кем "format" : "код формата", -- задает по каким вопросам каких анкет требуется статистика. Если пусто - по всем ,"result" : "response|email|save", -- cпособ возврата результата: -- response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id ---- дополнительные параметры запроса зависящие от result -- email ,email : [ e@mail1 ,e@mail2 ... ] -- адреса получателей списка подписчиков -- email или save ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"selected" : количество адресов участвовавших в выборке ,"list" : { "код анкеты" : { "код вопроса" : { "код ответа" : { "num" : "число ответов" ,"perc" : "процент от количества ответов на этот вопрос" } ..... } ..... } ..... } }
{ "action" : "stat.group.common", "group" : [ ], -- коды групп. Если пусто - по всем ,"result" : "response|email|save" -- cпособ возврата результата: -- response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id ---- дополнительные параметры запроса зависящие от result -- email ,"email" : [ e@mail1 ,e@mail2 ... ] -- адреса получателей отчетов -- email или save ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"members" : { -- сумма locked.* может не равняться просто locked "total" : "всего адресов" ,"active" : "активных" ,"locked" : "заблокированых" ,"locked.unconfirmed" : "заблокированых, так как не подтвердили регистрацию" ,"locked.unsubscribed" : "заблокированых, так как отписались" ,"locked.blocked" : "заблокированых, так как приостановили получение писем" }, -- для email статистика по доменам ,"tld" : { -- количество адресов по доменам первого уровня "домен первого уровня" : "количество адресов" ,"домен первого уровня" : "количество адресов" ,"домен первого уровня" : "количество адресов" ............ }, ,"sld" : { -- количество адресов по доменам второго уровня "домен второго уровня" : "количество адресов" } ,"домен второго уровня" : "количество адресов" } ,"домен второго уровня" : "количество адресов" } ............ } -- для номеров мобильных телефонов статистика по операторам и тарифам -- тариф указан за одну смс, а не за одно сообщение в рассылке ! -- сообщение, в зависимости от длинны, может состоять из нескольких смс ! ,"operator" : { "badphone" : { -- сюда попадут неверные номера (например городской вместо мобильного) "n" => "количество номеров" } ,"oper1" : { "n" => "количество номеров этого оператора ,"tarif" => "цена в сотых долях копейки одной смс этому оператору" } ,"oper2" : { "n" => "количество номеров этого оператора ,"tarif" => "цена в сотых долях копейки одной смс этому оператору" } ........... } }
Универсальная статистика позволяет получить информацию про переходы, открытия писем, тиражи выпусков и результаты доставки. Примеры использования вынесены в отдельный раздел.
При использовании кэширования запоминаются сами данные, а способ возврата результата задаваемый в "result" и "caption" применяется к ним позже.
При использовании кэширования в режиме "fetch" необходим только параметр "result" и связанные с ним так как, при отсутствии данных в кэше, вычисление результата производиться не будет.
При "result" равном "email" или "save" вызов асинхронный !
{ "action" : "stat.uni" ,"cache" : { параметры кэширования } ---- Параметры расчёта -- или Единичный запрос ,"skip" : число пропускаемых строк данных отчёта от начала. не обязательно. по умолчанию 0 ,"first" : число выбираемых строк после пропуска skip. не обязательно. по умолчанию все ,"select" : [ -- обязательно -- список полей для выборки -- или список полей и функций агрегирования -- или список полей и функция unique(*) -- -- поля типа дата могут содержать указания на точность в виде двух букв из набора (Y M D h m s) -- по умолчанию поля типа дата имеют точность Ys или YD - в зависимости от их назначения -- -- например: dt:YM (дата от года до месяца), dt:Yh (дата от года до часа), dt:YY (год) -- не верно: dt:hY - первый уточнитель (час) младше второго (год) -- -- поля типа дата могут содержать указания на то что требуется получить -- номер дня в неделе - dt:DOW -- номер дня в году - dt:DOY -- номер недели в году - dt:WOY -- первый день недели - dt:CW1D -- от значения даты -- -- допустимые функции агрегирования -- count(*) -- count(unique имяполя) -- max(имяполя) -- min(имяполя) -- avg(имяполя) -- sum(имяполя) -- range(имяполя) -- stdev(имяполя) -- variance(имяполя) -- -- в функциях перед именем поля может использоваться префикс unique -- -- поле не может быть и в списке выбора и при этом использоваться -- в функциях агрегирования (даже с разным заданием точности) -- -- правильные примеры -- a,b,c -- a,b,avg(c),max(d) -- dt:YM,b,min(c),max(c) -- a,b,count(*),min(e) -- max(dt:YD),min(y) -- max(f),min(f) -- a,b,unique(*) -- a,b,count(unique c) -- -- не правильные примеры -- -- a,b,avg(a) -- поле а и в выборке и в агрегировании -- a,b,unique(*),avg(e) -- функция unique(*) не совместима ни с одной другой функцией -- unique(*) -- unique(*) без списка полей ] ,"filter" : [ -- фильтр результатов, не обязательно -- -- все элементы списка объеденяются через "И" -- -- если имя поля содержит указание точности даты, то -- значение для сравнения большей точности будут -- автоматически сокрашены. значия с меньшей точностью -- считаются ошибкой -- -- пример: "2010-05-04 12:13:14" станет "2011-05" для точности YM -- не верно: "2010-05-04" не хватает точности для Ys -- -- поля типа дата кроме констант могут так же сравниваться с текущим -- временем +/- сдвиг. это описано ниже. { "a" : имя поля или функция агрегирования ,"op" : операции сравнения ( == != < <= > >= ) ,"v" : значение } ,{ "a" : имя поля ,"op" : операции (не-)вхождения в список (in !in) ,"v" : [ значение, значение, ...] список значений для проверки вхождения (in) или не вхождения (!шт) } ,{ "a" : имя поля ,"op" : операции (не-)определённости (is_null !is_null) только для полей помеченных (null) параметр "v" должен или отсутствовать или быть равен "" } ......... ] ,"order" : [ -- упорядочивание результата, не обязательно -- -- список полей и функций агрегирования -- -- префикc "-" задаёт сортировку по убыванию -- префикс "+" или его отсутвие - по возрастанию -- -- a,-b -- +b,-avg(z) -- -a,+b,-c -- +dt:YM,-c ] -- или Запрос с объединением -- Результаты всех единичных запросов объединяются в одну строку ответа по уникальным ключам по порядку выполнения запроса. -- Если в каком-либо запросе результатов для уникального ключа нет, то в строку добавляется соответствующее число значений null. -- Если в результате строки с уникальным ключём встречается больше одного раза, то используется только первый результат, а остальные отбрасываются. -- Дублирование уникального ключа в объединённой строке на происходит, так как он удаляется из результатов второго и далее запросов перед их добавкой в объединённую строку. -- Смотрите пример запроса с объединением в разделе "Примеры запросов универсальной статистики" ,"join" : [ -- объединяемы запросы. обязательно { Единичный запрос-1 } ,{ Единичный запрос-2 } ,{ Единичный запрос-3 } .... ] ,"groupby" : "число" -- обязательно. больше или равно 1 -- размер уникального ключа для объединения результатов -- 0 - без ключа. объединяются все колонки. (например вы выбираете min() из нескольких объектов) -- 1 - первая колонка каждого результата единичного запроса -- 2 - первая и вторая -- 3 - первая, вторая и третья -- и так далее ---- Прочие параметры -- заголовки столбцов -- предназначены для создания заголовков в csv и xlxs, но появятся в ответе и при ответе "response" -- содержимое и количество элементов не анализируется, вы можете задать заголовков и меньше и больше количества столбцов данных ,"caption" : [ -- не обязательно "адын" ,"дыва" ,"тры ...... ] ,"result" : "response|email|save|none" -- cпособ возврата результата: -- response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен -- email - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id -- save - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id -- none - ответ всегда пустой массив. этот вариант полезен только для использования -- c кэшированием в режиме refresh - кэш обновляется, а сами данные не высылаются -- для сокращения размера ответа ---- дополнительные параметры запроса зависящие от result -- email ,"email" : [ e@mail1 ,e@mail2 ... ] -- адреса получателей отчетов -- email или save ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv) }
ответ
{ <общие поля> -- для result = email или save ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"list" : [ [строка1,данные в порядке заданом в select] [строка2,данные в порядке заданом в select] [строка3,данные в порядке заданом в select] ........ ] }
У полей типа дата можно указать что требуется не сама дата, а производные от неё величины:
Запись dt:DOW означает получение номера дня в неделе от значения даты.
Результатом является число от 1 до 7 - Пн -1 .... Сб - 6, Вс -7
В условиях понимает также 0 как воскресенье и английские полные названия дней, а так же их английские трёх и двух буквенные аббревиатуры (регистр не важен)
Запись dt:DOY означает получение номера дня в году от значения даты.
Результатом является число от 1 до 366.
Запись dt:WOY означает получение номера недели в году на которую приходится значения даты.
Результат возвращается как YYYY-Www, где YYYY - год, ww - номер недели от 01 до 53.
Номер недели определяется по ГОСТ ИСО 8601-2001: первой неделей года считается та, в который есть первый четверг года. (для григорианского календаря - та где 4 января).
Таким образом, начальные дни нового года могут быть в последней неделе прошлого года. И последние дни прошлого года - в первой неделе нового года.
Например:
2000-12-31 даст 2000-W52 - конец года в его последней неделе
2001-12-31 даст 2002-W01 - конец года в первой неделе следующего года
2012-01-01 даст 2001-W52 - первый день года в последней неделе предыдущего года
2012-01-02 даст 2002-W01 - а второй уже в первой неделе своего года
2014-05-04 даст 2014-W18 - просто дата на 18 неделе года
Запись dt:CW1D означает получение даты первого дня недели на которую приходится значения даты.
Результат возвращается как дата с точностью до дня YYYY-MM-DD
Начало недели определяется по ГОСТ ИСО 8601-2001: понедельник.
Для полей типа дата возможно сравнение с текущим временем +/- сдвиг.
Для этого значение v записывается в виде
"сurrent +Y year +M month +D day +h hour round +m minute round +s second"
Все поля задающие сдвиг не обязательны, но их порядок от года к секунде должен соблюдаться.
К названию величины можно добавлять на конце "s"
Указатели округления часов и минут - round - не обязательны.
Результат вычисления current всегда неявно приводится к точности поля заданом в ключе "a"
Например, в условии
issue.dt:YM < current - 1 day
точность результата "current - 1 day" неявно преобразуется к YM.
Особенность Григорианского календаря такова, что просто так отнимать/прибавлять от даты месяца и года нельзя, так как в месяце получившейся новой даты может не быть такого дня.
По этому вычитание годов или месяцев округляет результат.
Например, если сегодня 30е марта, то вычитание 1го месяца даст февраль, а 30е февраля было ранее только в 1712 году и следующий раз может быть, предположительно, в 3328 году.
Например, если сегодня 31 декабря, то вычитание 3х месяцев даст 31 сентября.
Например, если сегодня 29 февраля, то вычитание 1 года даст 29 февраля прошлого года, который явно не високосный.
Строго формально всё ещё хуже - бывает 61я секунда в минуте (не так уж и редко, последние разы 31 декабря 2008 23:59:60 и 30 июня 2012 23:59:60) и 23 или 25 часов в сутках (при переходе на и с летнего времени час или выпадает или добавляется, и без указания временной зоны один час может или пропасть или встретиться дважды). Но это системой не учитывается.
Вычитание/прибавление 1 дня можно записать как вычитание/прибавление 24 часов, по этому вычитание дней тоже округляет результат что иметь возможность установить время в 0:0:0.
А вычитание/прибавление часов - не округляет.
Округление часов указываемое словом round необходимо когда временной отрезок должен начинаться точно от начала часа.
Без округления результат сохранит текушие минуты и секунды дав время "на N часов назад/вперёд"
С округлением минуты и секунды будут установлены в 0 что даст время "начало часа N часов назад/вперёд"
Округление минут работает аналогично округления часов - секунды устанавливаютс в 0 и вы получаете точно начало минуты.
точность даты понижается до года
к/из полученой даты прибавляются/вычитаются указанное количество лет
результат преобразуется обратно к точности год-секунда установкой первого месяца первого числа 0 часов 0 минут 0 секунд
точность даты понижается догода-месяца
к/из полученой даты прибавляются/вычитаются указанное количество месяцев
результат преобразуется обратно к точности год-секунда установкой первого числа 0 часов 0 минут 0 секунд
точность даты понижается до года-месяца-дня
к/из полученой даты прибавляются/вычитаются указанное количество дней
результат преобразуется обратно к точности год-секунда установкой 0 часов 0 минут 0 секунд
с округлением
точность даты понижается до года-месяца-дня-часа
к/из полученой даты прибавляются/вычитаются указанное количество часов
результат преобразуется обратно к точности год-секунда установкой 0 минут 0 секунд
без округлением
к/из полученой даты прибавляются/вычитаются указанное количество часов
с округлением
точность даты понижается до года-месяца-дня-часа-минуты
к/из полученой даты прибавляются/вычитаются указанное количество минут
результат преобразуется обратно к точности год-секунда установкой 0 секунд
без округлением
к/из полученой даты прибавляются/вычитаются указанное количество минут
Примеры простые
сейчас
current
cейчас минус 1 час 3 минуты плюс 4 секунды
current -1 hour -3 minutes +4 second
сейчас минус 40 дней назад плюс 78 часов
current -40 days + 78 hours
что-то произошло за два последних часа
dt >= current - 2 hours
что-то произошло за два последних часа и только за них не считая текущий час
dt >= current - 2 hours round and dt < current - 0 hours round
выпуск состоялся в прошлом месяце (ниже есть пример считающийся быстрее)
issue.dt:YM == current - 1 month
выпуск состоялся в прошлом месяце и ранее (ниже есть пример считающийся быстрее)
issue.dt:YM <= current - 1 month
выпуск состоялся вчера
issue.dt:YM == current - 1 day
выпуск состоялся за последнии 24 часа
issue.dt:YM > current - 24 hours
выпуск состоялся начиная с 5 числа прошлого месяца и позже
обратите внимание, что вычитается 4 дня - так как вычитание месяца установит день в 1, то для получения 5го числа надо прибавить 4, а не 5
issue.dt >= current - 1 month + 4 days
выпуск состоялся начиная с 3 числа текушего месяца и позже
обратите внимание, что вычитание ноля месяцев использовано для сброса дня в 1 и уже потом коррекции его до 3
issue.dt >= current - 0 month + 2 days
Примеры, если вы хотите что бы считалось быстрее (но записывать зато сложнее):
Ускорение расчётов основано на том, что округлять до месяца дату каждого проверяемого выпуска и сравнивать с нужным будет дольше, чем не меняя даты сравнивать её константой,
хоть хитро записаной, но вычисляемой только один раз.
выпуск состоялся в прошлом месяце и ранее
"current - 0 month" даст начало текущего месяца, а вычитание "1 second" даст последнюю секунду прошлого месяца
issue.dt <= current - 0 month - 1 second
выпуск состоялся ровно в прошлом месяце
"current - 1 month" даст начало прошлого месяца
"current - 0 month" даст начало текущего месяца, а вычитание "1 second" даст последнюю секунду прошлого месяца_
issue.dt >= current - 1 month И issue.dt <= current - 0 month - 1 second
Примеры быстрого сравнения для самостоятельного понимания:
выпуск состоялся с 4 мая до 20 августа этого года
issue.dt >= current - 0 year + 4 month + 3 days И issue.dt < current - 0 years + 7 month + 19 days
выпуск состоялся с 4 мая по 20 августа этого года
issue.dt >= current - 0 year + 4 month + 3 days И issue.dt <= current - 0 years + 7 month + 20 days - 1 second
Поля типа дата (помечены dt), временные константы и "текущее время" задаются временем московского часового пояса (с неявным подразумеванием зимнего или летнего времени).
Отметка dt:Ys обозначет, что поле имеет значение времени с точность от года (Y) до секунды (s).
Отметка (null) обозначает, что поле может иметь неопределённое значение.
Например если выпуск рассылки не использовал ни какой черновик, то значение поля issue.draft.id будет не опеределено.
Все логические операции с полем имеющим неопределённое значение всегда не выполняются.
Например, неопределённое значение номера черновика не попадёт под фильтр issue.draft.id > 10, но так же оно не попадёт и под фильтр issue.draft.id <= 10.
Запись xxx.yyy.* обозначает что доступны все поля объекта yyy.
Например, при наличии у объекта yyy поля zzz, можно его получить через xxx.yyy.zzz
Если какое-то поле является набором полей другого объекта, то доступны даже те поля другого объекта, что сами являются наборами полей.
Например, так как в объекте Клик доступны все поля объекта Выпуск (cliсk.issue.*), а в объекте Выпуск - объекта Группа (issue.group.*), то можно получить значение поля "Название группы из выпуска которой был этот клик" - сlick.issue.group.name
domain.id - id домена domain.name - назвение домена
member.id - id подписчика member.email - значение email или телефона подписчика member.haslock - блокировка подписчика 0 - нет - может получать письма или sms 1 - отписался - не может получать письма или sms 2 - не подтверждён - не может получать письма или sms 4 - имеет фатальные ошибки доставки - не может получать письма или sms прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указаных блокировок member.domain.* - информация о домене подписчика -- информация об ошибках доставки. все поля null если последняя доставка была успешной. member.error.error - количество ошибок доставки (null) member.error.lock - 0|1|null - адрес заблокирован (1) из-за ошибок (в зависимости от количества и типа ошибок) (null) - заблокированный адрес не участвует в рассылке и попадает в статистику как hardbounced member.error.dt - дата последней ошибки доставки (YYYY-MM-DD hh:mm:ss) (null) member.error.str - текст последней ошибки доставки (null) -- информация из анкет подписчика member.anketa.ANKETA.QUEST - значение ответа QUEST из анкеты ANKETA. - при отсутствии ответа на указаный вопрос результат null - *в данный момент допустимо только в select* - *в данный момент не может быть параметром функций агрегации*
Существует специальная особенность связанная с выборкой данных подписчика.
Пока вы используете в запросе поля id и email, вы получаете данные о всех подписчиках.
Как только в запросе появляется поле haslock, вы начинаете получать данные только о тех подписчиках, запись о которых до сих пор есть в вашей базе.
Это связано с тем, что информация о адресе подписчика и его номере хранится всегда, а информация о блокировке только при наличии записи о пользователе в вашей базе и она пропадает если вы его удаляете.
Пример когда проявится разница - запрос адресов участвовавших в выпуске ("select":["member.email"]) вернёт все адреса попавшие в выпуск, а такой же запрос с дополнительной выборкой текущего состояния блокировки ("select":["member.email", "member.haslock"]) вернёт только тех, кого вы ещё не удалили из своей базы.
Эту особенность можно использовать специально для отсечения тех кто из базы уже удалён. Фильтр member.haslock >= 0 выберет подписчиков с любым состоянием блокироваки, но приведёт к исключению из результатов тех кто уже удалён.
group.id - id группы group.gid - символический код группы group.name - название группы
Поля с количеством отсеяных участников содержат актуальное значение для выпусков начиная с 26-07-2013.
Для более ранних выпусков поля содержат 0.
Поле issue.cost содержит актуальное значение для выпусков начиная с 01-11-2013.
Для более ранних выпусков поля содержат 0 так как старая система тарификации не пересчитываема в новую.
issue.id - id выпуска issue.dt - дата выпуска (dt:Ys) issue.name - тема выпуска issue.members - число получателей выпуска issue.format - формат выпуска issue.size - размер выпуска. Для email - размер одного письма, для sms - количество выпущенных смс. issue.cost - цена выпуска. Для email - 0, для sms - в единицах тарификации, в данный момент это копейки issue.archive - ссылка на копию выпуска в веб-архиве (доступ ограничивается - см. issue.set.access) issue.access.type - тип доступа к выпуску в архиве - см issue.set.access. *в данный момент допустимо только в select* *в данный момент не может быть параметром функций агрегации* issue.access.group- группа доступа к выпуску в архиве (null) - см issue.set.access. *в данный момент допустимо только в select* *в данный момент не может быть параметром функций агрегации* issue.access.passwd пароль доступа к выпуску в архиве (null) - см issue.set.access. *в данный момент допустимо только в select* *в данный момент не может быть параметром функций агрегации* issue.double - количество дублирующихся адресов в списке. имеет смысл только для Экспресс-Выпуска. заполняется с 11-12-2013 issue.onlyunique - режим подавления дублирующихся адресов при выпуске. имеет смысл только для Экспресс-Выпуска. заполняется с 11-12-2013 - 0 - высылать письма на адреса встреченные второй и более разы - 1 - НЕ высылать письма на адреса встреченные второй и более разы issue.wrongline - количество строк в списке (cvs или json) которые система не смогла разобрать и они были отброшены. имеет смысл только для Экспресс-Выпуска. заполняется с 11-12-2013 issue.hardbounce - количество участников группы не допущенных в выпуск из-за большого количества ошибок доставки issue.stoplist - количество участников группы не допущенных в выпуск из-за нахождения их адреса в стоп-листе issue.lockunsub - количество участников группы не допущенных в выпуск из-за того что их адрес отписан issue.lockconfirm - количество участников группы не допущенных в выпуск из-за того то внесение в базу ими ещё не подтверждено issue.group.* - информация о группе по которой был выпуск issue.draft.id - номер черновика использованного при выпуске (null) issue.sequence.id - номер последовательности вызвавшей выпуск (null) issue.variant.id - номер варианта сплит-тестирования для которого вышел выпуск (null) issue.thumbnail_640x1100 - ссылка на изображения письма выпуска 640x1100 (подробности в issue.get) (null) issue.thumbnail_150x180 - ссылка на изображения письма выпуска 640x1100 (подробности в issue.get) (null) -- суммарная статистика по выпуску. -- это кэш. первые 5 дней он обновляется раз в 15 минут. потом - раз в три часа issue.deliv_ok - количество успешно доставленных писем issue.deliv_bad - количество писем с ошибкой доставки issue.clicked - количество кликов issue.u_clicked - количество уникальных кликов issue.readed - количество чтений issue.u_readed - количество уникальных чтений issue.unsubed - количество отписок из выпуска -- суммарная статистика по выпуску за час -- это кэш. он обновляется раз в 20 минут issue.hourly.dt - дата и час (YYYY-MM-DD hh) для которых сгруппирована статистиска issue.hourly.clicked - количество кликов issue.hourly.u_clicked - количество уникальных кликов issue.hourly.readed - количество чтений issue.hourly.u_readed - количество уникальных чтений issue.hourly.unsubed - количество отписок из выпуска -- суммарная статистика по выпуску/домену за день -- это кэш. он обновляется раз в 20 минут issue.daily.domain.id - id домена issue.daily.domain.name - название домена issue.daily.dt - дата (YYYY-MM-DD) для которой сгруппирована статистиска issue.daily.deliv - общее количество писем. в первый день рассылки учитывает ok+bad+unk. в остальные - только ok+bad issue.daily.deliv_ok - количество успешно доставленных писем issue.daily.deliv_bad - количество писем с ошибкой доставки issue.daily.clicked - количество кликов issue.daily.u_clicked - количество уникальных кликов issue.daily.readed - количество чтений issue.daily.u_readed - количество уникальных чтений issue.daily.unsubed - количество отписок из выпуска -- География кликнувших и прочитавших issue.geo.id - числовой код географии CCCRR000 - CCC числовой код страны по ISO 3166-1, RR - для России числовой код региона по ОКАТО/ОКТМО и 00 для прочих стран и не определившегося региона России issue.geo.name - название географии на русском языке "Страна. Регион" или "Страна" если регион не определён issue.geo.country.id - числовой код страны по ISO 3166-1 issue.geo.country.alpha2 - двухбуквенный код страны по ISO 3166-1 issue.geo.country.name - название страны на русском языке issue.geo.region.alpha5 - пятисимвольный код региона по ISO 3166-2 (имеет вид XX-XXX) для России и совпадает с alpha2 для прочих стран issue.geo.region.name - название региона для России на русском языке, пусто для прочих стран -- Устройство подписчика issue.gadget.gender - Desktop, Mobile, Tablet, Robot issue.gadget.os - Linux, Android, Windows, iOS, Mac, Blackberry, Other issue.gadget.browser - Firefox, Chrome, Opera, Safari, IE, Blackberry, Other issue.gadget.browmajor - старшая часть версии браузера
link.id - id ссылки link.url - url ссылки link.reltype - параметр классификации -- отрицательные значения зарезервированы для системы -- в данный момент: -- -1 - ссылка из выпуска рассылки -- -2 - ссылка - целевая страница достигнутая подписчиком link.relref - параметр классификации link.linkgroup.* - информация о группе в которую входит ссылка
linkgroup.id - группы ссылок linkgroup.name - name группы ссылок linkgroup.reltype - параметр классификации linkgroup.relref - параметр классификации
Не забывайте уточнять в запросе click.link.reltype !
Например, при подсчёте всех кликов из выпуска и без его указания вы получите информацию как по самим кликам из выпуска (reltype=1), так по посещения Целевых Страниц (reltype=-2). Уточните в фильтре не только номер выпуска, но и классификацию ссылки.
click.dt - дата и время клика (dt:Ys) click.ip - ip кликнувшего click.member.* - информация о кликнувшем подписчике click.domain.* - информация о домене кликнувшего подписчика click.issue.* - информация о выпуске из которого был клик click.link.id - id ссылки click.link.url - url ссылки click.link.reltype - параметр классификации click.link.relref - параметр классификации click.linkgroup.* - группы ссылок
read.dt - дата и время чтения (dt:Ys) read.member.* - информация о прочитавшем (открывшем письмо) подписчике read.domain.* - информация о домене прочитавшего подписчика read.issue.* - информация о выпуске который был прочтён
deliv.member.* - информация о подписчике-получателе deliv.domain.* - информация о домене подписчика-получателя deliv.issue.* - информация о выпуске который доставлялся deliv.status - код статуса доставки - больше 0 - доставлено - равно 0 - в процессе доставки - мешьше 0 - ошибка доставки или отсеян из рассылки - Для писем кода ошибок обозначают - -2 - все попытки доставки успеха не имели, но и не был получен ответ, что точно не примут - -3 - письмо приняли за спам - -5xx - код ошибки SMTP-DSN 5xxx - -15xx - код ошибки SMTP (5xx) сдвинутый на -1000 - Для sms кода ошибок обозначают - -2000 - прочие ошибки - -2003 - истекло время доставки - -2004 - sms-центр принял сообщение, но потом не стал доставлять и просто удалил - -2005 - не удалось доставить на телефон абонента - -2006 - sms-центр сообщил, что потерял информацию о статусе доставки - -2007 - неизвестная ошибка доставки - -2008 - sms-центр сразу отверг сообщение - Статусы описывающие адреса/телефоны которые потенциально могли быть - в рассылке, но были отсеяны из списка получателей - ещё на этапе формирования - т.е. письмо/смс вообще не формировалось. - По умолчанию сбор этих статусов не активен. Для его включения обратитесь в саппорт. - -100010 - Адрес в стоп-листе - -100011 - Адрес имеет постоянные ошибки доставки - -100012 - Адрес не подтверждён - -100013 - Адрес отписался - -100014 - Оператор получателя вам недоступен (для sms) deliv.result - результат доставки - 1 - доставлено - 0 - в процессе доставки - -1 - ошибка доставки -- для sms-рассылок (до 04.12.2013 - null, для email-рассылок - null) deliv.oper - оператор получателя (null) - other - 0 - megafon - 1 - skylink - 2 - mts - 3 - beeline - 4 - tele2 - 5 deliv.size - количество смс использованых для передачи сообщения (null) deliv.cost - стоимость сообщения. сотых долях копейки (null)
Вместо префикса deliv можно использвать префиксы
unsub.dt - дата получения информации об отписке (YYYY-MM-DD hh:mm:ss) unsub.why - способ отписки - 1 - нажав кнопку "Это спам" в своей почтовой системе - 2 - по ссылке отписаться или через наш сайт - 3 - через жалобу в нашу службу поддержки unsub.member.* - информация об отписавшемся подписчике unsub.domain.* - информация о домене отписавшегося подписчика unsub.issue.* - информация о выпуске из которого отписались, если он известен (null)
datarow.id - идентификатор ряда данных datarow.name - название ряда данных datarow.prec - точность даты ряда данных -- Одна запись ряда данных datarow.record.dt - дата записи - ! дата всегда возваращается с точность Ys вне зависимости от datarow.prec datarow.record.value - значение записи
При повторном заполнения подписчиком формы старые данные заменяются новыми
form.id - идентификатор формы
form.name - название формы
form.state - состояние формы
form.member.id - id заполнившего
form.member.email - адрес заполнившего
form.member.dt_fill - дата заполнения Ys (null)
form.member.dt_confirm - дата подтверждения заполнения Ys (null)
stat.common.dt - дата (YYYY-MM-DD) stat.common.tarif - код тарифа на эту дату -- данные вызова member.list.count на эту дату. все поля null до 29.01.2014 stat.common.emails - количество адресов в базе stat.common.phones - количество телефонов в базе stat.common.active_emails - количество адресов способных участвовать в рассылках stat.common.active_phones - количество телефонов способных участвовать в рассылках stat.common.locked - уникальное количество заблокированных - не могут быть в рассылке. stat.common.stoplist - в том числе заблокированные так как находятся в стоп-листе stat.common.lockconfirm - в том числе заблокированные так как не подтвердили внесение в базу stat.common.hardbounce - в том числе заблокированные так как имеют фатальные ошибки доставки stat.common.lockunsub - в том числе заблокированные так как отписались
Возможно одновременное использование следующих сочетаний полей в одном запросе
Специальные названия полей используются для функций count() и sum() если в запросе участвуют несколько типов статистики.
Область вычисления функции задается аргументом.
В фильтре можно использовать поля из конкретной области статистики.
*.dt - дата события *.issue.id - id выпуска *.issue.name - тема выпуска *.issue.group.id - id группы выпуска *.issue.group.gid - код группы выпуска *.issue.group.name - name группы выпуска *.issue.dt - дата выпуска *.issue.members - число получателей выпуска *.issue.format - формат выпуска *.issue.deliv_ok - количество успешно доставленных писем *.issue.deliv_bad - количество писем с постоянной ошибкой доставки *.issue.clicked - количество кликов *.issue.u_clicked - количество уникальных кликов *.issue.readed - количество чтений *.issue.u_readed - количество уникальных чтений *.issue.unsubed - количество отписок из выпуска *.issue.draft.id - номер черновика использованного при выпуске (null) *.issue.sequence.id - номер последовательности вызвавшей выпуск (null) *.issue.variant.id - номер варианта сплит-тестирования для которого вышел выпуск (null) *.member.id - id подписчика *.member.email - значение email или телефона подписчика *.member.haslock - блокировка подписчика
Ряд Данных предназначен для хранения статистики из внешних источников.
Ряд Данных позволяет хранит наборы пар (дата,число)
Дата - от YY до Yh, уникальна в Ряде Данных.
Число - целое
Пополнять Ряд Данных можно задавать непосредственно из данных вызова, из csv- или xlsx-файлов с указание по какой ссылке их забирать, из статистических данных Google Analitics.
Использование Рядов Данных в вызове Универсальной Статистики в сочетании с выборкой данных по выпуску рассылки (клики, чтения, доставки) позволит оценить, например, изменение посещаемости после рассылки.
{ "action" : "datarow.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "идентификатор рядя данных" ,"name" : "название ряда данных" ,"prec" : "точность даты ряда данных" ,"reltype" : ... ,"relref" : ... } ... ] }
{ "action" : "datarow.get" ,"id" : "идентификатор ряда данных" }
ответ
ответ
{ <общие поля> ,"obj" : { "id" : "идентификатор рядя данных" ,"name" : "название ряда данных" ,"prec" : "точность даты ряда данных" ,"ga.bind" : "привязка к GA" ,"ga.request" : { параметры запроса к Google Analictics } ,"reltype" : ... ,"relref" : ... } }
{ "action" : "datarow.create" ,"name" : "название ряда данных ,"prec" : "точность даты ряда данных" -- "YY" - год, "YM" - год-месяц, "YD" - год-день, "Yh" - год-час -- точность даты указывается при создании и в дальнейшем изменена быть не может -- не обязательная привязка к Google Analitics ,"ga.bind" : "id авторизации" -- ссылка на объект authext хранящий авторизацию ,"ga.request" : { -- игнорируется при пустом или отсутсвующем ga.bind -- параметры запроса к Google Analictics для пополнения ряда данных через Сore Reporting API -- https://developers.google.com/analytics/devguides/reporting/core/v3/reference -- -- запрос должен возвращать в первой колонке дату, во второй - значение -- обратите внимание, что GA возвращает дату с точностью YD и, следовательно, может использовать -- только если точность ряда данных YD и меньше -- -- запросы к GA для полнения записей система будет производить автоматически сама "ids" : "...." ,"metrics" : "...." ,"dimensions" : "...." ,"segment" : "...." ,"filters" : "...." } ,"reltype" : ... ,"relref" : ... }
ответ
{ <общие поля> ,"id" : "идентификатор созданного ряда данных" }
Обновляются только указанные в запросе поля
Точность ряда данных изменить нельзя
{ "action" : "datarow.set" ,"id" : "идентификатор ряда данных" ,"name" : "новое название ряда данных ,"ga.bind" : "новая авторизация к GA авторизации" -- укажите пусто что бы удалить привязку к GA ,"ga.request" : { новый запрос к GA } -- игнорируется при пустом или отсутсвующем ga.bind ,"reltype" : ... ,"relref" : ... }
ответ
{ <общие поля> }
{ "action" : "datarow.delete" ,"id" : "идентификатор ряда данных" }
ответ
{ <общие поля> }
Вызов позволяет внести, изменить или удалить записи.
Одна запись состоит из пары "дата" (идентифицирует запись в данном ряду данных) и соответствующего дате "числа".
Дата может задавать в любой точностью не меньшей чем указана при создании ряда данных.
Формат даты - YYYY-MM-DD hh:mm:ss или YYYYMMDDhhmmss
Лишние компоненты даты отбрасываются.
При наличии в данных нескольких записей для одной даты, результатом будет обработка последней.
Число - положительное или отрицательное число или ноль или пусто. Дробная часть, при наличии, отбрасывается.
Запись для отсутствующей ещё даты создаётся автоматически.
Запись для уже существующей даты изменяет значение на новое, если число не пусто, или удаляется, если задано пустое значение.
При указании файла или ссылки на файл поддерживается содержимое сжатое zip.
Если файл - таблица xlsx, то данные берутся с первого листа. Одна строка - одна запись. По умолчанию первая колонка интерпретируется как дата, вторая как число.
Иначе файл считается текстовым (csv) с попыткой автоматически определить разделитель из возможных (запятая, точка с запятой, вертикальная черта, табуляция). Одна строка - одна запись. Первая колонка - дата, вторая число.
Если Ряд Данных связан с Google Analitics, то он пополняется автоматически. Но можно пополнить его и по своему желанию использовав данный вызов в варианте с ga.
Положение колонки с датой и числом для любого способа задания данных можно указать явно через dt.index и value.index, если они отличаются от 0 и 1. Нумерация с нуля.
{ "action" : "datarow.load" ,"id" : "идентификатор ряда данных" ,"dt.index" : "индекс колонки с датой" -- по умолчанию 0 ,"value.index" : "индекс колонки с числом" -- по умолчанию 1 -- или получение данных из Google Analitics (требуется заранее заполнить ga.bind и ga.request "ga" : { -- указанные тут параметры сильнее параметров сохранённых в ga.request "start-date" : "YYYY-MM-DD | today | yesterday | NdaysAgo | minimum" ,"end-date" : "YYYY-MM-DD | today | yesterday | NdaysAgo" ,прочие параметры которые может понять Google Analitics } -- или получения данных из внешнего файла "url" : "ссылка на файл" -- или явное задание структуры данных "list" : [ [ "дата-1", "число-1"] ,[ "дата-2", "число-2"] ,[ "дата-3", "число-3"] ...... ] -- или задание данных содержимым файла "list" : "содержимое файла" }
ответ
{ <общие поля> ,"count" : число добавленных, изменённых или удалённых записей ,"warnings" : [ описание ошибочных строк проигнорированных при обработке - причина и номер строки ] }
Альтернатива удалению записей по одной через datarow.load.
Удаляются все записи попадающие в указанный диапазон дат и значений.
В целях безопасности пустой фильтр игнорируется (формально он означал бы удаление всего).
Для удаления всех записей ряда данных используйте filter со специальным значением "ALL".
{ "action" : "datarow.clean" ,"id" : "идентификатор ряда данных" -- или ,"filter" : [ -- обязательно фильтр как для stat.uni по полям datarow.record.dt и datarow.record.value ] -- или ,"filter" : "ALL" }
ответ
{ <общие поля> ,"count" : "количество удалённых записей" }
Cобытийные действия предназначены для автоматизации реакции системы в ответ на те или иные события происходящие с пользователем или вызванные его действиями.
Для задания автоматической реакции системы на те или иные действия/бездействия пользователя создайте "Последовательность" описывающую что ("Действия") в ответ на какие события ("Cобытия") в каком порядке ("Шаги","Варианты") должно происходить.
На каждом Шаге последовательности можно задать несколько сценариев развития событий создав несколько Вариантов описав какие События активируют какой вариант (один вариант могут активировать несколько разных действий) и задать какие Действия (одно или несколько) должны быть выполнены в каждом из вариантов.
Как простой частный случай с помощью событийных действий можно реализовать триггерные рассылки (автоответчики) - задайте на первом шаге условие начала последовательности и как действие - первое высылаемое письмо.
На следующий шагах задавайте интервал времени до высылки следующего письма и его высылку в действиях.
Для придания автоответчику интелектуальности можно, например, сочетать события "Клик" и "Прошло время" для выбора какое из писем высылать далее, действия "Изменить данные" что бы учитывать на какое из высланых писем пользователь среагировал, действия "Завершить последовательность" что бы прекратить высылать подписчику письма при отсутствии инетереса, действие "Перейти на другую последовательность" что бы сменить тематику в зависимости от его реакции.
В более сложных случаях можно организовать автоматические напоминания о забытых корзинах в интернет-магазинах, автоматическое изменение статуса покупателя в зависимости от числа покупок и даже квест-игры по электронной почте.
Каждое событие произошедшее в системе проверяется не подходит ли оно в какой-либо последовательности к её первому шагу или к текущему шагу уже находящегося на последовательности пользователя.
Проверка производится путём просмотра всех условий каждого из вариантов шага. Если в данном варианте шага событие подходит к одному из условий, то дальнейший поиск в данном шаге последовательности прекращается и выполняются все действия описанные в том варианте к которому подошло событие после чего пользователь переходит на следующий шаг последовательности.
Подходящее событие может быть проигнорировано если пользователь или последовательно находятся в состоянии паузы.
Подходящее событие может не вызвать начало прождения пользователем последовательности если этому мешают настройки разовости и закрытости последовательности.
Можно ли ещё раз начать прохождение последовательности, если она уже была пройдена или проходится в данный момент.
В данный момент не реализовано !
Можно ли одновременно проходить последовательность несколько раз и если можно, то при запуске нового прохождения прервать ли текущие
Новые участники не могут начать последовательность при наступлении подходящих событий.
Однако новый участник может быть добавлен вызовом sequence.member.start
Это полезно для тестирования. Отметьте последовательность закрытой на время её создания и тестирования, что бы ни кто из обычных пользователей не мог случайно начать её прохождение. А тестовых пользователей вы можете добавить через sequence.member.start
Ни как не влияет на прождение последовательности уже имеющимися участниками.
Cобытия не учитываются и значит ни кто не продвигается по последовательности и не начинает её. Пропущенные события теряются.
Возобновление прохождения при увеличении количества шагов.
Участники, завершившие ранее прохождение последовательности путём дохождения до её последнего шага, автоматически возобновят её прохождение с шага, следующего за тем на котором они закончили.
Для одного участника возобновляется только одно, имеющее максимальный номер шага-окончиния, прохождение.
Не возобновляется участник и так проходящий последовательность в момент её удлиннения не смотря на параметр parrallel.
Наступает когда пользователь первый раз вносится в базу и на это от него не требуется подтверждения регистрации.
Обратите внимание, что это событие должно быть в последовательности только первым и в другой позиции просто не сработает никогда по логике.
{ "type" : "member.new.no-confirm" }
Наступает когда пользователь первый раз вносится в базу и от него требуется подтверждение регистрации.
Обратите внимание, что это событие должно быть в последовательности только первым и в другой позиции просто не сработает никогда по логике.
{ "type" : "member.new.confirm" }
Наступает когда пользователь подтверждает регистрацию.
{ "type" : "member.confrim" }
Наступает когда пользователь отписывается (т.е. запрещает дальнейшую высылку ему чего-либо)
{ "type" : "member.unsubscribe" }
Не может быть в списке у вариантов первого действия последовательности.
Наступает когда с момента попадания на данных шаг прошёл указаный интервал времени равный указанному количеству дней, часов и минут.
{ "type" : "time.elapsed" ,"interval" : "DDDDD hh:mm" или "hh:mm" или "mm" -- DDDDD - до пяти цифр количества дней -- hh - количество часов -- mm - количество минут }
Не может быть в списке у вариантов первого действия последовательности.
Наступает когда текущее время совпало с заданными ожидаемыми.
Зачем ? Например удобно накопить желающих начать какой либо курс и разом начать его в удобный день высылкой первого письма.
Можно указать:
{ "type" : "time.happened" ,"weekday" : "номер дня недели" -- не обязятельно при наличии time -- 1-6 - Пн-Сб, 7 - Вс -- вызов sequence.steps.set дополнительно принимает 0 как Вс, но при записи преобразует в 7 ,"time" : "дата и время" -- не обязательно при наличии wekday -- ММ - месяц -- DD - день -- hh - час -- mm - минута -- Допустимые сочетания дня недели, даты и времени: -- "MM-DD hh:mm" -- "DD hh:mm" -- "hh:mm" -- weekday -- weekday + "hh:mm" }
Наступает когда пользователь нажимает на ссылку в высылаемых ему письмах.
Рассылки должны выпускаться с преобразванием ссылок для учёта переходов, иначе клик системой замечен не будет. При высылки письма по действию "Выслать письмо" такое преобразование включается автоматически.
Клик по определённой ссылке в письме обычной рассылки ("свободный клик") приведёт к наступления события "Клик" во всех последовательностях где такое событие ожидается на первом шаге для этой ссылки и где состояние настроек последовательности позволяет ему начать её прохождение.
В результате свободного клика для кликнувшего пользователя в каждой начатой им последовательности будут выполнены предписанные там действия и он станет ждать событий на шаге 2.
Клик по определённой сслыки из письма высланого пользователю при исполнении действия "Выслать письмо" ("связаный клик") приведёт к событию "Клик" только в той последовательности из которой было выслано письмо и только если на текущем шаге пользователя ожидается такой клик. Состояние настроек последовательности или пользователя может повлиять на учёт клика.
В результате связаного клика для кликнувшего пользователя будут выполнены предписаные на его текущем шаге действия и он продвинется на следующий шаг.
{ "type" : "click.link" ,"url" : "ссылка" }
Наступает когда при изменении данных пользователя удовлетворяются (или не удовлетворяются - в зависимости от параметра *.not) условия обоих фильтров если заданы оба и едниственного фильтра если задан один.
Фильтр БЫЛО проверяет данные до изменения. Пользователя удовлетворяет условия фильтра, если его страные данные (до изменения) прошли проверку успешно, а новые (после изменения) - НЕ успешно. Т.е. данные перестали попадать под условие.
Фильтр СТАЛО - после изменений. Пользователя удовлетворяет условия фильтра, если его страные данные (до изменения) прошли проверку НЕ успешно, а новые (после изменения) - успешно. Т.е. данные стали попадать под условие.
Структура описания условий was.cond и new.cond аналогична структуре одного элемента условий фильтра у групп-фильтров.
Но не принимаются условия с типами AND, OR, group, stat.uni и PRF.
{ "type" : "member.change" --------- -- фильтр "БЫЛО. может отсутствовать при наличии фильтра "СТАЛО" ,"was.not" : 0|1 -- 0 - фильтр соблюдён если пользователь удовлетворяет условию -- 1 - фильтр соблюдён если пользователь НЕ удовлетворяет условию -- и одно из: ,"was.group" : "код группы" ,"was.group.name" : "название группы" -- только при вызове get -- или ,"was.cond" : { условие. при вызове get дополнительно aid.name и qid.name } --------- -- фильтр "СТАЛО". может отсутствовать при наличии фильтра "БЫЛО" ,"new.not" : 0|1 -- 0 - фильтр соблюдён если пользователь удовлетворяет условию -- 1 - фильтр соблюдён если пользователь НЕ удовлетворяет условию -- и одно из: ,"new.group" : "код группы" ,"new.group.name" : "название группы" -- только при вызове get или ,"new.cond" : { условие. при вызове get дополнительно aid.name и qid.name } }
Наступает когда пользователь переходит на данных шаг и его текущие данные попадают (или при match.not = 1 - не попадают) под описаное условие.
Применение - условные ветвления.
На шаге должен быть предусмотрены другие варианты действий иначе, если совпадения не будет, пользователь застрянет на этом шаге навечно.
Или в варианте с событием "Совпадение данных" должны быть альтернативные события которые могут продвинуть пользователя дальше.
Структура описания условий has.cond аналогична структуре одного элемента условий фильтра у групп-фильтров.
Но не принимаются условия с типами AND, OR, group, stat.uni и PRF.
{ "type" : "member.match" ,"match.not" : 0|1 -- 0 - совпадение если пользователь попал под условие -- 1 - совпадение если пользователь НЕ попал под условие -- одно из: ,"match.group" : "код группы" ,"match.group.name" : "название группы" -- только при вызове get или ,"match.cond" : { условие. при вызове get дополнительно aid.name и qid.name } }
Наступает когда заполняется форма опросов.
"type" : "form.filled" ,"form.id" : код формы ,"form.name" : название формы -- только при вызове get
Наступает когда пользователь подтверждает заполнение формы опросов.
"type" : "form.completed" ,"form.id" : код формы ,"form.name" : название формы -- только при вызове get
{ "type" : "noop" }
Пользователю высылается персонализованное письмо на основе черновика выпуска рассылки.
{ "type" : "send.letter" ,"draft" : "код черновика рассылки" -- обязательно -- черновик должен иметь заполненный адрес отправителя ,"draft.name" : "название черновика" -- только при вызове get }
Указанная ссылка вызывается методом GET. Результат вызова игнорируется.
Вхождение символов EMAIL заменяется на адрес пользователя.
{ "type" : "http.get" ,"url" : "http/https ссылка" }
Данные пользователя изменяются указанным в формате образом или изменяется один ответ одной анкеты указанные прямо в описании.
В целом аналогично вызову member.update
{ "type" : "member.update" ,"fire_event" : 0 | 1 -- при выполнении записать событие Изменение Данных (member.change) -- по умолчанию 0 - не записывать ,"if_has" : что делать, если изменяемый пункт анкеты уже заполнен -- "overwrite" - заменить старое значение новым из формата -- "merge" - объединить старое и новое значения -- "skip" - оставить старое значение ,"if_hasnt" : что делать, если изменяемый пункт анкеты ещё не заполнен -- "set" - заполнить указанным в формате значением -- "skip" - оставить пункт незаполненным -- одно из ,"format" : "код формата" ,"format.name" : "название формата" -- только при вызове get или ,"field" : { "aid" : "код анкеты" ,"qid" : "код ответа" ,"answer" : "значение ответа используемое при заполнении" ,"aid.name" : "название анкеты" -- только при вызове get ,"qid.name" : "название анкеты" -- только при вызове get } }
Вносит пользователя в указанную группу-список если его там ещё нет.
{ "type" : "group.in" ,"group" : "код группы" ,"group.name" : "название группы" -- только при вызове get }
Удаляет пользователя из указанной группы-списока если он там есть.
{ "type" : "group.out" ,"group" : "код группы" ,"group.name" : "название группы" -- только при вызове get }
Параллельно с текущей запускается указанная последовательность с участием этого пользователя.
Запуску погут помешать настройки запускаемой последовательности, но в текущей последовательности это ни на что не повлияет.
{ "type" : "sequence.start" ,"sequence : "код последовательности" -- при отсутвии запускает саму себя ещё раз ,"sequence.name" : "название последовательности" -- только при вызове get }
Все участия пользователя в указанной последовательности (если имеются) принудительно завершаются.
{ "type" : "sequence.stop" ,"sequence : "код последовательности" -- при отсутвии останавливает саму себя ,"sequence.name" : "название последовательности" -- только при вызове get }
Текущая последовательность принудительно завершается и запускается указанная новая последовательность с участием этого пользователя.
Запуску погут помешать настройки запускаемой последовательности, но в текущей последовательности это ни на что не повлияет.
{ "type" : "sequence.goto" ,"sequence : "код последовательности" -- при отсутвии перезапускает саму себя ,"sequence.name" : "название последовательности" -- только при вызове get }
{ "action" : "sequence.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "код последовательности" ,"name" : "название" } ... ] }
{ "action" : "sequence.create" ,"name" : "название последовательности" -- обязательно ,"onlyonce" : 0 | 1 -- последовательность однократна. по умолчанию 0 -- 0 - нет -- 1 - да ,"parrallel" : -1 | 0 | +1 -- параллельность последовательности. по умолчанию 0. -- *В данный момент не реализовано и всегда 0 !* -- 0 - нет -- +1 - да -- -1 - да, с прерыванием текуших ,"closed" : 0 | 1 -- закрытость для новых участников. по умолчанию 0 -- 0 - нет -- 1 - да ,"resume_on_growing" : 0 | 1 -- возобновить прохождение при увеличении количества шагов. по умолчанию 0 -- 0 - нет -- 1 - да ,"pause" : 0 | 1 -- отстановка последовательности. по умолчанию 0 -- 0 - нет -- 1 - да }
ответ
{ <общие поля> , "id" : "код созданой последовательности" }
{ "action" : "sequence.get" , "id" : "код последовательности" }
ответ
{ <общие поля> ,"obj" : { ,"id" : "код последовательности" ,"name" : "название последовательности" ,"onlyonce" : "однократность последовательности" ,"parallel" : "параллельность последовательности" ,"closed" : "недоступность для новых участников" ,"resume_on_growing" : "возобновить прохождение при увеличении количества шагов" ,"pause" : "отстановка последовательности" } }
Изменяются только явно заданые в запросе поля
Не заданые - остаются как были
{ "action" : "sequence.set" , "id" : "код последовательности" ,"name" : "название последовательности" - необязательный ,"onlyonce" : "однократность последовательности - необязательный ,"parallel" : "параллельность последовательности" - необязательный ,"closed" : "недоступность для новых участников" - необязательный ,"resume_on_growing" : "возобновить прохождение при увеличении количества шагов" ,"pause" : "отстановка последовательности" - необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> }
если "return_fresh_obj" : "1", то ответ -- как на запрос чтения sequence.get
{ "action" : "sequence.delete" , "id" : "код последовательности" }
ответ
{ <общие поля> }
Параметр "номер шага" в данный момент введён для поддержки возможных будущих расширений (например возможности изменения шагов по одному)
В данный момент, при сохранении нового списка шагов они упорядочиваются по возрастранию номера шага как он указан в sequence.list.set, но внутренне все шаги перенумеровываются начиная с 1 и в sequence.list.get уже фигурируют под этими номерами.
{ "action" : "sequence.steps.get" , "id" : "код последовательности" }
ответ
{ <общие поля> ,"list" : { -- описание шагов последовательности "номер шага" : [ -- список вариантов шага { -- вариант "event" : [ -- список ожидаемых событий { описание события } ,{ описание события } ..... ] ,"action" : [ -- список действий выполняемых при наступлении любого из событий { описание действия } ,{ описание действия } ..... ] } ,{ вариант } ,{ вариант } ..... ] ,"номер шага" : [ .... ] ...... ] }
Изменение списка шагов полностью заменяет текущий список на новый
Если новый содержит меньше шагов, то пользователи оказавшиеся из-за их текущего положения вне списка автоматически заканчивают проходнение.
Остальные пользователи сохраняют номер шага на котором находятся, но "смысл шага" (события, действия, варианты) может стать полностью новым в соответствии с устанавливаемым списком.
Если новый список содержит больше шагов чем старый и в последовательности разрешено автовозобновление, то пользователи закончившие ранее последовательнось путём прождения её последнего шага автоматически возобновят её прохождение.
Параметр "номер шага" - целое число - в данный момент ввёдён для поддержки возможных будущих расширений (например возможности изменения шагов по одному)
В данный момент, при сохранении нового списка шагов они упорядочиваются по возрастранию номера шага как он указан в sequence.list.set, но внутренне все шаги перенумеровываются начиная с 1 и в sequence.list.get уже фигурируют под этими номерами.
{ "action" : "sequence.steps.set" , "id" : "код последовательности" , "list" : { описание шагов последовательности как в sequence.steps.get } }
ответ
{ <общие поля> }
{ "action" : "sequence.stats" , "id" : "код последовательности" }
ответ
{ <общие поля> ,"list" : { "номер шага" : "количество пользователей на нём" ,"номер шага" : "количество пользователей на нём" .... "finished" : "количество пользователей закончивших последовательность (не важно по какой причине)" } }
{ "action" : "sequence.member.list" , "id" : "код последовательности" , "steps" : [ .... ] - список интересующих шагов. по умолчанию все. ,"groupby" : "member" | "step" - способ группировки. по умолчанию - без группировки }
ответ
{ <общие поля> -- без группировки ,"list" : [ -- список описаний каждого участника на каждом шаге { "sequence" : "последовательность" ,"step" : "позиция в последовательности или finished" ,"member" : "адрес участника" ,"state" : "cостояние" -- 0 - пауза - происходящие события игнорируются -- 1 - активен - происходящие события учитываются -- -1 - последовательность закончена -- -2 - последовательность закончена из-за sequence.member.stop -- -3 - последовательность закончена из-за parallel = 0 или -1 -- -4 - последовательность закончена из-за action = 11,12,13 -- -5 - последовательность закончена из-за изменений по указанию -- -6 - последовательность закончена из-за изменений так как участник оказался вне последовательности ,"dt" : "дата-время попадания на текущий шаг или дата окончания последовательности" } ,{ .... } ..... ] -- с группировкой по участникам ,"list" : { "адрес участника" : [ -- список для этого участника { ... } ,{ ... } .... ] ,"адрес участника" : [ -- список для этого участника { ... } ,{ ... } .... ] ..... } -- с группировкой по шагам ,"list" : { "шаг" : [ -- список для этого шага { ... } ,{ ... } .... ] ,"шаг" : [ -- список для этого шага { ... } ,{ ... } .... ] ..... } }
Указанные пользователи начинают прохождение указанной последовательности как-будто произошло одно из событий её первого шага.
Если первый шаг состоит из нескольких вариантов, то вызов закончится ошибкой и ни кто не начнёт прохождение так как непонятно какой из вариантов считать реализовавшимся.
Настройки последовательности могут влиять на возможность того или иного участника начать её прохождение.
{ "action" : "sequence.member.start" , "id" : "код последовательности" -- обязателен один из параметров: ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] или ,"group" : код группы для получения списка }
ответ
<общие поля>
Указанные пользователи приостанавливаю прохождение указанной последовательности и возобновят его при вызове sequence.member.resume
{ "action" : "sequence.member.pause" , "id" : "код последовательности" -- обязателен один из параметров: ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] или ,"group" : код группы для получения списка }
ответ
<общие поля>
Указанные пользователи возобновляют прохождение указанной последовательности
{ "action" : "sequence.member.resume" , "id" : "код последовательности" -- обязателен один из параметров: ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] или ,"group" : код группы для получения списка }
ответ
<общие поля>
Указанные пользователи завершают прохождение указанной последовательности на каком бы её шаге не находились
{ "action" : "sequence.member.stop" , "id" : "код последовательности" -- обязателен один из параметров: ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] или ,"group" : код группы для получения списка }
ответ
<общие поля>
{ "action" : "sequence.member.membershipsequence.member.membership" , "id" : "код последовательности" -- не обязательно , "email" : "адрес пользователя" }
ответ
{ <общие поля> ,"list" : { "код последовательности" : [ -- список описаний шагов -- структура одно элемента описана в вызове sequence.member.list { ... } ,{ ... } .... ] ,"код последовательности" : [ -- список описаний шагов { ... } ,{ ... } .... ] ..... }
Формы опросов предназначены для получения информации от пользователей c сохранением её в анкеты.
Предусмотрен механизм верфикации заполнения формы при котором данные попадают сначала в первичную анкету (анкету-формы) и только после подтверждения в основные анкеты (анкеты-хранилища).
Данные анкеты-формы и анкет-хранилищ всегда доступны для просмотра и использования в рассылках. В зависимости от того, на сколько вам важна верификая заполнения вы можете пользоваться в работе как сразу первичными данными из анкеты-формы, так и только подтверждёнными даными из анекет-хранилищ.
Форма размещается клиентом у себя или созданой на сервисе входной странице landing-page.
После заполнения пользователем формы введённые данные сохраняются в указанную начальную анкету-формы, ему высылается fill-letter и он попадает на welcome-page (или welcome-redirect).
После подверждения заполнения формы (как описано в высланом ранее fill-letter), данные переносятся (если запланировано) из анкеты-формы по описаным в ней правилам в анкеты-хранилища, пользователю высылается welcome-letter и он попадает на fill-page (или fill-reedirect).
Заполнение и подтверждение формы так же пораждают тригерные события для расширения логики обработки. При переносе данных в анкеты-хранилища так же пораждается событие "Данные пользователя изменились".
В зависимости от того, опознала ли система пользователя при заполнении формы и разрешено ли внесение адресов без подтверждения, алгоритм работы формы может пропускать шаги связанные с подтверждением заполнения формы.
Через вызов stat.uni можно получить статистику заполнения форм.
{ "action" : "form.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор" ,"name" : "название" ,"state : "состояние" ,"dt" : "дата создания" } ... ] }
{ "action" : "form.get" ,"id" : "идентификатор формы" }
ответ
{ <общие поля> "obj" : { "id" : "идентификатор формы" ,"name" : "название" ,"dt" : "YYYY-MM-DD" -- дата создания ,"state" : 0|1 -- состояние: 0 - форма отключена, 1 - активна ,"preview" : 0|1 -- при возврате подписчика к форме из-за ошибки заполнения заполнять её ранее введёнными данными ,"anketa" : анкета-форма в которую собираются данные ,"group" : группа-список в которую попадают заполнившие форму. не обязательно ,"landing" : { "webpage" : id веб-страницы служащей шаблоном для отрисовки landing-page. не обязательно } ,"fill" : { "draft" :id черновика высылаемого как fill-letter. не обязательно -- или одно из или вообще ничего: ,"webpage" : id веб-страницы служащей шаблоном для отрисовки fill-page ,"link" : id ссылки для fill-redirect } ,"welcome" : { "draft" :id черновика высылаемого как welcome-letter. не обязательно -- или одно из или вообще ничего: "webpage" : id веб-страницы служащая шаблоном для отрисовки welcome-page ,"link" : id ссылки для welcome-redirect } } }
При изменении существующей формы изменяются только те поля, которые явно указаны в запросе.
Для удаление не обязательного параметра используйте пустое значение.
{ "action" : "form.set" ,"obj" : { ,"name" : "название" ,"state" : 0|1 -- состояние: 0 - форма отключена, 1 - активна ,"anketa" : анкета-форма в которую собираются данные ,"preview" : 0|1 -- при возврате подписчика к форме заполнять её ранее введёнными данными -- 0 - нет (по умолчанию) -- 1 - да ,"group" : группа-список в которую попадают заполнившие форму ,"landing" : { "webpage" : id веб-страницы служащей шаблоном для отрисовки landing-page. не обязательно } ,"fill" : { "draft" :id черновика высылаемого как fill-letter. не обязательно -- ответ пользователю после заполнения. одно из: -- или отрисовка страницы (параметр link стирается) ,"webpage" : id веб-страницы служащей шаблоном для отрисовки fill-page -- или перенаправление (параметр webpage стирается) ,"link" : id ссылки для fill-redirect -- или станица с текстом по умолчанию (оба параметра стираются) ,"webpage" : "" ,"link" : "" } ,"welcome" : { "draft" :id черновика высылаемого как welcome-letter. не обязательно -- ответ пользователю после подтверждения заполнения формы. одно из: -- или отрисовка страницы (параметр link стирается) ,"webpage" : id веб-страницы служащей шаблоном для отрисовки fill-page -- или перенаправление (параметр webpage стирается) ,"link" : id ссылки для fill-redirect -- или станица с текстом по умолчанию (оба параметра стираются) ,"webpage" : "" ,"link" : "" } } -- необязательные ,"id" : "идентификатор формы" -- если не указан, создается новая ,"return_fresh_obj": "" -- вернуть объект в формате form.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате form.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "form.delete" ,"id" : "идентификатор формы" }
ответ
{ <общие поля> }
{ "action" : "form.source" ,"id" : "идентификатор формы" ,"js" : 0|1 -- генерировать код с учётом использования java-script -- не всегда возможно разместить код с java-script на не своём сайте -- в большестве случаев java-script не будет работать в письмах -- -- при использовании java-script код будет пытаться максимально оставлять -- пользователя на странице где он заполняет форму выводя все сообщения -- по возможности во всплывающих окнах }
ответ
{ "html" : "код формы" ,"url" : "полный адрес входной страницы формы" -- #6025 [BASE]/ ,"url.fill" : "полный адрес страницы, отображаемой при окончании заполнения" ,"url.welcome" : "полный адрес страницы, отображаемой при подтверждении заполнения" }
Этот вызов переносит ответ пользователя из анкеты-формы в анкеты-хранилища не дожидаясь, пока он сам подтвердит заполнение,
Этот вызов делает ровно то что написано, он не подтвердит регистрацию нового пользователя за него и не породит событие "Форма заполнена".
{ "action" : "form.transfer" ,"id" : "идентификатор формы" ,"email" : "адрес, данные которого перенести" }
ответ
{ <общие поля> }
В данный момент Шаблоны веб-страниц используются только Формами опросов и не имеют ни какого отдельного самостоятельного назначения.
{ "action" : "webpage.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор" ,"name" : "название" } ... ] }
{ "action" : "webpage.get" ,"id" : "идентификатор шаблона" }
ответ
{ <общие поля> "obj" : { "id" : "идентификатор шаблона" ,"name" : "название" ,"page" : "html текст страницы" } }
{ "action" : "webpage.set" ,"obj" : { ,"name" : "название" ,"page" : "html текст страницы" } -- необязательные ,"id" : "идентификатор шаблона" ,"return_fresh_obj": "" -- вернуть объект в формате webpage.get }
ответ
{ <общие поля> ,"id" : номер -- объект в формате webpage.get при наличии в запросе параметра "return_fresh_obj" ,"obj" : { ... } -- объект в формате webpage.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "webpage.delete" ,"id" : "идентификатор шаблона" --- или несколько ,"id" : [ "id1", "id2", .. ] }
ответ
{ <общие поля> }
Хранение параметров внешних авторизаций в данный момент поддерживает только Google Analitics и предназначено для обеспечения автоматического пополнения Рядов Данных статистикой из Google Analitics.
{ "action" : "authext.list" }
ответ
{ <общие поля> ,"list" : [ { "id" : "идентификатор внешней авторизации" ,"type" : "тип внешней авторизации" ,"login" : "логин внешней авторизации" ,"reltype" : ... ,"relref" : ... } ... ] }
Токен прочесть нельзя.
{ "action" : "authext.get" ,"id" : "идентификатор внешней авторизации" }
ответ
{ <общие поля> ,"obj" : { "id" : "идентификатор внешней авторизации" ,"type" : "тип внешней авторизации" ,"login" : "логин внешней авторизации" ,"reltype" : ... ,"relref" : ... } }
{ "action" : "authext.сreate" ,"type" : "тип внешней авторизации" -- в данный момент поддерживается: -- 8 - Google Analitics ,"login" : "логин внешней авторизации" -- используется тольо как метка для уникальности в пределах одного типа ,"token" : "токен внешней авторизации" -- для GA - refresh token ,"reltype" : ... ,"relref" : ... }
ответ
{ <общие поля> ,"id" : "идентификатор созданной внешней авторизации" }
Обновляются только указанные в запросе поля
{ "action" : "authext.set" ,"id" : "идентификатор внешней авторизации" ,"type" : "тип внешней авторизации" ,"login" : "логин внешней авторизации" ,"token" : "токен внешней авторизации" ,"reltype" : ... ,"relref" : ... }
ответ
{ <общие поля> }
{ "action" : "authext.delete" ,"id" : "идентификатор внешней авторизации" }
ответ
{ <общие поля> }
{ "action" : "authext.ga.props" ,"id" : "идентификатор внешней авторизации" }
ответ
{ <общие поля> "list" : { "логин-1" : [ { "id" : "id сайта" ,"name" : "название сайта" } ,.... ] ,.... } }
Использовать только перед новым годом
{ "action" : "sys.dedmoroz" "email" : "email для ответа" ,"message" : "пожелание" }
ответ
{ <общие поля> }
{ "action" : "sys.settings.get", "list" : [ ], -- коды настроек. Если пусто - все настройки "params" : { -- не обязательно "код настройки" : { "параметр" : "значение", "параметр" : "значение", .... }, "код настройки" : { ... } } }
ответ
{ <общие поля>, "list" : { "код настройки" : "значение в формате зависящим от настройки" .......... } }
{ "action" : "sys.settings.set", "list" : { -- только те что надо изменить "код настройки" : "значение в формате зависящим от настройки" ........... } }
ответ
{ <общие поля> }
Список настроек которые можно только прочесть
"about.id" : "код клиента" ,"about.name" : "Название" ,"about.tarif" : "код тарифа" ,"about.user" : "текущий пользователь (sublogin)" ,"trial" : 0|1 - тестовый режим. действуют некоторые ограничения ,"trial.issue.limit" : лимит на тираж писем. null - ограничения нет ,"trial.issue.rest" : доступный остаток тиража писем. null - ограничения нет ,"allow.email" : 0|1 - доступна работа с email ,"allow.sms" : 0|1 - доступна работа с sms ,"sms.unlimited" : 0|1 - тираж sms не ограничен купленым количеством ,"sms.used" : "использовано единиц тарификации sms начиная с 01-11-2013" - в настоящий момент это копейки ,"sms.byed" : "куплено единиц тарификации sms начиная с 01-11-2013" - в настоящий момент это копейки ,"member.tarif.limit" : лимит на количество адресов в базе используемый при расчёте оплаты. null - ограничения нет ,"member.hard.limit" : лимит на количество адресов в базе который не превысить. null - ограничения нет ,"member.noconfirm.limit" : лимит на количество адрес которые можно внести без подтверждения. null - ограничения нет ,"member.noconfirm.rest" : доступный остаток на внесение без подтверждения. null - ограничения нет ,"sec.allowip" : [ -- список ip-адресов или сidr-адресов только с которых разрешёна работа -- пустой список - нет ограничений "адрес" ,"адрес" ... ] ,"sec.login.denysuper" : 0|1 -- вход основным логином запрещён, ,"sec.login.lock.error" : лимит числа неудачных попыток входа после которого логин блокируется, ,"sec.login.lock.inactive" : количество дней неактивности после которых логин блокируется, ,"sec.password.history" : глубина истории паролей каждого логина. нельзя сменить пароль на имеющийся в истории, ,"sec.password.check" : 0|1 -- проверять что новый пароль соответствует каждому из требований -- * 8 символов и длиннее -- * содержит буквы -- * содержит цифры ,"sec.password.expire.day" : количество дней после смены пароля после которых заставлять менять пароль опять ,"target.script" : код для сервиса "Целевые страницы" предназначеный для размещения на сайте поддерживаются дополнительные параметры - link.group.id : номер - автоматически включать новые целевые страницы в указанную группу ссылок - noqs : 1 - удалить из адреса целевой страницы все параметры (например они всегда разные для разных посетителей) - url : "ccылка" - вместо адреса целевой страницы использовать указаный
Список настроек которые можно и прочесть и поменять
"about.owner.email" : [ "email", "email", ... ], -- email-адрес/адреса ответственного лица. -- Используется как получатель для всех писем системы когда не указан другой адрес "support.access" : "0|1", -- службе поддержки разрешён вход для помощи -- Уведомления о действиях с адресами производимыми пользователями -- Значением является массив в котором могут быть или один и более почтовый адрес или одна и только одна ссылка http/https -- Указанные почтовые адреса проверяются на синтаксическую верность и при ошибке вызов завершится так же с ошибкой -- В ссылке последовательность EMAIL при вызове заменяется на адрес подписчика с которым произведено действие "notify.member.join" : [ .. ], -- Уведомление о регистрации нового адреса (через внешние формы) "notify.member.confirm" : [ .. ], -- Уведомление о подтверждении регистрации адреса "notify.member.modify" : [ .. ], -- Уведомление об изменении данных регистрации (самим владельцем адреса) "notify.member.remove" : [ .. ], -- Уведомление об удалениии регистрации (самим владельцем адреса) -- Перенаправления пользователя после совершения действий "redirect.member.join" : "url", -- После регистрации через внешнюю форму -- когда пользователь зарегистрирован как новый -- Может быть переопределено или отменено в конкретной -- форме на сайте параметром redirect_to. "redirect.member.join.exists" : "url", -- После регистрации через внешнюю форму -- когда пользователь уже существует -- Может быть переопределено или отменено в конкретной -- форме на сайте параметром redirect_exists_to "redirect.member.confirm" : "url", -- После подтверждения регистрации "redirect.member.remove" : "url", -- После удаления регистрации -- Использование шаблонов информационных писем "infolett.confirm.need" : "код шаблона", -- Высылается когда адрес регистрируется или при использовании вызова -- "member.sendconfirm" без указания желаемого черновика. -- Пусто - стандартный системный текст "infolett.confirm.done" : "код шаблона", -- Высылается сразу после подтверждения регистрации. -- Пусто - не высылается ничего "infolett.info" : "код шаблона", -- Высылается когда требуется сообщить подписчику его регистрационные -- данные и он уже подтвердил регистрации. -- Пусто - стандартный сиситемный тест -- "msisdn.country" : "число", -- код страны (без +) для нормализации регистрируемых не полных номеров телефонов "msisdn.zone" : "число", -- код зоны для нормализации регистрируемых не полных номеров телефонов -- "issue.link.qid" : "строка", -- добавка к ссылкам в письмах -- переходы из писем рассылок плохо видны в статистике именно как переходы из рассылки -- и часто попадают в общую кучу "прямые переходы" (typed in). -- Вы можете указать параметр (например source=pro) который будет добавляться ко всем -- ссылкам в вашем выпуске (например, было http://site.tld/,а станет http://site.tld/?source=pro) -- и, соответственно, позволит однозначно определить при анализе посещаемости сайта -- что посетитель пришёл именно из выпуска рассылки. "issue.access" : { "права доступа у выпуску. структура аналогичная параметру access вызова issue.set.access, за исключением отсутствия варианта default" } "issue.dontsend.550" : 0|1 -- автоматически исключать из выпусков рассылок адреса у которых последняя ошибка smtp = 550 - неизвестный получатель ,"target.сookie.ttl" : положительное-число -- "Время отслеживания после перехода" для сервиса "Целевые страницы". Задаётся в минутах. По умолчанию 360 - 6 часов
{ "action": "user.list" }
ответ
{ <общие поля> ,"list" : [ { "sublogin" : "саблогин пользователя", "status" : "-1 - ожидает смены пароля |0 - активен | 1 - заблокирован", }, .. ] }
Созданный пользователь получает состояние "Требуется сменить пароль"
{ "action" : "user.create", "sublogin" : "саблогин", "password" : "пароль", "email" : "email для отправки пароля" -- необязательно }
ответ
{ <общие поля> }
{ "action" : "user.delete", "sublogin" : "саблогин" }
ответ
{ <общие поля> }
Настройки основному пользователю (sublogin пусто при авторизации) может менять только он сам.
{ "action" : "user.set", "sublogin" : "логин пользователя", -- обязательно. "status" : "-1 - заставить сменить пароль | 0 - активировать | 1 - заблокировать" -- необязательно -- если текущий статус -1 то изменить его возможно только сменой пароля "password.new" : "новый пароль", -- необязательно "password.old" : "старый пароль", -- обязательно, если указан password.new "email" : "адрес для высылки письма с новым паролем" -- не обязательное поле }
ответ
{ <общие поля> }
Меняет пароль текущему пользователю
{ "action" : "sys.password.set", "password.new" : "новый пароль", "password.old" : "старый пароль", }
ответ
{ <общие поля> }
{ "action" : "sys.message" "email" : "email для связи" ,"message" : "текст сообщения" ,"attach" : "cодержимое прикрепляемого файла" -- не обязательно }
ответ
{ <общие поля> }
{ "action" : "sys.log", "from" : "YYYY-MM-DD hh:mm:ss" -- дата события от, не обязательно "upto" : "YYYY-MM-DD hh:mm:ss" -- дата события по, не обязательно }
ответ
{ <общие поля>, "list" : [ -- по возрастанию времени { "dt" : "дата события", "ip" : "ip адрес инициатора", "login" : "логин инициатора", "object" : "объект", "action" : "действие", "title" : "заголовок", "value.old" : "старое значение (если применимо)", "value.new" : "новое значение (если применимо)" } .......... ] }
{ "action": "rights.get", "user" : "логин пользователя", "list" : [ -- список запрашиваемых проверяемых вызовов, если пусто - то все "action1", "action2", ... ] }
ответ
{ <общие поля>, "list" : { -- список вызовов: 1 - доступно, 0 - недоступно "action1" : " 1 | 0 " "action2" : " 1 | 0 ", .. } }
{ "action": "rights.set", "user" : "логин пользователя", "list" : { -- список устанавливаемых прав: 1 - доступно, 0 - недоступно. -- Изменяются только значения перечисленных в списке прав. "action1" : " 1 | 0 ", "action2" : " 1 | 0 ", ... } }
ответ
{ <общие поля> }
Фильтр отбора состоит из списка элементов задающих условия отбора или условия объединения других условий.
Пустой фильтр (т.е. не содержащий ни одного элемента) ни когда не совпадает ни с чем и результат его использования всегда пустой.
Каждый элемент содержит поле 'which' задающее его тип и возможные дополнительные поля в зависимости от типа:
При получении описания фильтра вставляются дополнительные поля aid.name, qid.name и pid.name содержашие названия соответсвующие кодам.
И значения ключей хэша resp так же становятся названиями соответствующих ответов.
Это позволяет сократить количесво запросов к API для визуализации фильтра на стороне клиента
При установке значения фильтра эти дополнительные поля и значения ключей хэша resp игнорируются.
[ { "which" : "тип элемента 1" <возможно дополнительные поля> } ,{ "which" : "тип элемента 2" <возможно дополнительные поля> } ... ,{ "which" : "тип элемента N" <возможно дополнительные поля> } ]
Адрес имеет 2 и меньше ошибки доставки И регион проживания один из RU01,RU05,RU40 И день рождения завтра И ( входи в группу abc ИЛИ входит в группу xyz )
При записи фильтра
[ { "which" : "<=", -- Адрес имеет 2 и меньше ошибки доставки "aid" : "member", "qid" : "error", "resp" : "2" }, { "which" : "AND" }, { "which" : "any", -- регион проживания один из RU01,RU05,RU40 "aid" : "personal", "qid" : "region", "resp" : { "RU01" : null ,"RU13" : null ,"RU40" : null } }, { "which" : "AND" }, { "which" : "dtnowmd", -- день рождения завтра "aid" : "personal", "qid" : "birthday", "resp" : "+1" }, { "which" : "AND" }, { "which" : "group", "group" : [ { "which" : "PRF", -- входи в группу abc "resp" : 1, "pid" : "abc" }, { "which" : "OR" }, { "which" : "PRF", -- входи в группу xyz "resp" : 1, "pid" : "xyz" } }
При получении фильтра
[ { "which" : "<=", -- Адрес имеет 2 и меньше ошибки доставки "aid" : "member", "qid" : "error", "resp" : "2", "aid.name" : "Cистемная анкета", "qid.name" : "Количество ошибок доставки" }, { "which" : "AND" }, { "which" : "any", -- регион проживания один из RU01,RU05,RU40 "aid" : "personal", "qid" : "region", "aid.name" : "Персональные данные", "qid.name" : "Регион" "resp" : { "RU01" : "Адыгея" ,"RU13" : "Мордовия" ,"RU40" : "Калуга" } }, { "which" : "AND" }, { "which" : "dtnowmd", -- день рождения завтра "aid" : "personal", "qid" : "birthday", "resp" : "+1" "aid.name" : "Персональны данные", "qid.name" : "День рождения" }, { "which" : "AND" }, { "which" : "group", "group" : [ { "which" : "PRF", -- входи в группу abc "resp" : 1, "pid" : "abc" "pid.name" : "Группа знающих буквы A-B-C" }, { "which" : "OR" }, { "which" : "PRF", -- входи в группу xyz "resp" : 1, "pid" : "xyz" "pid.name" : "Группы знающих буквы X-Y-Z" } }
Для обеспечения приоритета условий используйте скобки, а не предположения какой у чего приоритет на основании "в таком-то языке так-то".
{ "which" : "AND" }
{ "which" : "OR" }
{ "which" : "group" "group" : [ массив описывающий фильтр ] }
{ "which" : "PRF" ,"resp" : "0 - не входит в группу, 1 - входит в группу" ,"pid" : "код проверяемой группы" }
{ "which" : "stat.uni" ,"resp" : "0 - не попадает, 1 - попадает" -- параметры stat.uni -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ ... ] -- используйте только если не подходит значение по умолчанию [ 'member.id' ] }
Хотя бы одни ответ из списка есть в ответах подписчика
{ "which" : "any" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"resp" : { "код ответа 1" : null ,"код ответа 2" : null ..... } }
Каждый ответ из списка есть в ответах подписчика
{ "which" : "each" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"resp" : { "код ответа 1" : null ,"код ответа 2" : null ..... } }
Выбран хотя бы один ответ
{ "which" : "atleast" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
На вопрос не выбран ни один ответ
{ "which" : "empty" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
Ответ на вопрос как число не равен (!=), равен (==), меньше(<), меньше или равен (<=), больше или равен (>=), больше (>) чем число в 'resp'
{ "which" : "!= | == | < | <= | => | >" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"resp" : "целое число" }
Ответ на вопрос числено равен текущему году (nowy), месяцу (nowm) или дню (nowd)
{ "which" : "nowy | nowm | nowd" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
Компонента "дата" в ответе равна (dtnow), не равна (dtnowne), ранее (dtnowlt), ранее или равна (dtnowle), позже или равна (dtnowge), позже (dtnowgl) чем "дата сегодня +/- сдвиг"
{ "which" : " dtnow | dtnowne | dtnowlt | dtnowle | dtnowge | dtnowgt " ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"reps" : "сдвиг в днях от сегодня" -- не обязательно. например: -2 - позавчера, +1 - завтра }
Компонента "месяц и день" в ответе равны месяцу и дню в "дате сегодня +/- сдвиг"
{ "which" : "dtnowmd" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"reps" : "сдвиг в днях от сегодня" -- не обязательно. например: -2 - позавчера, +1 - завтра }
Компонен "год" в ответе равен текущему году
{ "which" : "dtnowy" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
Компонен "месяц" в ответе равен текущему месяцу
{ "which" : "dtnowm" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
Компонен "день" в ответе равен текущему дню +/- сдвиг
{ "which" : "dtnowd" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"reps" : "сдвиг в днях от сегодня" -- не обязательно. например: -2 - позавчера, +1 - завтра }
Ответ пустой
{ "which" : "emptyS" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
{ "which" : "dirtyS" ,"aid" : "код анкеты" ,"qid" : "код вопроса" }
Это медленый фильтр.
В будущем он может быть удалён.
В большинстве случаев его использования можно избежать, если изначально делать вопрос не полем ввода, а списком выбора
Строка ответа на вопрос не равна (ne), равна (eq), меньше(lt), меньше или равна (le), больше или равна (ge), больше (gt) чем строка в 'resp'
{ "which" : "ne | eq | lt | le | ge | gt" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"resp" : "строка для сравнения" }
Это медленый фильтр.
В будущем он может быть удалён.
В большинстве случаев его использования можно избежать, если изначально делать вопрос не полем ввода, а списком выбора
Строка ответа начинается (beg) или не начинается (nbeg) со строки "resp"; содержит (has) или не содержит (nhas) строку "resp"; заканчивает (end) или не заканчивается (nend) строкой "resp"
{ "which" : "has | nhas | beg | nbeg | end | nend" ,"aid" : "код анкеты" ,"qid" : "код вопроса" ,"resp" : "строка" }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.clicked" ,"issue.members"] ,"order" : ["issue.dt"] }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.clicked" ,"issue.members"] ,"filter" : [{ "a" : "issue.group.gid", "op" : "==" , "v" : "gdfhdfh" }] ,"order" : ["issue.dt"] }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.clicked" ,"issue.members"] ,"filter" : [ {"a" : "issue.group.gid", "op" : "==", "v" : "gdfhdfh" } , {"a" : "issue.dt", "op" : ">=", "v" : "2011-03-17 11:30:27"}] }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.clicked" ,"issue.members"] ,"filter" : [{"a" : "issue.id", "op" : "==", "v" : 15 }] ,"order" : ["issue.dt"] }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.clicked" ,"issue.members"] ,"filter" : [ {"a" : "issue.group.gid", "op" : "==", "v" : "gdfhdfh" } , {"a" : "issue.dt", "op" : "==", "v" : "2011-03-17 11:30:27" }] ,"order" : ["issue.dt"] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"order" : ["click.dt:YD"] }
{ "select" : ["click.dt:YM" ,"count(*)"] ,"order" : ["click.dt:YM"] }
{ "select" : ["click.dt:YY" ,"count(*)"] ,"order" : ["click.dt:YY"] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ { "a" : "click.dt:YM", "op" : ">=", "v" : "2011-05" } , { "a" : "click.dt:YM", "op" : "<=", "v" : "2012-05" } ] ,"order" : ["click.dt:YD"] }
{ "select" : ["click.dt:YM" ,"count(*)"] ,"filter" : [ { "a" : "click.dt:YY", "v" : "2011", "op" : ">=" } , { "a" : "click.dt:YY", "op" : "<=", "v" : "2010" } ] ,"order" : ["click.dt:YM"] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ { "a" : "issue.id", "op":"==", "v" : 15} , { "a" : "click.dt:YM", "op" : "<=", "v" : "2011-05" }] ,"order" : ["click.dt:YD"] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [{"a" : "issue.dt:YY", "op":">", "v" : "2011"} ] ,"order" : ["click.dt:YD"] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ { "a" : "issue.dt:YY", "op":">", "v" : "2011"} , { "a" : "issue.group.gid", "op" : "==", "v" : "gdfhdfh" }] ,"order" : ["click.dt:YD"] }
{ "select" : ["click.link.url" ,"count(*)"] ,"order" : ["click.link.url"] }
{ "select" : ["click.link.url" ,"count(*)"] ,"order" : ["click.link.url"] ,"filter" : [ { "a" : "click.dt:YY", "op" : "==", "v" : "2010" } ] }
{ "select" : ["click.link.url" ,"count(*)"] ,"filter" : [ { "a" : "click.dt:YY", "op" : "==", "v" : "2011" } , { "a" : "issue.id", "op" : "==", "v" : "16" } ] ,"order" : ["click.link.url"] }
{ "select" : ["click.link.url" ,"count(*)"] ,"order" : ["click.link.url"] ,"filter" : [ { "a" : "click.dt:YY", "op" : ">=", "v" : "2011" } , { "a":"issue.group.gid", "op":"==", "v":"all"} , { "a" : "issue.dt", "op" : "==", "v" : "2010-01-26 16:51:26" } ] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ {"a" : "click.link.url", "op" : "==", "v" : "http://www.disney.com/" }] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ {"a" : "click.link.url", "op" : "==", "v" : "http://www.disney.com/" } , { "a" : "click.dt", "op" : ">=", "v" : "2011-05-11 14:25:54" }] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ {"a" : "click.linkgroup.id", "op" : "==", "v" : "16" } , { "a" : "click.dt", "op" : ">=", "v" : "2011-05-11 14:25:54" }] }
{ "select" : ["click.dt:YD" ,"count(*)"] ,"filter" : [ {"a" : "click.linkgroup.name", "op" : "==", "v" : "Профиль all" } , {"a" : "click.dt", "op" : ">=", "v" : "2011-05-11 14:25:54" }] }
{ "select" : ["click.dt:YD" ,"click.link.url" ,"count(*)"] ,"filter" : [{"a" : "member.email", "op" : "==", "v" : "vadim\@iprojects.ru" }] }
{ "select" : ["click.dt:YD","click.link.url ","count(*)"] ,"filter" : [ {"a" : "member.email", "op" : "==", "v" : "ask\@subscribe.ru" } , { "a" : "click.dt:Ym", "op" : ">=", "v" : "2011-08-10 13:30" } ] }
{ "select" : ["issue.name", "issue.group.name" ,"issue.dt" ,"issue.readed" ,"issue.members"] }
{ "select" : ["issue.name", "issue.group.name" ,"issue.dt" ,"issue.readed" ,"issue.members"] ,"filter" : [ {"a" : "issue.group.gid", "op" : "==", "v" : "import20110627175254" } , { "a" : "issue.dt", "op" : "==", "v" : "2011-06-28 13:54:48" } ] }
{ "select" : ["read.dt:YY" ,"count(*)"] }
{ "select" : ["read.dt:YM" ,"count(*)"] }
{ "select" : ["read.dt:YD" ,"count(*)"] }
{ "select" : ["read.dt:YD" ,"count(*)"] ,"filter" : [ {"a" : "issue.group.gid", "op" : "==", "v" : "import20100720185533" } , { "a" : "issue.dt", "op" : "==", "v" : "2010-10-18 17:17:17" }] }
{ "select" : ["read.dt:YD" ,"count(*)"] ,"filter" : [{"a" : "issue.dt:Ym", "op" : ">", "v" : "2010-10-18 17:30" }] }
{ "select" : ["read.dt" ,"member.email"] }
{ "select" : ["read.dt" ,"member.email"] ,"filter" : [ {"a":"read.dt:YD", "op" : "<=", "v" : "2010-10-20" }] ,"order" : [ "read.dt"] }
{ "select" : ["read.dt" ,"member.email"] ,"filter" : [ { "a" : "read.dt:YD", "op" : "<=", "v" : "2010-10-20" } , { "a" : "issue.group.gid", "op" : "==", "v" : "import20100720185533" } , { "a" : "issue.dt", "op" : "==", "v" : "2010-10-18 17:17:17" } ] ,"order" : [ "read.dt"] }
{ "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"issue.deliv_ok" ,"issue.members"] ,"filter" : [ { "a" : "deliv.status", "op" : ">", "v" : "0" } ] }
{ "select" : ["issue.name","issue.group.name","issue.dt","issue.deliv_ok","issue.members"] ,"filter" : [ { "a" : "deliv.status", "op" : ">", "v" : "0" } , { "a" : "issue.group.gid", "op" : "==", "v" : "masssending" } ] }
{ "select" : ["issue.name","issue.group.name","issue.dt","issue.deliv_ok","issue.members"] ,"filter" : [ { "a" : "deliv.status", "op" : ">", "v" : "0" } , { "a" : "issue.group.gid", "op" : "==", "v" : "masssending" } , { "a" : "issue.dt", "op" : "==", "v" : "2010-05-31 16:23:47" } ] }
{ "select" : ["issue.name","issue.group.name","issue.dt","member.email","deliv.status"] ,"filter" : [ { "a" : "deliv.status", "op" : "<", "v" : "0" } ] }
{ "select" : ["member.email","deliv.status"] ,"filter" : [ { "a" : "deliv.status", "op" : "<", "v" : "0" } , { "a" : "issue.group.gid", "op" : "==", "v" : "p212" } , { "a" : "issue.dt", "op" : "==", "v" : "2010-12-31 23:02:29" } ] }
{ "select" : ["issue.name","issue.group.name","issue.dt","deliv.status"] ,"filter" : [ { "a" : "member.email", "op" : "==", "v" : "test@test.ru" } ] }
{ "select" : ["issue.name","issue.group.name","issue.dt","deliv.status"] ,"filter" : [ { "a" : "member.email", "op" : "==", "v" : "test@test.ru"} , { "a" : "issue.dt:YM", "op" : ">=", "v" : "2010-12" } ] }
{ "select" : ["issue.id","issue.group.gid","issue.dt","member.email","deliv.status"] ,"filter" : [ {"a" : "issue.dt:YM", "op" : ">=", "v" : "2011-08" } , {"a":"deliv.status", "op":"<","v":"0"} ] ,"order" : ["issue.id","issue.dt","member.email"] }
{ "select" : ["member.email","count(deliv.*)"] ,"filter" : [ {"a" : "issue.dt:YM", "op" : ">=", "v" : "2011-08" } , { "a":"deliv.status", "op":"<","v":"0"} ] ,"order" : ["member.email"] }
{ "select" : ["member.email","count(deliv.*)"] ,"filter" : [{"a" : "issue.dt:YM", "op" : ">=", "v" : "2011-08" }] ,"order" : ["member.email"] }
{ "select" : ["*.dt:YD", "count(click)", "count(read)" ] ,"order" : ["-*.dt:YD"] }
{ "select" : ["*.dt:YM", "count(click)", "count(read)" ] ,"filter" : [{"a":"*.dt:YY", "op" : ">=", "v" : "2011" }] ,"order" : ["-*.dt:YM"] }
Указание *.dt:YM
ограничивает дату события - т.е. дату клика, чтения, выпуска. Даты событий не взаимосвязаны и клики и чтения берутся все случившиеся
в указанный интервал. Сравните со следующим отчётом.
{ "select" : ["*.dt:YM","sum(issue.members)","count(deliv)","count(read)","count(unique read.member.id)","count(click)", "count(unique click.member.id)"] ,"filter" : [ {"a" : "*.dt:YM", "op" : ">=", "v" : "2011-06" } , {"a" : "deliv.status", "op" : ">", "v" : "0" }] ,"order" : ["-*.dt:YM"] }
Указание *.issue.dt:YM
ограничивает дату выпуска - т.е. клики и чтения считаются только от выпусков указанного интервала
{ "select" : ["issue.dt:YM","sum(issue.members)","sum(issue.deliv_ok)","sum(issue.clicked)","sum(issue.readed)"] ,"filter" : [ {"a" : "issue.dt:YM", "op" : ">=", "v" : "2011-06" } ] ,"order" : ["issue.dt:YM"] }
Быстрый вызов по заранее подготовленным данным с небольшим (5-10 минут) отставанием от реального времени
{ "select" : [ "issue.name", "issue.dt", "issue.group.name", "issue.members", , "issue.deliv_ok", "issue.deliv_bad", "issue.clicked", "issue,u_clicked", , "issue.readed", "issue.u_readed", "issue.unsubed" ] ,"filter" : [ {"a" : "issue.dt", "op" : ">=", "v" : "2011-06-01 00:00:00" } ] ,"order" : [ "issue.dt" ] }
Аналогичный, но заметно более медленный на больших списках, вызов по данным в реальном времени
{ "select" : [ "*.issue.name", "*.issue.dt", "*.issue.group.name", "*.issue.members" , "count(deliv_ok)", "count(deliv_bad)", "count(click)", "count(unique click.member.id)" , "count(read)", "count(unique read.member.id)" ] ,"filter" : [ {"a" : "*.issue.dt", "op" : ">=", "v" : "2011-06-01 00:00:00" } ] ,"order" : ["*.issue.dt"] }
Для каждого участника выпуска номер 50 выбирается его адрес, дата внесения в базу,дата выпуска рассылки, статус доставки, дата первого клика в письме рассылки, общее число кликов в письме
Уникальный ключ составлен из номера получателя и номера выпуска. В данном случае это избыточно (номер выпуска у всех один), но если запрос подразумевает охват нескольких выпусков, то это необходимо.
Вместо номера получателя можно было бы использовать его адрес (он так есть в выборке), но тогда будет выполняться дольше, так как числовое поле (номер) в уникальном ключе работает быстрее чем строчное (адрес).
{ "action":"stat.uni" ,"groupby" : 2 -- размер ключа ,"join" : [ { -- Первый запрос. На основе списков доставки выбираются участники выпуска 50 и их данные "select":[ -- уникальный ключ "deliv.member.id" ,"deliv.issue.id" -- данные об адресе и доставке ,"deliv.member.email" ,"deliv.member.anketa.member.create.time" ,"deliv.issue.dt" ,"deliv.status" ] ,"filter":[ {"a":"deliv.issue.id","op":"==","v":"50"} ] } , { -- Второй вопрос. Данные о кликах выпуска 50 "select":[ -- уникальный ключ "click.member.id" ,"click.issue.id" -- данные о первом клике и их количество ,"min(click.dt)" ,"count(*)" ] ,"filter":[ {"a":"click.issue.id","op":"==","v":"50"} ] } ] ,"caption":[ -- Один раз колонки уникального ключа "Номер получателя" ,"Номер рассылки" -- Колонки первого запроса ,"Адрес получателя" ,"Дата регистрации" ,"Дата рассылки" ,"Статус доставки" -- Колонки второго запроса ,"Дата первого клика" ,"Число кликов" ] ,"result" : "save" ,"result.format" : "xlsx" }
В результате получится примерно следующее.
Пользователь второй из строки не кликал, что отражается как null в соответствующий колонках.
Номер получателя | Номер рассылки | Адрес получателя | Дата регистрации | Дата рассылки | Статус доставки | Дата первого клика | Число кликов |
34 | 50 | xxx@kovalyuk.ru | 2013-08-27 13:49:14 | 2013-10-04 16:26:03 | 1 | 2013-10-04 16:45:28 | 1 |
21 | 50 | yyy@avon.com | 2013-08-27 10:07:17 | 2013-10-04 16:26:03 | 1 | null | null |
78 | 50 | zzz@gmail.com | 2013-08-27 10:36:32 | 2013-10-04 16:26:03 | 1 | 2013-10-04 16:45:28 | 3 |
В зависимости от точности заданной в анкете для вопроса типа "дата", необходимо использовать один из следующих форматов записи даты или даты-времени в данных импорта:
точность yd - 'YYYY-MM-DD'
точность yh - 'YYYY-MM-DD hh'
точность ym - 'YYYY-MM-DD hh:mm'
точность ys - 'YYYY-MM-DD hh:mm:ss'
Для импортирования и рассылки через Экспресс-Выпуск доступны четыре формата описания адресов и их данных.
Данные задаваемые непосредственно в вызове указываются в параметре users.list
Внешние данные указываются ссылкой в параметре users.url
При выпуске почтовой рассылки адрес получателя задаётся ключём email объекта member.
При выпуске sms-рассылки номер получателя задаётся ключём cellphone объекта member.
Остальные данные не обязательны и могут быть любой структуры, что в сочетании с возможностью шаблонизатора организовывать циклы, получать списки ключей и значений объектов позволяет создавать очень сложные шаблоны.
При выпуске почтовой рассылки адрес получателя находится в колонке member.email.
При выпуске sms-рассылки номер получателя находится в колонке member.cellphone.
Остальные данные не обязательны, но при их наличии каждая колонка содержит только по одному значению для каждого адреса (не может быть массивом или объектом) и должна быть описана в caption.
Первый лист должен содержать в первой строке описание какой анкете и ответу соответствует данная колонка (в формате коданкеты.кодвопроса).
При импорте возможно задание этого соответствия в параметре caption вместо первой строки первого листа.
Одна ячейка может содержать только одно значение для каждого адреса (не может быть массивом или объектом).
Понимаются дzанных сжатые архиватором zip, хотя пользы от этого ни какой - xslx и так является zip-архивом и повторное сжатие нечего не даст.
Разделитель колонок - запятая или точка с запятой.
Cимвол экранирования - двойная кавычка.
Содержимое ячейки может быть заключено в кавычки.
Первая может содержать "#charset=кошка" для однозначного определения кодировки.
Тогда следующая строка должна содержать описание какой анкете и ответу соответствует данная колонка (в формате коданкеты.кодвопроса).
При импорте возможно задание этого соответствия в параметре caption вместо строки.
Одна ячейка может содержать только одно значение для каждого адреса (не может быть массивом или объектом).
Понимаются данных сжатые архиватором zip.
Если в колонке как часть его значения встречается символ разделитель колонок, то значение колоноки должно быть взято в кавычки.
Если в колонке как часть его значения встречается символ экранирования, то значение колоноки должно быть взято в кавычки, а символ экранирования удвоен.
Верно:
test@test.ru,"ЗАО ""Рога и копыта""",+70000000000 test@test.ru,"Рога, копыта и хвосты",+70000000000
НЕ верно:
test@test.ru,ЗАО "Рога и копыта",+70000000000 test@test.ru,Рога, копыта и хвосты,+70000000000
1) Если значение массив, то данные считаются заданными в формате JSON-массив
2) Если значение объект, то данные считаются заданными в формате JSON-объект
3) Если значение строка представляющая zip-архив и он содержит файл workbook.xml, то считается что это XLSX (технически XLSX это zip-архив со специальным набором файлов)
4) Если значение строка представляющая zip-архив и он не содержит файл workbook.xml, берётся первый по порядку файл архива и cчитается, что это данные в формате CSV
5) Если значение строка не-zip-архив, то считается, что это данные в формате CSV
1) Если content-type ответа application/json, то данные должны описывать массив или объект и формат выбирается как описано выше в пунктах 1 и 2.
2) При другом значении content-type выбор происходит как описано выше в пунктах 3, 4 и 5.
"users.list" : [ { "member" : { "email" : "test@test.ru" }, -- простые данные "string" : "строка текста какой-то длинные", "hash" : { "DEF" : "значение ключа DEF" ,"ABC" : "значение ключа ABC" }, "array" : [ "первый элемент" ,"второй элемент" ,"третий элемент" ....], -- структура с вложенными данными "personal" : { "fio" : { "fam" : "Фамилиё" ,"name" : "Ымя" } "homephone" : "112", "gender" : "есть", "something" : [ { "aaa" : "bbb", "ccc" : "ddd" }, "eeeee", [ "ffff", "ggg", "hhh"] ] } -- ещё структура "kredit-payment-by-month" : [ { "month" : "2012-12" ,"summa" : "1234" }, { "month" : "2013-01" ,"summa" : "4567" }, { "month" : "2013-02" ,"summa" : "8901" } ] }, { "member" : { "email" : "test2@test.ru" }, ......... }, ..... ]
"users.list" : { "caption" : [ { "anketa" : "member" ,"quest" : "cellphone" }, { "anketa" : "info" ,"quest" : "firstname" }, { "anketa" : "info" ,"quest" : "title" }, { "anketa" : "info" ,"quest" : "middlename" }, ], "rows" : [ [ "+70000000000","Павел","Иванович","Уважаемый" ], [ "+70000000000","Алексей","Алексеевич","Глубоко уважаемый" ], ...... ] }
В виду двоичного содержимого файла, он не может быть приведён в документации и доступен по ссылке
https://pro.subscribe.ru/API/sample.xlsx
"users.list" : "member.cellphone,info.firstname,info.title,info.meddlename\n+70000000000,Павел,Иванович,Уважаемый\n+70000000000,Алексей,Алексеевич,Глубоко уважаемый\n......"
Зачем это надо ? Например раздача пользователям уникальных кодов для последующего их использования на вашем сайте или магазине.
Для персонализации выпуска данные из анкет подписчиков и данные общих параметров (extra) можно дополнить данными из внешнего источника получаемыми динамически по ходу выпуска рассылки.
Это реализуется путём использования специальны функций шаблонизатора в тексте и/или шаблоне выпуска:
[% external_anketa("url") %]
[% external_extra("url") %]
С точки зрения шаблонизатора эти функции возвращают пустой результат, но меняют набор данных для использования в персонализации.
Вызовы указанных адресов производятся методом POST с передачей cgi-параметра request содержащего json-utf8 данные о текущем выпуске.
Ответ так же ожидается в json-utf8.
При вызове передаются следующие данные позволяющие идентифицировать что это за выпуск:
{ "some.id" : "......." - некая строка до 32 символов однозначно идентифицирующая выпуск (это НЕ номер выпуска который он получит позже) ,"login" : "..." - аккаунт для которого формируется выпуск ,"group.id" : "..." - код группы для которой формируется выпуск ,"track.id" : 123 - номер трекера для track.get присвоенный выпуску ,"draft.id" : 123 - номер черновика на основе которого формирутеся выпуск или null ,"seq.id" : 123 - номер последовательности вызвавшей этот выпуска или null ,"variant.id" : 123 - номер варианта А/Б-тестирования вызвавшего этот выпуска или null ,"extra": { ... } -- данные параметра extra вызова issue.send или null -- только для external_anketa() ,"users.list" : [ список адресов для которых ожидаются дополнительные анкетные данные ] }
Не работает в текстовых копиях.
Анкетные данные пользователей дополняются результатами обработки external_anketa().
В выпуске может быть несколько использований external_anketa() - все они будет обработаны один раз перед началом формирования писем по порядку расположения в тексте. Место расположения в данный момент не важно. Дополненные параметры действуют с самого начала текста.
Ошибка получения данных или разбора полученного json или не соответствия типа json фатальна для группы получателей указаных в выпуске, но сам выпуск продолжается в предположении что проблема разовая и следующие получатели смогут успешно пополнить свои данные.
Однако ошибка при получении данных для первой группы фатальна и выпуск прекращается.
Для одного выпуска вызовов каждого external_anketa() может быть несколько и они могут поступать одновременно - в зависимости от количества получателей выпуск формируется в несколько потоков, а получатели обрабатываются порциями. В данный момент обычный размер порции составляет 1000 адресов.
В параметре users.list передаются адреса текущей группы получателей.
Ответ должен быть json-массивом содержащим json-объекты или null.
Данные приписываются пользователю по порядку их расположения в массиве.
Внешние данные для пользователя могут быть любой структуры - не обязательно двухуровневые объекты как у анкетных данных.
Элементом массива может быть null - соответствующий получатель не получит данных.
Массив в ответе может быть короче исходного - оставшиеся адреса не получат данных.
Массив в ответе может быть длиннее исходного - лишние элементы игнорируются.
Пример:
users.list ответ [ [ "1@test.ru" { данные для 1@test.ru } ,"2@test.ru" ,null -- нет данных для 2@test.ru ,"3@test.ru" { данные для 3@test.ru } ] ,"4@test.ru" -- нет данных для 4@test.ru так как ответ короче ]
Результаты всех external_anketa() для каждого получателя сначала объединяются между собой по ключам первого уровня. Более поздние данные имеют приоритет и заменяют собой имеющиеся.
Итоговый результат объединяется по ключам второго уровня с данными персонализации получателя. Данные уже имеющиеся в анкете менее приоритетны и заменятся внешними при их наличии. Внешние данные для анкеты member игнорируются.
Пример для выпуска:
данные анкеты одного пользователя
{ "member" : { "email" : "test@test.ru" ,"id" : 123 } ,"info" : { "firstname" : "Имя" ,"lastname" : "Фамилия" } ,"param" : { "raz" : "Раз" "dva" : "Два" } }
данные вызова external_anketa() для этого пользователя
{ "member" : { "email" : "xxxx@test.ru" } ,"info" : { ,"lastname" : "фамилиЁ" } ,"param" : [ "Три", "Четыре" ] ,"secret" : "12345" }
результат
{ "member" : { "email" : "test@test.ru" -- не замененно так как member не изменяем ,"id" : 123 } ,"info" : { "firstname" : "Имя" ,"lastname" : "фамилиЁ" -- внешние данные при объединение объектов по ключам второго уровня } ,"param" : [ "Три", "Четыре" ] -- полностью заменено данными первого уровня так как внешние данные не объект ,"secret" : "12345" -- новые внешние данные }
Работает в текстовых копиях.
Общие параметры указываемые в ключе extra вызова issue.send дополняются результатами обработки external_extra().
В выпуске может быть несколько использований external_extra() - все они будет обработаны один раз перед началом формирования писем по порядку расположения в тексте. Место расположения в данный момент не важно. Дополненные параметры действуют с самого начала текста.
Ошибка получения данных или разбора полученного json или не соответствия типа json фатальна - выпуск прекращается.
Ответ должен быть json-объектом.
Результаты всех external_extra() сначала объединяются между собой по ключам первого уровня. Более поздние данные имеют приоритет и заменяют собой имеющиеся.
Итоговый результат объединяется по ключам первого уровня с данными указанными в extra. Данные уже имеющиеся в extra имеют приоритет и не заменятся внешними.
Пример для выпуска с двумя вызовами:
данные extra из issue.send
{ "nol" : "ноль" }
данные первого вызова external_extra()
{ "odin" : "адын" ,"dva" : "ещё адын" ,"abv" : { "a" : "А" ,"b" : "Б" ,"v" : "В" } ,"gde" : { "g" : "Г" ,"d" : "Д" ,"e" : "Е" } }
данные второго вызова external_extra()
{ "nol" : "два" ,"dva" : "два" ,"gde" : { "х" : "Х" } }
результат
{ "nol" : "ноль" -- данные их extra приоритетнее ,"odin" : "адын" -- нет во втором вызове external_extra() ,"dva" : "два" -- есть во втором вызове external_extra() ,"abv" : { -- нет во втором вызове external_extra() "a" : "А" ,"b" : "Б" ,"v" : "В" } ,"gde" : { -- есть во втором вызове external_extra() - просто замена без попыток объединения ключей "х" : "Х" } }
Часть типов объектов (в перспективе все типы) позволяют присвоить каждому их экземпляру пару чисел для отметки их в пользовательских целях.
Такие объекты имеют параметры reltype (предполагается что это значение хранит некий обобщённый тип класификации) и relref (указатель на что-то внутри классификации).
По умолчанию при создании оба поля получают значения равные 0.
У обоих полей все отрицательные значения зарезервированы для системных нужд. Используйте для себя положительные значения во избежания конфликтов.
При использовании возможностей связанных с загрузкой данных с указанных вами адресов, необходимо не забывать что получить данные с адресов вашей локальной вычислительной сети не есть возможно - они спрятаны от внешнего мира за вашим шлюзом.
К таким адресам относятся:
10.0.0.0 - 10.255.255.255 (10/8 prefix) 127.0.0.0 - 127.255.255.255 (127/8 prefix) 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
С полным списком можно ознакомиться в RFC 5735 http://tools.ietf.org/html/rfc5735
0.116 2014-06-17 * Новый функционал "Формы опросов" - реализуется через вызовы form.* - вспомогательны объекты "Шаблоны веб-страниц" webpage.* - новые события тригеров form.filled и form.completed - статистка доступна через stat.uni: form.* - набор свойств form у вопроса анкеты для поддержки трансляции данных - вызов decor.siteform удалён как устаревший * Уточнение формата даты для datarow.load * Новый параметре attach вызова sys.message * Вызов sequence.member.membership: правильное название параметра с адресом это email * Забытое описание вызова link.delete * Расширенные кода недоставки - сбор по умолчанию отключён - доступны через stat.uni deliv_elim - изменены номера статусов -1x на -10001x 0.115 2014-05-17 * Логические операции с группами (объединиие, пересечение и прочие) и получение группы-списка из группы фильтра с помощью вызовов group.snapshot и group.clean * Расширенные кода недоставки -1x * Список адресов из разового фильтра с помошью group.filter для member.update/delete/sendconfirm и stoplist.add/delete 0.114 2014-04-17 * Определение географии и устройства подписчика * Ряды данных - сбор данных о конверсии. Как напрямую от вас, так и импорт из Google Analitics * Несколько запросов за один вызов * sequence.member.start теперь игнорирует закрытость последовательности. полезно при тестировании * target.script - новые параметры noqs и url * authext - вспомогательный объект для рядов данных 0.113 2014-03-17 * Целевые страницы. Проследите пусть подписчика по сайту после перехода из письма ! * Для удаления блокировки из-за ошибок доставки следует использовать member.set или member.update явно указывая установку поля member.error в "0" * Новое состояние трекера запросов: -4 - отложенное на будущее действие * Выпуск транзакционной рассылки с указанием получателя в параметре email сразу закончится с ошибкой, если адрес синтаксически не верен или не возможен для рассылки (отписан, в стоп-листе, ошибки доставки) * Адрес отправителя обязателен в черновике или информационном письме для использования их в других вызовах * Пользовательские метки объектов. Первые кто поддреживает link и linkgroup (+ соответствующие изменения в stat.uni,link.*, link.group.*) * sys.settings.get - возможность задания параметров для настроек 0.112 2014-02-17 * Внешние данные для персонализации (external_anketa(),external_extra()) позволяют творить чудеса (раздача личных кодов скидок малая их часть) * Выпуск рассылки issue.send: новый параметр reply.name - имя для обратного адреса для ответа from.email - теперь обязателен для email from.name - теперь обязателен для sms * Универсальная статистика member.error.* - информация об ошибках доставки адреса stat.common.* - общая статистика по дням dt:CW1D - модификатор получения первого дня недели dt:DOW - модификатор получения номера дня недели dt:DOY - модификатор получения номера дня в году dt:WOY - модификатор получения номера недели в году unsub.dt - описано забытое ранее поле * Для member.update/delete/sendconfirm и stoplist.add/delete источником адресов может служить Универсальная статистика * Удаление нескольких черновиков за раз в issue.draft.delete 0.111 2013-12-17 * Специальный вызов для отправки пожеланий Деду Морозу sys.dedmoroz * Универсальная статистка stat.uni issue.hourly.* - Кэш быстрого получения значений параметров выпуска (клики,чтения,отписки) с группировкой по каждому часу issue.daily.* - Кэш быстрого получения значений параметров выпуска (доставки,клики,чтения,отписки) с группировкой по каждому дню для каждого домена deliv.oper/size/cost - Детальная статистика каждого получателя sms-рассылки - оператор, количество sms, цена за эти sms issue.double, issue.wrongline, issue.onlyunique - полезная инфомация о статистике Экспресс-выпуска deliv.result - Исход доставки. Вспомогательное значение для облегчения некоторых выборок вычитание day из current округляет время до 0:0:0 указание round позволяет округлить часы и минуты при использовании join можно указать groupby равным 0 - это тоже имеет смысл забытое описание member.haslock = 4 * Общая статистика группы stat.group.common - новая информация об операторах * Учточнение правил экранирования для списков в CSV * Список зарезервированных имён для приложений к письмам * Тест ленты lenta.send ещё удобнее с параметром decor * Изменение ленты lenta.set теперь возвращает id 0.110 2013-10-30 * Выпуск рассылки issue.send новый параметр to.name - имя отправителя новый параметр reply.email - обратный адрес для ответа поддержка выпуска с растягиванием по времени для email - tz_limit параметры отвечающие за содержимое выпуска перенесены в letter (совместимость сохранена) параметр grp переименован в group (совместимость сохранена) уточнение значений по умолчанию для relink.param * Вызовы issue.later.list/get - расширение и совместимость с issue.send (совместимость сохранена) Результат issue.later.get теперь можно использовать для issue.send * Поддержка to.name и reply.email в issue.split.variant.create/set/get, infolett.set/get. issue.draft.set/get * Новая тарификация sms новое значение в stat.issue - sms.cost новая переменная в stat.uni - issue.cost значения sys.settings.get(sms.byed,sms.used) теперь в копейках 0.109 2013-10-17 * Новые вызовы stoplist.add и stoplist.delete с поддержкой трекинга и большими возможностями для замены вызова stoplist.set * Новый вызов member.where - список групп фильтров в которых состоит адрес * Универсальная статистика stat.uni объединение результатов нескольких запросов в один - join новый параметр caption для красивого оформления результатов новые переменные issue.access.* - получения прав доступа к выпуску исправление описание переменной unsub.why - 1 и 2 были перепутаны местами * Работа с файловым хранилищем rfs.file.put/get новый параметр encoding для указания что данные не двоичные, а base64 замечание о кодировке двоичных данных для rfs.file.get/put * anketa.quest.delete - возможность удалить несколько вопросов за раз * anketa.create - теперь всегда возвращает id новой анкеты * Учтонение что wget() пока понимает только константы 0.108 2013-09-20 * Новые возможности динамического контента из RSS и социальных сетей - lenta.* * Выпуск sms c ограничением частоты, времени дня и учётом временной зоны получателя - параметр tz_limit вызова issue.send * Параметры шаблонизатора общие для всех - параметр extra вызова issue.send * Забытое описание параметра email в issue.draft.preview и infolett.preview * Окончание совместимости со старым способом возврата ошибок * Окончание совместимости со старым способом указания уведомлений 0.107 2013-08-01 * Получение анкетных данных из Универсальной статистки через member.anketa.* * Новые переменные в Универсальной статистике issue.archive - адрес архива выпуска issue.thumbnail_* - адреса изображений предпросмотра выпуска issue.hardbounce, issue.stoplist, issue.lockunsub, issue.lockconfirm - количество адресов не допущенных в выпуск с разбивкой по причинам member.haslock = 4 - информация о новой блокировке адреса - из-за фатальных ошибок доставки * Отчёты со статистикой и об ошибках в результатах отслеживания асинхронного вызовы issue.send при рассылке "Экспресс-Выпуск" * Новые статистические данные в member.list.count: locked.stoplist и locked.hardbounced * Указание списка для member.update/delete/sendconfirm с помощью ссылки * Получение адреса изображений предпросмотра выпуска рассылки в issue.get * track.list - в фильтре по статусу можно указать список статусов, а не только один * issue.get ссылка на архив теперь возвращается в параметре archive вместо url * Отменены ни где не используемые параметры: Анкета - member_fill Вопрос анкеты - listsubtype, mustselect, onetime, defval Параметр subtype - только для вопросов dt Параметр width - только для вопросов free * Окончание поддержки старого вызова issue.running "Список выпусков формируемых прямо сейчас" 0.106 2013-07-04 * Модерация имени отправителя sms - вызовы issue.smssender.* * Дополнительный параметр "report_file.json" в результате отслеживания асинхронного вызова member.import * Новый параметр в ответе member.set - newbie * Новые состояния асинхронного запроса - "Отменено" и "Генерация отчёта" * Новые события тригерных действий - "Регистрация с подтверждением" и "Регистрация без подтверждения" * Новый способ выбора победителя сплит-тестирования - "меньше отписок" * Новое состояние сплит-тестирования - "Победитель выбран" * Новый параметр в свойствах варианта сплит-тестирования - is_winner * Новые настройки sms.used, sms.byed и sms.unlimited в вызове sys.setting.get * Окончание совместимости со старыми параметрами вызовов member.import/member.import.probe/anketa.quest.add/anketa.quest.set * !!! Изменился способ указания высылаемых уведомлений в вызовах member.import, member.set, member.sendconfirm !!! ПОДРОБНОСТИ В РАЗДЕЛЕ "Общие замечания" !!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 15 СЕНТЯБРЯ 2013 ГОДА 0.105 2013-06-07 * Новая возможность - Отслеживания состояния и хода асинхронных вызовов - track.* * Измененения в вызовах issue.send, member.* и stat.* для поддержки отслеживания * Новое статистическое поле "отписок" в объекте Выпуск (issue) вызова Универсально Статистики stat.uni * Новая настройка about.user в вызове sys.setting.get * Уточнение формата параметров sys.log * Уточнение описания параметра newbie.confirm и названия вызова member.set * Уточнение описания параметра users.list для member.import * Правильное написание параметра clean_group для member.import * !!! ВЫЗОВ issue.running "Список выпусков формируемых прямо сейчас" УСТАРЕЛ. !!! ИСПОЛЬЗУЙТЕ ЗАМЕНУ "Список асинхронных вызовов" !!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 01 АВГУСТА 2013 ГОДА 0.104 2013-05-07 * Уточнение поведения issue.send c отложеным выпуском 0.103 2013-04-29 * Универсальная статистика stat.uni резко повышенное быстродействие при использовании новых полей новые статистические поля доставки/кликов/чтений в объекте Выпуск (issue) вызова stat.uni и примеры с их использованием новый объект domain - домен подписчика * Новый движок импорта подписчиков. Из видимых изменений у вызовов member.import(.probe) изменился способ возврата ошибок и предупреждений новый параметр clean_group - очистить группу-список перед импортом JSON-объект можно использовать как источник данных * Новая настройка "Не высылать на отсутствующие адреса" issue.dontsend.550 в вызовах sys.settings.get/set * Модерация информационных писем и поле onmoderation в вызовах infolett.* * Работа с анкетами anketa.quest.add/anketa.quest.set -- описание параметра id в ответе anketa.quest.set - изменение нескольких вопросов сразу. новый способ передачи параметров anketa.quest.add - создание нескольких вопросов за раз. новый способ передачи параметров * Вызовы rfs.* новый параметр url уточнение описания * Замечание про тестирование с локальным адресам * Замечание про последовательность обработки 0.102 2013-03-15 * !!! ИЗМЕНИЛСЯ СПОСОБ ВОЗВРАТА ОПИСАНИЯ ОШИБОК !!! !!! ПЕРЕЙДИТЕ НА НОВУЮ СХЕМУ ДО 15 СЕНТЯБРЯ 2013 ГОДА !!! * Новый вызов member.list.count - Количество участников в группе * Список подписчиков member.list: новый параметр member.haslock * Список групп group.list: вставлено забытое описание параметров type и add_type * Прочитать группу group.get новый параметр with_filter параметр id позволяет задавать список групп * Универсальная статистика stat.uni новый параметр "cache" - подсказки как в итоге использовался кэш уточнения про временную зону, 61ю секунда, 23 и 25 часов исправление в примерах * кэширование ответов - уточнение описания режима cache : "fetch" 0.101 2013-01-25 * система кэширования результатов вызовов * Универсальная статистика stat.uni поддержка кэширования и специальный ответ result = "none" поддержка вычитания годов и месяцев из текущей даты и полезны к этому примеры информация об отписках полностью переработаное и расширеное описание всех доступных данных * кэширование условий stat.uni в условиях отбора группы * уточнения описания полей с массивами аресов в sys.settings.* * уточнение описания параметра sort вызова member.list 0.100 2012-12-18 * issue.send: возможность задания данных произвольной сложной структуры для "Экспресс-Выпуска" * новый вызов issue.later.get * новый вызов sys.password.set * новые специальные ответы "Перенаправление" и "Смена пароля" * member.import/member.import.probe: новые поля в ответе rows и queue_position * sys.settings.*: новые параметры redirect.member.join.exists и sec.* * decor,siteform: новый параметр redirect_exists_to * issue.send: возможность указать время отложенного выпуска с точностью до минуты * issue.later.send: возможность указать новое время отложенного выпуска с точностью до минуты * issue.later.list: новое поле draft.id * email.test: новые поля ip и ptr * уточнение описания как работать с сессией авторизации 0.99 2012-11-13 * Описаны лимиты внесения без подтверждения для импорта адресов списком (member.import) и внесения по одному адресу (member.set) * Новый параметр sequence.event в member.import * issue.send: исправлено неверное название параметра draft на верное draft.id * Отслеживание переходов в сплит-тестирования: link.qsid для issue.split.variant.* * Вызовы decor.issue.* (Общее оформление) удалены * issue.later.list - изменения и новые поля в ответе format, group, status.reason, issue.date, status * sys.settings.get - новые значения trial, trial.issue.limit, trial.issue.rest allow.email, allow.sms member.tarif.limit, member.hard.limit, member.noconfirm.limit, member.noconfirm.limit 0.98 2012-10-02 * Группы по результатам статистических запросов (group.filter.set/get) * Прочитать выпуск (issue.get): параметр draft переименован в draft.id новые параметры sequence.id и variant.id * Универсальная статистика (stat.uni) новые поля - issue.draft.id, issue.sequence.id, issue.variant.id, member.haslock новые операции в фильтре - is_null и !is_not сравнение значения поля с текущим временем 0.97 2012-09-06 Сплит-тестирование / А-B тестирование 0.96 2012-08-06 Cобытийные действия / Триггерные рассылки 0.95 2012-07-23 * Новый вызов issue.running * Новый параметр format в вызове issue.list * Новые параметры from,upto,group,format в вызове issue.later.list 0.94 2012-06-26 Транзакционные выпуски. Описание различия между четырмя способами выпуска. 0.93 2012-04-19 * Добавление поддержки списка email или одного email в вызове member.update * Добавлен параметр addr_type для уточнения типа адреса в вызове member.set. * Вызов issue.draft.set - division стало необязательно. * В вызовах issue.draft.get,issue.draft.set,issue.draft.list для использования предустановленных черновиков добавлены параметры "template", "template.thumbnail". * Форматирование, уточнения (group.create, issue.draft.get). 0.92 2012-02-15 * Формат данных подписчиков для импортирования и экспресс выпуска (users.list) изменен * Поддерживается формат XLSX или стандартный CSV (разделитель колонок - запятая, допускается заключение текста ячейки в кавычки) 0.91 2012-01-31 * Добавлена поддержка параметра "result", для вызовов stat.issue и stat.uni. * Во всех запросах использующих параметр "result" = (response|email|save) добавлен дополнительный параметр "result.format" для возможности выбора формата XLSX, если "result" равен "save" или "email". * Сам параметр "result" стал необязательным, по умолчанию -"response". 0.90 2012-01-20 Поддержка авторизация с помощью биометрических карт AGSES 0.89 2011-11-11 * Исправления stat.issue (описание, добавлен итог по выпускам и получателям), * stat.activity (добавлена возможность сохранения и высылки,обратная сортировка, изменения в описании), * stat.uni (добавлены типы статистики deliv_ok deliv_bad deliv_unk и пример их использования в сводной статистике) 0.88 2011-10-26 Возможность влиять на код группы-списка создваемой при внесении списка подписчиков 0.87 2011-10-20 Не совместимое изменение работы member.get и member.set с участием в группах-списках. 0.86 2011-10-18 Возможность разовой авторизации. 0.85 2011-10-17 Новые вызовы user.create, user.delete, user.set (вместо sys.password.set) 0.84 2011-10-13 Новые вызовы issue.later.*, rights.*, user.list, issue.draft.preview и infolett.preview. 0.83 2011-10-10 Новые вызовы link.* и sys.messaage. Вызов about.get удалён. 0.82 2011-09-27 Вызов "Универсальная статистика" 0.81 2011-09-26 Новый вызов "Окончание работы". Уточнение что импорт может добавлять в любую группу-список 0.80 2011-09-22 Вызов создания группы group.create теперь полностью поддерживает создание группы-списка 0.79 2011-09-14 Только протокол https; Вызов about.get будет удалён 0.78 2011-09-13 Добавлены разделы "Журнал работы", "Пароль", "Чтение настроек", "Изменение настроек", "Общая статистика по группе", "Статистика выпусков", "Портрет аудитории", "Доставка выпусков" 0.77 2011-08-11 Добавлены разделы "Пригласить подписчиков","Общее оформление выпусков", "Массовое изменение данных подписчиков", "Форма подписки для сайта", "Файлы изображений и отчетов" 0.76 2011-06-27 Добавлен раздел "Форматы просмотра и шаблоны заполнения" 0.75 2011-06-23 Вызов member.delete может работать со списком и группой 0.74 2011-05-30 Уточнение описания member.list 0.73 2011-05-30 Форматирование 0.72 2011-05-30 Добавлен раздел "Список подписчиков" (вызов member.list), и "Архив выпусков" (вызов issue.list) 0.71 2011-05-11 Добавлен раздел "Черновики выпусков" 0.70 2011-04-29 Расширение функций вызова stat.activity 0.69 2011-04-27 Вызов email.test 0.68 2011-04-26 Добавлен раздел "История изменений" 0.67 2011-04-26 * Вынос вызовов <OBJ>.list к своим объектам. Описание синхронных и асинхронных вызовов. * Уточнение про медленные фильтры. Форматирование. 0.66 2011-04-25 Вызовы issue.draft.*, и infofett.* 0.65 2011-04-25 Форматирование 0.64 2011-04-25 Уточнения в описании стоп-листа 0.63 2011-04-25 Форматирование 0.62 2011-04-25 Добавление вызовов stoplist.* Удаление stoplist.list 0.61 2011-04-12 Описание параметра group в вызове member.set 0.60 2011-04-12 Описание параметра newbie.confirmв вызове member.set 0.59 2011-04-11 Уточнения типа _plain после quest пугали людей и они писали fio_plain 0.58 2011-04-11 Описан member.get 0.57 2011-03-17 Списковые ответы опять хэш.Разница между получением и установкой фильтра. Пример расширен работой с датой 0.56 2011-03-16 Форматирование 0.55 2011-03-16 Улучшено описание параметра session, вызов about.get отнесён в статистику 0.54 2011-03-16 Форматирование 0.53 2011-03-16 Описание фильтра отбора в группе 0.52 2011-03-15 Форматирование 0.51 2011-03-15 Форматирование 0.50 2011-03-15 Форматирование 0.49 2011-03-15 Форматирование 0.48 2011-03-14 member.set::newbie.notify иmember.set::newbie.notify.letter 0.47 2011-03-11 Более внятное название название метода 0.46 2011-03-10 member.set/confirm/delete 0.45 2011-03-10 anketa.save/anketa.quest.save ->anketa.set/anketa.quest.set 0.44 2011-03-01 Уточнение, что дополнятся при импорте может не любая группа 0.43 2011-02-17 Общее описание методов получение изамены фильтра в группе 0.42 2011-02-17 Описание общих методов работы сгруппами 0.41 2011-02-15 Форматирование