!!! ИЗМЕНИЛСЯ СПОСОБ ВОЗВРАТА ОПИСАНИЯ ОШИБОК !!!
!!! ПЕРЕЙДИТЕ НА НОВУЮ СХЕМУ ДО 15 СЕНТЯБРЯ 2013 ГОДА !!!
!!! ИЗМЕНИЛОСЬ НАЗВАНИЕ ПАРАМЕТРА С КОДОМ ОШИБКИ В ВЫЗОВАХ member.import/member.import.probe !!!
!!! ПЕРЕЙДИТЕ НА НОВОЕ НАЗВАНИЕ ДО 15 ИЮНЯ 2013 ГОДА !!!
!!! ИЗМЕНИЛСЯ СПОСОБ ПЕРЕДАЧИ ПАРАМЕТРОВ В ВЫЗОВАХ anketa.quest.add/anketa.quest.set !!!
!!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 15 ИЮНЯ 2013 ГОДА !!!
!!! ВЫЗОВ "Список выпусков формируемых прямо сейчас" УСТАРЕЛ. ИСПОЛЬЗУЙТЕ ЗАМЕНУ "Список асинхронных вызовов" !!!
!!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 01 АВГУСТА 2013 ГОДА !!!
Метод вызова - POST.
Не забывайте, что вы будете использовать протокол HTTP и, следовательно, название и значение параметров вызова надо передавать в кодировке urlencode (RFC 1738 http://tools.ietf.org/html/rfc1738).
Описание формата JSON вы найдёте в RFC 4627 http://tools.ietf.org/html/rfc4627
Пример данных для вызова функции login методом POST:
apiversion=100&json=1&request.id=777&request={"action":"login","login":"jondoe","passwd":"secret"}
Последовательность обработки одновременных вызовов не гарантирована так как они выполняются параллельно.
Если вам требуется твёрдая уверенность в том, что вызов Б нормально воспользуется результатами более раннего вызова А, то вы должны дождаться явного окончания вызова А и только потом посылать вызов Б.
Например, два вызова anketa.quest.add в случае, когда они сделаны для одной и той же анкета и второй вызов послан до окончания первого, могут дать три разных результата
- добавятся оба вопроса
- только первый
- только второй
Ответ выдаётся в формате JSON и кодировке UTF-8
Если иного не описано, то вызов является синхронным - запрошенное действие будет выполнено (или не выполнено при ошибке) к моменту ответа на вызов.
Если вызов помечен как асинхронный, то успешный ответ обозначает что запрошенное действие принято и будет выполнено позже в порядке обработки очереди запросов на такое же действие.
Асинхронный вызов возвращает track.id - номер запроса для отслеживания с помощью track.get
{ "request.id" : "то что было в запросе в параметре request.id" ,"duration" : null или "время обработки запроса" }
{ <общие поля> ,<поля специфические для конкретного запроса> }
При наличии ошибки (ошибок) препятствующих полному или частичному выполнению запроса в ответе появится массив errors со списком описаний каждой ошибки.
Обратите внимание, что, зависимости от вызова и самой ошибки, поле explain может быть не только строкой, но и массивом и объектом.
Часть вызовов может возвращать массив warnings аналогичный структуры для того что бы сообщить о событиях помешавших выполнить вызов в какой-либо его части, но не позволяющих считать что вызов ошибочен.
Для совместимости со старым способом возврата ошибки, временно, до 15 сентября 2013 года, будут возвращаться так же и прежние поля error/explain со значениямм взятыми от первой ошибки в массиве errors.
{ <общие поля> ."errors" => [ { "id" : "код ошибки-1" ,"explain" : "возможное более развёрнутое описание-1" ,<возможно поля специфические для конкретного запроса-1> } ,{ "id" : "код ошибки-2" ,"explain" : "возможное более развёрнутое описание-2" ,<возможно поля специфические для конкретного запроса-2> } ...... ] -- *до 15 сентября 2013 года, для совместимости со старым способом возврата ошибок* ,"error" : "код ошибки-1" ,"explain" : "возможное более развёрнутое описание-1" }
При наличии в ответе поля REDIRECT необходимо
Так же стоит иметь счётчик перенаправлений что бы избежать зацикливания
В данный момент ограничение максимальной глубина перенаправлений десятью
выглядит достаточным.
{ <общие поля> ,"REDIRECT" : "/xxx/yyy" }
Получение ответа с ошибкой 'error/auth/failed' и уточнением 'force_change_password' означает,
что для продолжения работы данной комбинацией login/sublogin требуется сменить пароль.
Это может быть вызвано как автоматическими событиями (например истёк срок действия пароля),
так и прямой установкой такого требования через вызов user.set или sys.password.set
Для продолжения работы необходимо:
{ <общие поля> ,"error" : "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" : "ping" }
ответ
{ <общие поля> ,"pong" : "что-то каждый раз разное" }
{ "action" : "pong" }
ответ
{ <общие поля> ,"ping" : "что-то каждый раз разное" }
Полученный в ответ номер сессии должен передаваться во всех запросах в 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" : "личный логин для которого выдана авторизация" }
Указанный параметр передаётся во параметрах вызова вместо "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" ,"status" : состояние запроса -- -2 - закончился ошибкой -- -1 - закончился успешно -- 0 - принят -- 1 - запущен -- 2 - начата обработка -- 3 - сортировка -- 4 - форматирование -- остальное - зависит от типа запроса ,"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 } -- === 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" : "код группы" -- пусто если при импорте не указывалась автосоздание новой -- или заполнение существующей группы иначе код автосозданой -- существующей группы ,"report_file" : "название файла" -- файл с отчётом если были ошибки ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } ,"statistic" : { -- статистика после завершения работы "inserted" : добавлено новых адрес ,"updated" : обновлено адресов '"erroneous" : строк с ошибками ,"unconfirmed" : новых адресов внесённых без подтверждения ,"repeated" : повторов адресов } -- === member.list.count === -- === member.sendconfirm === -- === member.update === -- === member.delete === "group.id" : "код группы" -- пусто если считается без указания группы -- иначе код группы указанной для расчёта ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } -- === issue.split.create === -- отслеживается не "создание" (как формально следует из названия) -- а процесс формирования списка получателей и назначения им того или иного варианта -- соответственно, трекер отслеживает тестирование в состояние "подготавливается к запуску" "split.id" : "код группы" -- номер сплит-тестирования ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе } } } }
{ "action" : "anketa.list" }
ответ
{ <общие поля> ,"list" : [ { "system" : "системная, да, нет (1, 0)" ,"member_fill" : "заполняется подписчиком, да, нет (0, 1)" ,"id" : "уникальный идентификатор" ,"name" : "название", } ... ] }
{ "action" : "anketa.get" ,"id" : код-анкеты }
ответ
{ <общие поля> ,"obj" : { "id" : код-анкеты, "param" : { "name" : название анкеты, "system" : анкета системная да/нет, "member_fill" : разрешено заполнять пользователю да/нет }, "order" : [ -- порядок вопросов "код-вопроса3", "код-вопроса8", ..... "код-вопроса4" ] "quests" : { -- вопросы анкеты "код-вопроса" : { "id" : код-вопроса, "@" : номер по порядку, "name" : формулировка вопроса, "type" : тип вопроса, "subtype" : под-тип вопроса, "width" : ширина ответа в байтах, "onetime" : заполняется однократно да/нет, "mustselect" : обязателен для заполнения да/нет, "defval" : значение по умолчанию, "answers" : { -- ответы вопроса "код ответа1" : "название ответа1", "код ответа2" : "название ответа2", ..... "код ответа3" : "название ответа3", }, "order" : [ -- порядок ответов "код ответа3", "код ответа1", ..... "код ответа2" ], }, ............ }, }
тип/под-тип вопроса:
{ "action" : "anketa.delete" ,"id" : "уникальный идентификатор анкеты" }
ответ
{ <общие поля> }
{ "action" : "anketa.create" ,"name" : "Название анкеты", необязательные: ,"copy_from" : "уникальный идентификатор анкеты (не нужен для создаваемой с нуля, а не копируемой анкеты)" ,"id" : "уникальный код анкеты" ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
{ "action" : "anketa.set" ,"id" : "идентификатор анкеты" ,"member_fill" : "заполняется подписчиком -- да, нет( 1 | 0 )" ,"name" : "название анкеты" необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" по умолчанию, считается "return_fresh_obj" : "0" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Cовместимость - старый способ передачи описания вопроса, когда все его параметры передаются на том же уровне что и "action" будет поддерживаться до 01 инюя 2013 года
{ "action" : "anketa.quest.add" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию) -- добавление одного вопроса ,obj : { -- описание вопроса "name" : "Текст вопроса" ,"type" : "(free, dt, 1m, nm ,int ,has)" -- тип вопроса -- свободный ввод, дата и время, выбор одного из списка, -- выбор нескольких из списка, целое число, существует ,"mustselect" : "Обязательно подписчику для заполнения - да , нет ( 1 | 0 )" ,"onetime" : "Ответ подписчиком дается только один раз - да , нет ( 1 | 0 )" -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода, обязателен, > 0" -- для type=dt: ,"dtsubtype" : "точность для даты и времени (yd, yh, ym, ys), обязателен" -- для type=1m или nm (выбор из списка): ,"listsubtype" : "из списка ('yn' ,'year', 'month', 'day'), не обязателен" ,"answers" : { -- ответы вопроса "код ответа 1" : "название ответа1" ,"код ответа 2" : "название ответа2" ..... ,"код ответа N" : "название ответаN" } ,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" ..... ,"код ответа 4" ] -- необязательные для любого типа ,"id" : "уникальный идентификатор вопроса" ,"defval" ; "значение по умолчанию (для has не нужен вообще, для 1m и nm - код ответа, для остальных - значение ответа)" } -- добавление нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все добавлены или все не добавлены ,obj : [ { описание вопроса-1 } ,{ описание вопроса-2 } ,............... ] }
ответ
{ <общие поля> ,"obj" : { объект анкета как из ответа anketa.get } -- если "return_fresh_obj" : "1" -- в зависимости от вида параметра obj в вызове ,"id" : "id-добавленного вопроса" -- или ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове "id-добавленного вопроса-1" ,"id-добавленного вопроса-2" ....... ] }
Cовместимость - старый способ передачи описания вопроса, когда все его параметры передаются на том же уровне что и "action" будет поддерживаться до 15 инюя 2013 года
{ "action" : "anketa.quest.set" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию) -- добавление одного вопроса ,"obj" : { -- описание вопроса "id" : "уникальный идентификатор вопроса" ,"name" : "Текст вопроса" ,"mustselect" : "Обязательно подписчику для заполнения - да , нет ( 1 | 0 )" ,"onetime" : "Ответ подписчиком дается только один раз - да , нет ( 1 | 0 )" -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода, обязателен, > 0" -- для type=1m или nm (выбор из списка): ,"answers" : { -- ответы вопроса "код ответа 1" : "название ответа 1" ,"код ответа 2" : "название ответа 2" ..... ,"код ответа N" : "название ответа N" } ,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" ..... ,"код ответа 4" ] -- необязательные для любого типа в целом ,"defval" ; "значение по умолчанию (для has не нужен вообще, для 1m и nm - код ответа, для остальных - значение ответа)" } -- изменение нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все изменены или все не изменены ,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" : "уникальный идентификатор вопроса" необязательный ,"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" соответствующей анкеты
{ "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" соответствующей анкеты
{ "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 } } }
При отсутствии адреса в базе он автоматически создаётся.
{ "action" : "member.set" ,"email" : "адрес подписчика" ,"addr_type": "тип адреса подписчика (email | msisdn)" ,"source" : "ip-адрес оригинального запроса" -- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос ,"if_exists" : "error|update|overwrite" -- правило изменения ответов анкетных данных. не действует на псевдоанкету "-group" -- error - при наличии адреса в базе возвращается ошибка -- update - если ответ на изменяемый вопрос уже есть то он остаётся неизменным -- overwrite - ответ заменяется/создаётся в любом случае ,"newbie.notify" : "сразу высылать письмо с просьбой подтвердить регистрацию новому подписчику (1|0)" -- если адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения, то ему высылается запрос для подтверждения регистрации -- отсутствие параметра (или значение 0) приведёт только кто тому, что не будет выслан запрос. -- а неоходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm -- при внесении номеров телефонов ни какие уведомления не высылаются и подтверждения не требуется ,"newbie.notify.letter" : "номер шаблона письма" -- Текст запроса будет стандартный (параметр отсутствует) или будет -- использован текст из указанного шаблона информационных писем ,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)" -- действует лимит внесения без подтверждения -- подробнее описанный в вызове member.import ,"obj" : { -- управление анкетными данными подписчика -- ank - код анкеты -- quest - код ответа -- val - значение ответа или код ответа если вопрос с выбором из списка 'ank1' : { -- установка значения ответа обычного вопроса 'quest' :'val' -- установка значения ответа у вопроса с множественным выбором ,'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" }
ответ
{ <общие поля> } если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "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 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1 -- результат удаления - 1 - удалён, 0 - нет (например адрес ошибочен или отсутствует) ,"адрес-2" : 0|1 ................. } }
{ "action" : "member.list" ,"addr_type": "тип выбираемых адресов подписчиков (email | msisdn)" -- при отсутвии определяется по типу адресов в указанной группе -- если указан, то должен совпадать с типом адресов в группе, если и та указана -- если не указан и не указана группа, то выбираются еmail-адреса ,"group" : "идентификатор группы" -- задает фильтр по списку подписчиков группы-фильтра или группы-списка (необязателен) ,"member.haslock" : "код" -- учёт состояния блокировки подписчика -- пусто или отсутствует - не учитывать состояние блокировки -- -1 - есть хоть какая-то блокировка - не может получать письма или sms -- 0 - нет блокировки - может получать письма или sms -- 1 - заблокирован так как отписался - не может получать письма или sms -- 2 - заблокирован так как не подтверждён - не может получать письма или sms -- 3 - 1 и 2 сразу - не может получать письма или sms -- -- формально этот параметр можно заменить дополнительными условиями в фильтре группы -- но его использование позволяет -- * не меняя фильтра групп узнавать сколько в ней всего участников и сколько из них могут получать письма -- * не создавая группы узнавать это же для всех свои адресов вообще -- * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы ,"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" : в том числе заблокированные так как не подтвердили внесение в базу -- при подсчёте по всем подписчикам, дополнительно появляются поля ,"total.email" : всего именно email ,"total.msisdn" : всего именно телефонов ,"active.email" : способных получать именно адреса ,"active.msisdn" : способных получать именно телефоны } }
Вызов member.import.probe предназначет для проверки что думает система импорта о ваших входных данных.
В ответ будет сообщено как произошло авто-определение кодировки (сharset), разделителя столбцов, определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких анкет приписаны столбцы данных
Если вы знаете зарание ответы на эти вопросы, то можете сразу указать эти данные при вызове тогда выше указание будет иметь приоритет над авто-определением системы.
Вызов member.import реально импортирует данные, описаные выше параметры будет определены автоматически если их не указать сразу при вызове.
Вызов member.import асинхронный - получение положительного ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта - он может не состоятся из ошибок возникших позже.
Совместимость. Для временного сохранения совместимости со старым способом возврата предупреждения и ошибок, в записях о предупреждениях и ошибках сохранён (но уже тут не описан) старый параметр name, выставляемый сейчас равным новому параметру id. Старый параметр name будет окончательно убран 15 июня 2013 года.
Не совместимость. Все возможные проблемы (фатальные или нет - смотрите по 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.notify" : "сразу высылать письмо с просьбой подтвердить регистрацию новому подписчику (1|0)" -- если адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения, то ему высылается запрос для подтверждения регистрации -- отсутствие параметра (или значение 0) приведёт только кто тому, что не будет выслан запрос. -- а неоходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm -- при внесении номеров телефонов ни какие уведомления не высылаются и подтверждения не требуется ,"letter" : "id информационного письма" -- это письмо с просьбой подтвердить регистрацию, которое будет выслано при внесении -- если это указано настройкой newbie.*", -- отсутствие или пусто - использовать текст по умолчанию ,"newbie.confirm" : "подписчик должен подтвердить внесение в базу (1|0)", -- по умолчанию - внесение без необходимости подтверждения подписчиком (0) -- внесение email без подтверждения ограничено величиной member.noconfirm.rest -- (узнать можно через sys.settings.get) при её исчерпании остальные адреса -- вносятся с подтверждением. -- если количество адресов в базе превышает member.tarif.limit, то величина member.noconfirm.rest -- равна нулю, иначе она равна member.noconfirm.limit за вычетом количества уникальных email -- адресов внесённых в текущем месяце -- на внесение номеров телефонов параметр newbie.confirm не влияет (они всегда вносятся без подтверждения) ,"auto_group" : { -- автоматически создать группу-список для импортируемых адресов -- или дополнить любую существующую группу-список импортируемыми адресами -- отсутствие всего параметра auto_group означает ни создавать новую ни пополнять существующую группу -- наличие auto_group но без id и без name означает создание группы со стандартным кодом -- и со стандартным названием. код созданый группы можно узнать используя возвращаемый номер track.id -- и вызов track.get "id" : "идентификатор группы-списка для пополнения" -- при отсутствии такой группы она создаётся автоматически -- если параметр пуст или отсутствует то используется стандартный -- код вида importYYYYYMMDDhhmmss ,"name" : "название группы" -- название для создаваемой группы. -- если параметр пуст или отсутвует то используется стандартное "Внесены <дата-время импорта>" }, ,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список указанную в auto_group перед началом импортирования -- позволяет не дополнять группу, а полностью заменять её участников -- -- сначал проверяются все возможные причины по которым импорт может не начаться. если они есть, то импорт заканчивается ошибкой и очистка не происходит -- иначе импорт начинается с очистки списка участников, а внесение новых происходит только после этого -- -- не путайте удаление адреса из списка участников с удалением адреса из базы - это разные вещи -- -- при одновременном импортировании в одну группу несколькими вызовами у которых хоть у одного cleangroup=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 - асинхронный }
ответ
{ <общие поля> -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : { "адрес-1" : 0|1 -- результат высылки - 1 - выслано, 0 - нет (например адрес ошибочен или отсутствует или не нуждается в подтверждении) ,"адрес-2" : 0|1 ................. } }
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
{ "action" : "member.update" -- указание подписчиков одним из способов ,"email" : "адрес подписчика" или ,"list" : [ "адрес подписчика" ,"адрес подписчика" ........ ] ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы к участникам которой будут применены изменения ,"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 ................. } }
{ "action" : "decor.siteform" ,"format" : "html" (в данный момент только одно это значение) ,"fields" : [ -- список вопросов в порядке, в котором они должны быть в форме { "anketa" : "код анкеты" ,"quest" : "код вопроса" } ..... ] ,"letter" : "код информационного письма, высылаемого после регистрации" (не обязательно) ,"redirect_to" : "полный урл для перенаправления после регистрации нового пользователя" (не обязательно) -- если не указан, то будет использована глобальная настройка -- redirect.member.join, если она заполнена -- укажите значение "-" для отмены действия глобальной настройки ,"redirect_exists_to" : "полный урл для перенаправления если пользователь уже существует" (не обязательно) -- если не указан, то будет использована глобальная настройка -- redirect.member.join.exists, если она заполнена -- укажите значение "-" для отмены действия глобальной настройки }
ответ
{ <общие поля> , "siteform" : "html код формы" }
Хранилище файлов имеющееся в вашем распоряжении позволяет держать в нём изображения и файлы на которые вы ссылаетесь из писем или прикрепляете к ним (хранилище картинок) и получать от системы отчёты которые вы заказывали с параметром "сохранить на сервере" (хранилище отчётов).
Хранилище файлов доступно через веб-ссылки, что бы на него можно было ссылаться из писем.
К хранилищу отчётов публичного доступа нет. Его файлы доступны только через 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" : "полный путь с названием файла" }
ответ
{ <общие поля> ,"datа" : содержимое файла }
Только для domain = image
{ "action" : "rfs.file.put" ,"domain" : "image" ,"path" : "полный путь с названием файла (отсутствующие попутные подкаталоги НЕ создаются автоматически)" ,"datа" : содержимое файла }
ответ
{ <общие поля> ,"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", "gid" : "id группы | masssending - если это Экспресс-Выпуск | personal - Транзакционное письмо", "lang": "язык выпуска" (ru - Русский |uk - Украинский |be - Белорусский)", (по умолчанию "ru") (игнорируется для SMS) * параметры содержимого выпуска. Для Транзакционных писем - только указание черновика. "from.name": "Имя отправителя", (по умолчанию название аккаунта) "from.email": "Адрес отправителя(email)", (игнорируется для SMS) (по умолчанию базовый адрес аккаунта) "subject": "Тема письма", (игнорируется для SMS) "message": { -- для выпуска по email-адресам одна или обе версии письма 'html' : 'html-версия письма' ,'text' : 'текстовая версия письма' -- для выпуска по SMS 'sms' : 'sms cообщение' } или черновик из которого их взять. при указании черновика другие параметры содержимого игнорируются "draft.id": "номер черновика содержимое которого даст выпуск", -- тип черновика определит вид и формат рассылки (email или sms) * параметры способа выпуска. Тестовый выпуск не доступен для Экспресс-Выпуска и Транзакционных писем. "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", ...... ] * параметры преобразования ссылок для учёта перехода по ним "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 * параметр прикрепления файлов. тип файла определяется по расширению. "attaches": [ { "name": "имя файла", "content": "содержимое файла" }, { "name": "имя файла", "content": "содержимое файла" }, { "url": "url откуда заборать" }, { "url": "url откуда заборать" }, ... ], * список получателей для Экпресс-Выпуска "users.list": адреса и данные персонализации -- непосредственно в JSON (два варианта) или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" или "users.url": "URL по которому находятся список адресов с данными для персонализации ftp:// или http(s)://", * параметры списка получателей для Экпресс-Выпуска "only_unique": 0|1 -- Следить за уникальностью адресов в списке -- 1 - да, повторно встреченные адреса исключаются из выпуска -- 0 - нет, повторно встреченные адреса участвуют в рассылке * получатель для Транзакционных писем "email" : "адрес получателя" -- данные для персонализации берутся из базы или "users.list": один адрес и данные персонализации -- непосредственно в JSON (два варианта) или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" -- при указании только адреса данные персонализации берутся из базы -- при нескольких адресах используется только первый }
ответ
{ <общие поля> ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* }
Вызов issue.running устарел и будет удалён 01 августа 2013 года
Используйте вызов "Список фоновых действий" с параметрами как приведено ниже дпя получение списка выпусков формируемых прямо сейчас или закончившихся с ошибкой.
{ "action" : "track.list" ,"filter" : { "action" : "issue.send" ,"!status" : -1 } }
{ "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" : "код выпуска" ,"format" : html|text|sms ,"group" : код группы для которой отложен выпуск ,"name" : "название выпуска (тема)" ,"draft.id" : код черновика используемого для выпуска ,"create.date" : "YYYY-MM-DD hh:mm:ss" -- дата постановки задания ,"status" : "статус задания" -- hold - отложено на хранение -- later - отложено для выпуска -- error - ошибка выпуска -- если статус "отложено для выпуска" ,"issue.date" : "YYYY-MM-DD hh:mm" -- запланированная дата выпуска -- если статус "отложено из-за ошибки" ,"status.reason" : код ошибки }, ... ] }
{ "action" : "issue.later.get", "id" : "код выпуска", }
ответ
{ <общие поля> ,"obj" : { "id" : "код выпуска" ,"format" : html|text|sms ,"group" : код группы для которой отложен выпуск ,"name" : "название выпуска (тема)" ,"draft.id" : код черновика используемого для выпуска ,"create.date" : "YYYY-MM-DD hh:mm:ss" -- дата постановки задания ,"status" : "статус задания" -- hold - отложено на хранение -- later - отложено для выпуска -- error - ошибка выпуска -- если статус "отложено для выпуска" ,"issue.date" : "YYYY-MM-DD hh:mm" -- запланированная дата выпуска -- если статус "отложено из-за ошибки" ,"status.reason" : код ошибки ,"message": { -- для выпуска по email-адресам одна или обе версии письма 'html' : 'html-версия письма' ,'text' : 'текстовая версия письма' -- для выпуска по SMS 'sms' : 'sms cообщение' } } }
Если на новую дату выпуска уже запланирован выпуск по такой же группе, то изменение даты закончится ошибкой.
Исключение - Экспресс-Выпуск и Транзакционные Письма. Выпуски по этим группам могут быть запланированы на одну и ту же дату в любом количестве.
{ "action" : "issue.later.send", "id" : "код выпуска", "issue.date" : "YYYY-MM-DD hh:mm" -- Новая дата выпуска -- Если параметр отсутствует или указана дата в прошлом, -- то выпуск выйдет сразу }
ответ
{ <общие поля> }
{ "action" : "issue.later.delete", "id" : "код выпуска" }
ответ
{ <общие поля> }
Сплит-тестирование (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 -- способ выбора победителя - в ручную, по чтениям или по кликам -- игнорируется, если процент равен 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 - ожидает выбора победителя -- 4 - завершено -- -1 - ошибки ,"parts" : [ -- список вариантов тестовых писем { "id" : "номер варианта" ,"start.at" : "время запуска" ,"issue.at" : "номер выпуска" -- если вариант уже выпущен для теста ,"issue.winner" : "номер выпуска" -- если выпущен выпущена как победитель } ,{ ...... } ....... ] }
{ "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" : "номер выпуска" } ,........ ] }
Нельзя создать новый вариант если тестирование не в состоянии "ожидает выпуска"
{ "action" : "issue.split.variant.create" ,"split.id" : номер тестирования -- параметры варианта ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты ,"letter" : { -- высылаемое письмо ,"format" : "html|sms|text" -- формат письма. в данный момент поддерживается только html ,"from" : "email отправителя", ,"sender" : "имя отправителя", ,"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" : "имя отправителя", ,"subject" : "тема письма", ,"text" : "текст письма в соответствующем формате" ,"link.qsid" : "параметр отслеживания переходов" } ,"issue.at" : "номер выпуска" -- если вариант уже выпущен для теста ,"issue.winner" : "номер выпуска" -- если вариант выпущен как победитель }
Изменить вариант письма можно только если тестирование в состоянии "ожидает запуска" или дата запуска варианта письма ещё не прошла или и тестирование не активно и изменяемый вариант ещё не выпущен.
{ "action" : "issue.split.variant.set" ,"id" : номер варианта -- параметры варианта, изменятся только явно указанные. параметр letter заменяется полностью ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты ,"letter" : { -- высылаемое письмо ,"format" : "формат письма" ,"from" : "email отправителя", ,"sender" : "имя отправителя", ,"subject" : "тема письма", ,"text" : "текст письма в соответствующем формате" ,"link.qsid" : "параметр отслеживания переходов" } ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" }
ответ
{ <общие поля> ,"id" : номер варианта тестирования } если "return_fresh_obj" : "1" ответ -- как на запрос "issue.split.variant.get" соответствующего варианта
Нельзя удалять вариант если тестирование не в состоянии "ожидает выпуска"
{ "action" : "issue.split.variant.delete" ,"id" : номер варианта }
ответ
{ <общие поля> }
{ "action" : "issue.list" ,"from" : "YYYY-MM-DD" -- от даты (не обязательно) ,"upto" : "YYYY-MM-DD" -- до даты (не обязательно) ,"group" : [ -- фильтр по группам (не обязательно) код-группы-1 ,код-группы-2 ... ] ,"format" : "email|sms|html|text" -- фильтр по формату (не обязательно). -- email это "html или text" }
ответ
{ <общие поля> ,"list" : [ { "id" : "уникальный идентификатор выпуска" } ... ] }
{ "action" : "issue.get" ,"id" : "уникальный идентификатор выпуска" }
ответ
{ <общие поля> "obj" : { "id" : "уникальный идентификатор выпуска", ,"date" : "дата выпуска", ,"group" : "уникальный идентификатор группы выпуска", ,"format" : "html|text|sms", -- формат выпуска ,"title" : "тема письма" ,"issue.access" : { "права доступа у выпуску. структура аналогичная параметру access вызова issue.set.acesss, за исключением отсутствия варианта default" } ,"text" : "содержимое выпуска" ,"draft.id" : "уникальный идентификатор черновика, по которому сделан выпуск", ,"sequence.id" : "уникальный идентификатор последовательности, событие в которой вызвало выпуск", ,"variant.id" : "уникальный варианта сплит-тестирования для которого сделан выпуск", ,"attach" : [ -- прикрепленные файлы "aaa.doc" ,"bbb.doc" ... ] ,"url" : { "public" : "http://..." -- ссылка на выпуск для доступа без авторизации подписчика ,"member" : "http://..." -- ссылка на выпуск для доступа с авторизацией подписчика } } }
{ "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" : "имя отправителя (для выпуска)", ,"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" : "имя отправителя (для выпуска)", ,"subject" : "тема письма (для выпуска)", ,"text" : "текст черновика в соответствующем формате" } необязательные "id" : "идентификатор черновика" -- если не указан, создается новый ,"return_fresh_obj": "" -- вернуть объект в формате issue.draft.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате issue.draft.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "issue.draft.delete" ,"id" : "код черновика" }
ответ
{ <общие поля> }
{ "action" : "issue.draft.preview" "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" : "имя отправителя", ,"subject" : "тема письма", ,"text" : "текст" } }
При создании или изменении шаблона он автоматически попадает на модерацию и использовать его при высылке писем нельзя. Но его можно повтороно менять и удалять.
По результатам модерации вам придёт уведомление.
{ "action" : "infolett.set" ,"obj" : { ,"name" : "название" ,"format" : "html|sms|text" -- формат ,"from" : "email отправителя", ,"sender" : "имя отправителя", ,"subject" : "тема письма", ,"text" : "текст" } -- необязательные ,"id" : "идентификатор шаблона" -- если не указан, создается новый ,"return_fresh_obj": "" -- вернуть объект в формате infolett.get }
ответ
{ <общие поля> ,obj { ... } -- объект в формате infolett.get при наличии в запросе параметра "return_fresh_obj" }
{ "action" : "infolett.delete" ,"id" : "идентификатор шаблона" }
ответ
{ <общие поля> }
{ "action" : "infolett.preview" ,"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" : "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.
Если в выпуске есть ссылки для отслеживания, то, при необходимости, создаются соответствующие им объекты "ссылка".
Все ссылки одного выпуска автоматически приписываются к автоматически создаваемому объеку "группа ссылок" который соответствует этому выпуску.
{ ,"action" : "link.list" ,"group" : "идентификатор группы" -- не обязательно -- при наличии ограничеивает спискок только ссылками указаной группы } ответ { <общие поля> ,"list" : [ { "id" : "идентификатор ссылки" ,"url" : "url ссылки" ,"group" : [ { "id" : "идентификатор группы ссылок" ,"name" : "название группы ссылок" } ... ] } ... ] ,"group" : { -- присутствует в ответе, только если в запросе был указан идентификатор группы "id" : "идентификатор группы" ,"name" : "название группы" } }
При изменении нескольких ссылок все изменения будут проигнорированы если проверка (GET) хоть одной ссылки для которой указано 1 вернёт HTTP код ответа не 2xxx и не 301, 302, 303, 401
{ "action" : "link.set" или одна ссылка ,"id" : "идентификатор ссылки" ,"url" : "url ссылки" ,"test" : "1/0 - проверять доступность ссылки" или несколько ссылок ,"list" : [ { "id" : .... ,"url" : .... ,"test" : .... } .. ] } ответ { <общие поля> }
{ "action" : "link.set.group" ,"id" : "идентификатор ссылки" ,"group" : { -- участие в не указанных группах не изменяется "id1" : "0 - удалить из группы. 1 -добавть в группу" ,"id2" : "0|1" ,"id3" : "0|1" ... } } ответ { <общие поля> }
{ "action" : "link.group.list" } ответ { <общие поля> ,"list" : [ { "id" : "идентификатор группы ссылок" ,"name" : "название группы ссылок" } ... ] }
{ ,"action" : "link.group.set" ,"id" : "идентификатор группы" -- если не указан, создается новый ,"name" : "название группы" } ответ { <общие поля> ,"id" : "идентификатор группы" }
Удаляется именно группа ссылок как объект обеспечивающий группировку ссылок.
Входящие в нёё ссылки не удаляются.
{ ,"action" : "link.group.delete" ,"id" : "идентификатор группы" } ответ { <общие поля> }
Существует два стоп-листа: владельца (A) - вы им полностью управляете и подписчика (M) - вносит в него себя подписчик сам и вы не можете повлиять на имеющиеся там записи.
{ "action" : "stoplist.erase" }
ответ
{ <общие поля> }
{ "action" : "stoplist.set" "list" : { "email" : 1 -- внести в стоп-лист запись типа А ,"email" : 0 -- удалить из стоп-листа запись типа А .............. } }
ответ
{ <общие поля> }
{ "action" : "stoplist.get" ,"type" : "тип листа" (A - внесенные владельцем, M - внесенные подписчиками, пусть - любой) ,"list" : [ -- отсутсвие параметра - дать всех "email-1" -- есть в А и М ,"email-2" -- нет ни в одном ,"email-3" -- есть в А ..... ] }
ответ
{ <общие поля> list : { "email-1" : { "A": 1 ,"M": 1 } ,"email-3" : { "A": 1 } } }
{ "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" : "всего затрачено смс" ,"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" : "заблокированых, так как приостановили получение писем" }, ,"tld" : { -- количество адресов по доменам первого уровня. для телефонов - кода стран (+7) "домен первого уровня" : "количество адресов" ,"домен первого уровня" : "количество адресов" ,"домен первого уровня" : "количество адресов" ............ }, ,"sld" : { -- количество адресов по доменам второго уровня. для телефонов - коды стран и следующие три цифры (например, +7921) "домен второго уровня" : "количество адресов" } ,"домен второго уровня" : "количество адресов" } ,"домен второго уровня" : "количество адресов" } ............ } }
Универсальная статистика позволяет получить информацию про переходы, открытия писем, тиражи выпусков и результаты доставки. Примеры использования вынесены в отдельный раздел.
При использовании кэширования запоминаются сами данные, а способ возврата результата задаваемый в "result" применяется к ним позже.
При использовании кэширования в режиме "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 - первый уточнитель (час) младше второго (год) -- -- допустимые функции агрегирования -- 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(*) без списка полей ] ,"order" : [ -- упорядочивание результата, не обязательно -- -- список полей и функций агрегирования -- -- префикc "-" задаёт сортировку по убыванию -- префикс "+" или его отсутвие - по возрастанию -- -- a,-b -- +b,-avg(z) -- -a,+b,-c -- +dt:YM,-c ] ,"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" должен или отсутствовать или быть равен "" } ......... ] ,"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] ........ ] }
Для полей типа дата возможно сравнение с текущим временем +/- сдвиг.
Для этого значение v записывается в виде
"сurrent +Y year +M month +D day +h hour +m minute +s second"
Все поля задающие сдвиг не обязательны, но их порядок от года к секунде должен соблюдаться.
К названию величины можно добавлять на конце "s"
Результат вычисления current всегда неявно приводится к точности поля заданой в "a"
Например, в условии
issue.dt:YM < current - 1 day
точность результата "current - 1 day" неявно преобразуется к YM.
Особенность Григорианского календаря такова, что просто так отнимать от даты месяца и года нельзя, так как в получившемся месяце может не быть такого дня.
Например, если сегодня 30е марта, то вычитание 1го месяца даст февраль, а 30е февраля было ранее только в 1712 году и следующий раз может быть, предположительно, в 3328 году.
Например, если сегодня 31 декабря, то вычитание 3х месяцев даст 31 сентября.
Например, если сегодня 29 февраля, то вычитание 1 года даст 29 февраля прошлого года, который явно не високосный.
По этому, при вычитании из current годов и/или месяцев
Строго формально всё ещё хуже - бывает 61я секунда в минуте (не так уж и редко, последние разы 31 декабря 2008 23:59:60 и 30 июня 2012 23:59:60) и 23 или 25 часов в сутках (при переходе на и с летнего времени час или выпадает или добавляется, и без указания временной зоны один час может или пропасть или встретиться дважды). Но это системой не учитывается.
Примеры простые:
сейчас
current
cейчас минус 1 час 3 минуты плюс 4 секунды
current -1 hour -3 minutes +4 second
сейчас минус 40 дней назад плюс 78 часов
current -40 days + 78 hours
выпуск состоялся в прошлом месяце (ниже есть пример считающийся быстрее)
issue.dt:YM == current - 1 month
выпуск состоялся в прошлом месяце и ранее (ниже есть пример считающийся быстрее)
issue.dt:YM <= current - 1 month
выпуск состоялся начиная с 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 3 - 1 и 2 сразу - не может получать письма или sms member.domain.* - информация о домене подписчика
Существует специальная особенность связанная с выборкой данных подписчика.
Пока вы используете в запросе поля id и email, вы получаете данные о всех подписчиках.
Как только в запросе появляется поле haslock, вы начинаете получать данные только о тех подписчиках, запись о которых до сих пор есть в вашей базе.
Это связано с тем, что информация о адресе подписчика и его номере хранится всегда, а информация о блокировке только при наличии записи о пользователе в вашей базе и она пропадает если вы его удаляете.
Пример когда проявится разница - запрос адресов участвовавших в выпуске ("select":["member.email"]) вернёт все адреса попавшие в выпуск, а такой же запрос с дополнительной выборкой текущего состояния блокировки ("select":["member.email", "member.haslock"]) вернёт только тех, кого вы ещё не удалили из своей базы.
Эту особенность можно использовать специально для отсечения тех кто из базы уже удалён. Фильтр member.haslock >= 0 выберет подписчиков с любым состоянием блокироваки, но приведёт к исключению из результатов тех кто уже удалён.
group.id - id группы group.gid - символический код группы group.name - название группы
issue.id - id выпуска issue.dt - дата выпуска (dt:Ys) issue.name - тема выпуска issue.members - число получателей выпуска issue.format - формат выпуска issue.size - размер выпуска. Для email - размер одного письма, для sms - количество потраченых смс. issue.deliv_ok - количество успешно доставленных писем issue.deliv_bad - количество писем с постоянной ошибкой доставки issue.clicked - количество кликов issue.u_clicked - количество уникальных кликов issue.readed - количество чтений issue.u_readed - количество уникальных чтений issue.unsubed - количество отписок из выпуска issue.group.* - информация о группе по которой был выпуск issue.draft.id - номер черновика использованного при выпуске (null) issue.sequence.id - номер последовательности вызвавшей выпуск (null) issue.variant.id - номер варианта сплит-тестирования для которого вышел выпуск (null)
link.id - id ссылки link.url - url ссылки link.linkgroup.* - информация о группе в которую входит ссылка
linkgroup.id - группы ссылок linkgroup.name - name группы ссылок
click.dt - дата и время клика (dt:Ys) click.ip - ip кликнувшего click.member.* - информация о кликнувшем подписчике click.domain.* - информация о домене кликнувшего подписчика click.issue.* - информация о выпуске из которого был клик click.link.id - id ссылки click.link.url - url ссылки click.linkgroup.id - группы ссылок click.linkgroup.name - name группы ссылок
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-центр сразу отверг сообщение
Вместо префикса deliv можно использвать префиксы
unsub.why - способ отписки - 1 - по ссылке отписаться или через наш сайт - 2 - нажав кнопку "Это спам" в своей почтовой системе - 3 - через жалобу в нашу службу поддержки unsub.member.* - информация об отписавшемся подписчике unsub.domain.* - информация о домене отписавшегося подписчика unsub.issue.* - информация о выпуске из которого отписались, если он известен (null)
Возможно одновременное использование следующих сочетаний полей в одном запросе
Специальные названия полей используются для функций 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 - блокировка подписчика
Cобытийные действия предназначены для автоматизации реакции системы в ответ на те или иные события происходящие с пользователем или вызванные его действиями.
Для задания автоматической реакции системы на те или иные действия/бездействия пользователя создайте "Последовательность" описывающую что ("Действия") в ответ на какие события ("Cобытия") в каком порядке ("Шаги","Варианты") должно происходить.
На каждом Шаге последовательности можно задать несколько сценариев развития событий создав несколько Вариантов описав какие События активируют какой вариант (один вариант могут активировать несколько разных действий) и задать какие Действия (одно или несколько) должны быть выполнены в каждом из вариантов.
Как простой частный случай с помощью событийных действий можно реализовать триггерные рассылки (автоответчики) - задайте на первом шаге условие начала последовательности и как действие - первое высылаемое письмо.
На следующий шагах задавайте интервал времени до высылки следующего письма и его высылку в действиях.
Для придания автоответчику интелектуальности можно, например, сочетать события "Клик" и "Прошло время" для выбора какое из писем высылать далее, действия "Изменить данные" что бы учитывать на какое из высланых писем пользователь среагировал, действия "Завершить последовательность" что бы прекратить высылать подписчику письма при отсутствии инетереса, действие "Перейти на другую последовательность" что бы сменить тематику в зависимости от его реакции.
В более сложных случаях можно организовать автоматические напоминания о забытых корзинах в интернет-магазинах, автоматическое изменение статуса покупателя в зависимости от числа покупок и даже квест-игры по электронной почте.
Каждое событие произошедшее в системе проверяется не подходит ли оно в какой-либо последовательности к её первому шагу или к текущему шагу уже находящегося на последовательности пользователя.
Проверка производится путём просмотра всех условий каждого из вариантов шага. Если в данном варианте шага событие подходит к одному из условий, то дальнейший поиск в данном шаге последовательности прекращается и выполняются все действия описанные в том варианте к которому подошло событие после чего пользователь переходит на следующий шаг последовательности.
Подходящее событие может быть проигнорировано если пользователь или последовательно находятся в состоянии паузы.
Подходящее событие может не вызвать начало прождения пользователем последовательности если этому мешают настройки разовости и закрытости последовательности.
Можно ли ещё раз начать прохождение последовательности, если она уже была пройдена или проходится в данный момент.
В данный момент не реализовано !
Можно ли одновременно проходить последовательность несколько раз и если можно, то при запуске нового прохождения прервать ли текущие
Новые участники не могут начать последовательность. Ни как не влияет на прождение последовательности уже имеющимися участниками.
Cобытия не учитываются и значит ни кто не продвигается по последовательности и не начинает её. Пропущенные события теряются.
Возобновление прохождения при увеличении количества шагов.
Участники, завершившие ранее прохождение последовательности путём дохождения до её последнего шага, автоматически возобновят её прохождение с шага, следующего за тем на котором они закончили.
Для одного участника возобновляется только одно, имеющее максимальный номер шага-окончиния, прохождение.
Не возобновляется участник и так проходящий последовательность в момент её удлиннения не смотря на параметр parrallel.
Наступает когда пользователь подтверждает регистрацию.
{ "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" : "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.membership" , "id" : "код последовательности" -- не обязательно , "member" : "адрес пользователя }
ответ
{ <общие поля> ,"list" : { "код последовательности" : [ -- список описаний шагов -- структура одно элемента описана в вызове sequence.member.list { ... } ,{ ... } .... ] ,"код последовательности" : [ -- список описаний шагов { ... } ,{ ... } .... ] ..... }
{ "action" : "sys.settings.get", "list" : [ ] -- коды настроек. Если пусто - все настройки }
ответ
{ <общие поля>, "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 ,"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" : количество дней после смены пароля после которых заставлять менять пароль опять
Список настроек которые можно и прочесть и поменять
"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.acesss, за исключением отсутствия варианта default" } "issue.dontsend.550" : 0|1 -- автоматически исключать из выпусков рассылок адреса у которых последняя ошибка smtp = 550 - неизвестный получатель
{ "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" : "текст сообщения" }
ответ
{ <общие поля> }
{ "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 - попадает" ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] }
Хотя бы одни ответ из списка есть в ответах подписчика
{ "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"] }
Для импортирования и рассылки через Экспресс-Выпуск доступны четыре формата описания адресов и их данных.
Данные задаваемые непосредственно в вызове указываются в параметре users.list
Внешние данные указываются ссылкой в параметре users.url
При выпуске почтовой рассылки адрес получателя задаётся ключём email объекта member.
При выпуске sms-рассылки номер получателя задаётся ключём cellphone объекта member.
Остальные данные не обязательны и могут быть любой структуры, что в сочетании с возможностью шаблонизатора организовывать циклы, получать списки ключей и значений объектов позволяет создавать очень сложные шаблоны.
При выпуске почтовой рассылки адрес получателя находится в колонке member.email.
При выпуске sms-рассылки номер получателя находится в колонке member.cellphone.
Остальные данные не обязательны, но при их наличии каждая колонка содержит только по одному значению для каждого адреса (не может быть массивом или объектом) и должна быть описана в caption.
Первый лист должен содержать в первой строке описание какой анкете и ответу соответствует данная колонка (в формате коданкеты.кодвопроса).
При импорте возможно задание этого соответствия в параметре caption вместо первой строки первого листа.
Одна ячейка может содержать только одно значение для каждого адреса (не может быть массивом или объектом).
Понимаются данных сжатые архиватором zip, хотя пользы от этого ни какой - xslx и так является zip-архивом и повторное сжатие нечего не даст.
Разделитель колонок - запятая или точка с запятой.
Содержимое ячейки может быть заключено в кавычки.
Символ используемый как разделитель должен экранироваться с помощью "\" если он часть значения.
Первая может содержать "#charset=кошка" для однозначного определения кодировки.
Следующая строка должна содержать описание какой анкете и ответу соответствует данная колонка (в формате коданкеты.кодвопроса).
При импорте возможно задание этого соответствия в параметре caption вместо строки.
Одна ячейка может содержать только одно значение для каждого адреса (не может быть массивом или объектом).
Понимаются данных сжатые архиватором zip.
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" : "memeber" ,"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" : "memeber.cellphone,info.firstname,info.title,info.meddlename\n+70000000000,Павел,Иванович,Уважаемый\n+70000000000,Алексей,Алексеевич,Глубоко уважаемый\n......"
При использовании возможностей связанных с загрузкой данных с указанных вами адресов, необходимо не забывать что получить данные с адресов вашей локальной вычислительной сети не есть возможно - они спрятаны от внешнего мира за вашим шлюзом.
К таким адресам относятся:
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.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) изменился способ возврата ошибок и предупреждений новый параметр cleangroup - очистить группу-список перед импортом 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 Форматирование