API, Betta 0.108 2013-09-20

Формат протокола

Вызов

Адрес для вызова

https://pro.subscribe.ru/api

Метод вызова

Метод вызова - 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 аналогичный структуры для того что бы сообщить о событиях помешавших выполнить вызов в какой-либо его части, но не позволяющих считать что вызов ошибочен.


{

 <общие поля>

."errors" => [
              {
               "id" : "код ошибки-1" 

              ,"explain" : "возможное более развёрнутое описание-1" 

              ,<возможно поля специфические для конкретного запроса-1>
              }
             ,{
               "id" : "код ошибки-2" 

              ,"explain" : "возможное более развёрнутое описание-2" 

              ,<возможно поля специфические для конкретного запроса-2>
              }

              ......

             ]
}

вверх

Специальный ответ "Перенаправление"

При наличии в ответе поля REDIRECT необходимо

Так же стоит иметь счётчик перенаправлений что бы избежать зацикливания

В данный момент ограничение максимальной глубина перенаправлений десятью
выглядит достаточным.


{
 <общие поля>

,"REDIRECT" : "/xxx/yyy" 

}

вверх

Специальный ответ "Смена пароля"

Получение ответа с ошибкой 'error/auth/failed' и уточнением 'force_change_password' означает,
что для продолжения работы данной комбинацией login/sublogin требуется сменить пароль.

Это может быть вызвано как автоматическими событиями (например истёк срок действия пароля),
так и прямой установкой такого требования через вызов user.set или sys.password.set

Для продолжения работы необходимо:


{
 <общие поля>

,"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-карт. Запрос.

Авторизация биометрических карт AGSES происходит в два этапа.

На этапе запроса вы получаете flicker-код, на этапе ответа сообщаете код полученный клиентом от своей карты
и, в случае успеха, в ответ получаете номер сессии.


{

 "action" : "login.agses.challenge" 

,"card" : номер карты, наличие лидирующих 0 не обязательно

}

ответ


{

 <общие поля>

,"flicker" : код фликера

,"hedgeid" : номер запроса

}

вверх

Авторизация AGSES-карт. Ответ.

Сессия, полученная в этом вызове точно такая же по своим свойствам как и сессия
от обычного вызова 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" : состояние запроса
                    -- -3 - отменён
                    -- -2 - закончился ошибкой
                    -- -1 - закончился успешно
                    --  0 - принят
                    --  1 - запущен
                    --  2 - начата обработка
                    --  3 - сортировка
                    --  4 - форматирование
                    --  5 - генерация отчёта
                    -- остальное - зависит от типа запроса

       ,"status.dt" : дата-время установки текущего состояния (YYYY-MM-DD hh:mm:ss)

       ,"error"  : код ошибки    -- не обязательно
                                 -- смысл зависит от типа запроса

   -- дополнительные параметры в зависимости от запроса и его состояния

      ,"param" : {

   -- === issue.send ===

                   ,"group.id" : код группы

                     -- характеристики выпуска, если они уже известны

                   ,"issue.id" : номер выпуска

                   ,"issue.dt" : время начала выпуска

                   ,"issue.size" : количество смсок или примерный размер письма в байтах

                   ,"issue.members" : количество получателей для которых уже сформированы письма

                   ,"issue.format" : "email" или "sms" 

                   -- в состоянии "начата обработка" примерная информация о достигнутом прогрессе

                   ,"eta" : {

                             "rest'        : примерное количество секунд до окончания

                            ,"perc"        : примерный процент обработки

                            ,"dt.finished" : примерное дата-время окончания

                            ,"dt.updated   : дата-время последнего обновления информации eta
                            }  

                   -- отчёт и статистика после завершения работы для Экспресс-Выпуска

                   ,"report_file" : "название файла" -- если были ошибки, то название файла с отчётом для вызова rfs.get

                   ,"statistic" : {
                                   "total"       : всего строк
                                  ,"taked"       : верных строк
                                  ,"erroneous"   : строк с ошибками
                                  ,"repeated"    : повторов адресов
                                  ,"only_unique" : 0|1 -- был ли выпуск запущен с запретом повторной
                                                       -- рассылки по дублирующимся адресам
                                  }

   -- === stat.uni ===

                    "report_file" : "название файла" -- пусто до окончания запроса
                                                     -- после окончания - название файла с отчётом для вызова rfs.get
                                                     -- или пусто если заказывалась высылка на почту
   -- === stat.activity ===
   -- === stat.issue    ===

                    "group.id" : "код группы" -- пусто если считалось без указания группы
                                              -- иначе код группы указанной для расчёта

                   ,"report_file" : "название файла" 

   -- === stat.group.portrait ===
   -- === stat.group.common   ===
   -- === member.list         ===

                    "group.id" : "код группы" -- пусто если считалось без указания группы
                                              -- иначе код группы указанной для расчёта

                   ,"report_file" : "название файла" 

                   ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе }

   -- === member.import ===

                    "group.id" : "код группы" -- пусто если при импорте не указывалась автосоздание новой
                                              -- или заполнение существующей группы иначе код автосозданой
                                              -- существующей группы

                   ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе }

                   -- отчёты и статистика после завершения работы

                   ,"report_file" : "название файла" -- файл в формате xlsx с отчётом в хранилище отчётов если были ошибки.
                                                     -- первые 1000 ошибок для просмотра человеком

                   ,"report_file.json" : "название файла" -- файл в формате json запакованый zip с отчётом в хранилище отчётов если были ошибки.
                                                          -- все ошибки в машиноразбираемом виде

                   ,"statistic" : {
                                   "inserted"    : добавлено новых адрес
                                  ,"updated"     : обновлено адресов
                                  ,"erroneous"   : строк с ошибками
                                  ,"unconfirmed" : новых адресов внесённых без подтверждения
                                  ,"repeated"    : повторов адресов
                                  }

   -- === member.list.count  ===
   -- === member.sendconfirm ===
   -- === member.update ===
   -- === member.delete ===

                    "group.id" : "код группы" -- пусто если считается без указания группы
                                              -- иначе код группы указанной для расчёта

                   ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе }

   -- === issue.split.create  === 

                    -- отслеживается не "создание" (как формально следует из названия)
                    -- а процесс формирования списка получателей и назначения им того или иного варианта
                    -- соответственно, трекер отслеживает тестирование в состояние "подготавливается к запуску" 

                    "split.id" : "код группы" -- номер сплит-тестирования

                   ,"eta" : { в состоянии "начата обработка" примерная информация о достигнутом прогрессе }

                  }
       }
}

вверх

Анкеты

Список анкет


{

 "action" : "anketa.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

             "system" : "системная, да, нет (1, 0)" -- системные анкеты не доступны для изменения

             ,"id" : "уникальный идентификатор" 

             ,"name" : "название",

            }

            ...

           ]

}

Чтение анкеты


{

 "action" : "anketa.get" 

,"id"     : код-анкеты

}

ответ


{

 <общие поля>

,"obj" : {

          "id" : код-анкеты,

          "param" : {

                     "name"     : название анкеты,

                     "system"   : анкета системная да/нет

                    },

          "order" : [ -- порядок вопросов

                     "код-вопроса3",

                     "код-вопроса8",

                     .....

                     "код-вопроса4" 

                    ]

          "quests" : { -- вопросы анкеты

             "код-вопроса" : {

                             "id" : код-вопроса,

                             "@"  : номер по порядку,

                             "name" : формулировка вопроса,

                             "type" : тип вопроса,

                             --  для типа "dt" 

                             "subtype" : под-тип вопроса
                                        --  yd  - Дата и время с точностью от года до дня
                                        --  yh  - Дата и время с точностью от года до часа
                                        --  ym  - Дата и время с точностью от года до минуты
                                        --  ys -  Дата и время с точностью от года до секунды

                             --  для типа "free" 

                             "width" : ширина поля в байтах для типа free

                             --  для типа "1m" или "nm" 

                             "answers" : { -- ответы вопроса

                                          "код ответа1" : "название ответа1",

                                          "код ответа2" : "название ответа2",

                                           .....

                                          "код ответа3" : "название ответа3",

                                         },

                             "order" : [ -- порядок ответов

                                        "код ответа3",

                                        "код ответа1",

                                        .....

                                        "код ответа2" 

                                       ],

                            },

             ............

         },

}

вверх

Удаление анкеты


{

    "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" : "идентификатор анкеты" 

    ,"name" : "название анкеты" 

    необязательный

    ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" 

    по умолчанию, считается "return_fresh_obj" : "0" 

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты

вверх

Добавления нового вопроса анкеты


{

   "action" : "anketa.quest.add" 

  ,"anketa.id" : "уникальный идентификатор анкеты вопроса" 

  ,"return_fresh_obj" : 0|1  -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию)

-- добавление одного вопроса

  ,obj : { -- описание вопроса

          "name" : "Текст вопроса" 

         ,"type" : "Тип вопроса" 
                 -- free - свободный ввод
                 -- dt   - дата и время
                 -- 1m   - выбор одного из списка
                 -- nm   - выбор нескольких из списк
                 -- int  - целое число

         -- параметры, определяемые типом вопроса:

         -- для type=free:

              ,"width" : "количество символов для свободного ввода, обязателен,  > 0" 

         -- для  type=dt:

              ,"dtsubtype" : "точность для даты и времени (yd, yh, ym, ys), обязателен" 

         -- для type=1m или nm (выбор из списка):

              ,"answers" : { -- ответы вопроса 

                            "код ответа 1" : "название ответа1" 

                           ,"код ответа 2" : "название ответа2" 

                           ..... 

                           ,"код ответа N" : "название ответаN" 

                          }

             ,"order" : [ -- порядок ответов

                           "код ответа 3" 

                          ,"код ответа 8" 

                          .....

                          ,"код ответа 4" 
                        ]

         -- необязательные для любого типа

         ,"id" : "уникальный идентификатор вопроса" 

        }

-- добавление нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все добавлены или все не добавлены

  ,obj : [
          { описание вопроса-1 }
         ,{ описание вопроса-2 }
         ,...............
         ]
}

ответ


{

  <общие поля>

 ,"obj" : { объект анкета как из ответа anketa.get } -- если "return_fresh_obj" : "1" 

-- в зависимости от вида параметра obj в вызове

 ,"id" : "id-добавленного вопроса" 

-- или

 ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове
          "id-добавленного вопроса-1" 
         ,"id-добавленного вопроса-2" 
         .......
         ]

}

вверх

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


{

   "action" : "anketa.quest.set" 

  ,"anketa.id" : "уникальный идентификатор анкеты вопроса" 

  ,"return_fresh_obj" : 0|1  -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию)

-- добавление одного вопроса

  ,"obj" : { -- описание вопроса

            "id" : "уникальный идентификатор вопроса" 

           ,"name" : "Текст вопроса" 

           -- параметры, определяемые типом вопроса:

           -- для type=free:

                ,"width" : "количество символов для свободного ввода, обязателен,  > 0" 

           -- для type=1m или nm:

                ,"answers" : { -- ответы вопроса 

                              "код ответа 1" : "название ответа 1" 

                             ,"код ответа 2" : "название ответа 2" 

                             ..... 

                             ,"код ответа N" : "название ответа N" 

                             }

               ,"order" : [ -- порядок ответов

                           "код ответа 3" 

                          ,"код ответа 8" 

                          .....

                          ,"код ответа 4" 
                          ]
        }

-- изменение нескольких вопросов. любая ошибка отменяет все изменения. вопросы буду или все изменены или все не изменены

  ,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" соответствующей анкеты

вверх

Удаление ответа вопроса анкеты

Для вопросов типа "1m" и "nm"


{

    "action" : "anketa.quest.response.delete" 

   ,"anketa.id" : "уникальный идентификатор анкеты вопроса" 

   ,"quest.id" : "уникальный идентификатор вопроса" 

   ,"id" : "уникальный идентификатор ответа" 

   необязательный

   ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" 

   по умолчанию, считается "return_fresh_obj" : "0" 

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты

вверх

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

Для вопросов типа "1m" и "nm"


{

    "action" : "anketa.quest.response.order" 

    ,"anketa.id" : "уникальный идентификатор анкеты вопроса" 

    ,"id" : "уникальный идентификатор вопроса" 

    ,"order" : [ -- новый порядок ответов

         "код-ответа3" 

        ,"код-ответа8" 

        .....

        ,"код-ответа4" 

]

    необязательный

    ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" 

    по умолчанию, считается "return_fresh_obj" : "0" 

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты

Подписчики

Проверка адресов

Вызов проверяет список адресов на синтаксическую верность, даёт нормализованый вариант написания и (если указано) на то, что про этот адрес думает первичный MX обслуживающий домен.

В ответе ключами списка являются адреса из исходного списка в неизменном виде. Номарлизованый вид доступен в параметре email.

Если проверка SMTP не указана, то в ответе не будет частей связаных с её результатами.

Стадии на которых проверка SMTP закончилась ошибкой (параметр status):

  resolver - определение MX

  nomxa    - у домена нет ни одной записи MX или А

  connref  - не удалось соединиться с MX

  banner   - ошибка в первичном банере

  helo     - ошибка в ответ на HELO

  mailfrom - ошибка в ответ на MAIL FROM

  rcptto   - ошибка в ответ на RCPT TO

Для принимания как работает SMTP и что значат все эти странные слова полезно изучить RFC 5321.


{

  "action" : "email.test" 

  "smtp.test" : "проверять доступность по smtp - 0|1" -- не обязательное поле

 ,"smtp.timeout" : "таймаут в секундах" -- не обязательное поле. по умолчанию 15.

 ,"list" :  [ -- список адресов для проверки

             " missing@CityCat.ru" 

            ,"     PRO@subscribe.ru   " 

            ,"123@test@test.ru  " 

            ......

            ]

}

ответ


{

    <общие поля>

   "list" : {

              " missing@CityCat.ru" : { "email" : "missing@citycat.ru" -- нормализованая форма адреса

                                       ,"syntax" : "ok" -- результат синтаксической проверки адреса

                                       ,"smtp"  : {

                                              "status"  : "rcptto" -- стадия возникновения ошибки

                                             ,"domain"  : "citycat.ru" -- домен для которого определялся первичный MX

                                             ,"mx"      : "smtp.citycat.ru" -- первичный MX используемый для теста

                                             ,"ip"      : "81.9.34.192" -- ip-адрес использованного MX

                                             ,"ptr"     : [             -- список имён соответствующих ip-адресу
                                                           "cat192.subscribe.ru" 
                                                          ]

                                             ,"code"    : "550" -- код SMTP-ошибки (000 - тайм-аут)

                                             ,"dsn"     : "5.1.1" -- DSN-код SMTP-ошибки (при наличии в ответе)

                                             ,"message" : "<missing@citycat.ru>... User unknown" 
                                                           -- текст SMTP-ошибки или ошибки DNS

                                                  }

                                       }
             ,"     PRO@subscribe.ru   " :  { "email" : "pro@subscribe.ru" 

                                             ,"syntax" : "ok" 

                                             ,"smtp" : {
                                                          "status" : "ok" 

                                                         ,"domain" : "subscribe.ru" 

                                                         ,"mx"     : "smtp.subscribe.ru" 

                                                         ,"ip"     : "81.9.34.192" 

                                                         ,"ptr"    : [
                                                                      "cat192.subscribe.ru" 
                                                                     ]
                                                       }

                                            }

             ,"123@test@test.ru  " :   { "email" : null

                                       ,"syntax" : "error/email/multydog" -- код ошибки

                                      }

         }

}

Получить ответы подписчика


{

  "action" : "member.get" 

 ,"email" : "адрес подписчика" 

}

ответ


{

    <общие поля>

-- ответы на вопросы анкет

  ,"obj" : { 

            -- ank   - код анкеты

            -- quest - код ответа

            -- val   - значение ответа или код ответа если вопрос с выбором из списка

            "ank1" : {

                       -- обычный вопрос

                       "quest" : "val" 

                       -- вопрос с множественным выбором

                      ,"quest" : [ "val", "val", "val"....]

                       -- вопрос с выбором одного из нескольких - всё равно массив

                      ,"quest" : [ "val" ]

                      }

          ,"ank2" : {

                      ..............

                     }

          -- псевдо-анкета описывающая участие в группах-списках

          ,"-group": { -- перечисляются кода только тех групп-списков, в которых адрес состоит

              "id1" : 1

             ,"id2" : 1

                .............

             ,"idN": 1

            }

          }

}

Cоздать подписчика / Установить ответы подписчика

При отсутствии адреса в базе он автоматически создаётся.


{

  "action" : "member.set" 

 ,"email" : "адрес подписчика" 

 ,"addr_type": "тип адреса подписчика (email | msisdn)" 

 ,"source" : "ip-адрес оригинального запроса" 
              -- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос

 ,"if_exists" : "error|update|overwrite" 
                 -- правило изменения ответов анкетных данных. не действует на псевдоанкету "-group" 
                 -- error     - при наличии адреса в базе возвращается ошибка
                 -- update    - если ответ на изменяемый вопрос уже есть то он остаётся неизменным
                 -- overwrite - ответ заменяется/создаётся в любом случае

  ,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)" 
                     -- используется только при внесении email-адресов
                     -- действует лимит внесения без подтверждения
                     -- подробнее описанный в вызове member.import

  ,"newbie.letter.confirm" : "номер шаблона информационного письма" 
                           -- высылается если новый адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения
                           -- если параметр пуст или отсутствует, то ничего выслано не будет
                           -- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm
                           -- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт
                           -- продолжит вносить уже с подтверждением и этот параметр будет использоваться 
                           -- при внесении номеров телефонов ни какие уведомления не высылаются

  ,"newbie.letter.no-confirm" : "номер шаблона информационного письма" 
                           -- высылается если новый адрес до этого отсутствовал в базе, и внесён с без необходимостью подтверждения
                           -- если параметр пуст или отсутствует, то ничего выслано не будет
                           -- при внесении номеров телефонов ни какие уведомления не высылаются
  ,"obj" : {

            -- управление анкетными данными подписчика

            -- ank   - код анкеты

            -- quest - код ответа

            -- val   - значение ответа или код ответа если вопрос с выбором из списка

            'ank1' : {

                       -- установка значения ответа обычного вопроса

                       'quest' :'val'

                       -- установка значения ответа у вопроса с множественным выбором

                      ,'quest' : [ 'val', 'val', 'val'....]

                       -- установка значения ответа у вопрос с выбором одного из нескольких - всё равно массив

                      ,'quest' : [ 'val' ]

                       -- удаление ответа

                      ,'quest' : null

                      }

          ,'ank2' : {

                      ..............

                     }

          -- управление членством в группах-списках с помощью псевдо-анкеты

          -- параметр 'if_exists' не влияет на эту анкету

          ,'-group': {

                  -- 0 - удалить из группы

                  -- 1 - добавить в группу

                  -- членство в неперечисленных группах не меняется

                  'id1' : "(0|1)" 

                  ,id2' : "(0|1)" 

                   .............

                  ,idN' : "(0|1)" 

                }

          }

-- необязательный

 ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" 

-- по умолчанию, считается "return_fresh_obj" : "0" 

}

ответ


{

 <общие поля>

,"newbie"  : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу

-- если "return_fresh_obj" : "1" 

 данные от запроса "member.get" соответствующего адреса

}

вверх

Подтвердить регистрацию


{

  "action" : "member.confirm" 

 ,"email" : "адрес подписчика" 

 ,'cookie' : "код подтверждения" 

}

ответ


{

 <общие поля>

 ,'error' : 'error/member/wrongcookie' - не верный код. отсутстви ошибки - подтверждение выполнено или не требовалось

}

вверх

Удалить подписчика

Адреса реально удаляются из базы !

Запрос с указанием списка по умолчанию синхронный.

Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.

Асинхронные запросы возвращают номер трекера для отслеживания.


{

  "action" : "member.delete" 

-- указание подписчиков одним из способов

 ,"email" : "адрес подписчика" 

или

 ,"list" : [

            "адрес подписчика" 

           ,"адрес подписчика" 

            ........

           ]

 ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный

или

 ,"group" : код группы участники которой будут удалены

 ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный

или

 ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip.

 ,"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
                   --  4 - заблокирован так как имеет фатальные ошибки доставки - не может получать письма или sms
                   --  прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указаных блокировок
                   --
                   -- формально этот параметр можно заменить дополнительными условиями в фильтре группы
                   -- но его использование позволяет 
                   --  * не меняя фильтра групп узнавать сколько в ней всего участников и сколько из них могут получать письма
                   --  * не создавая группы узнавать это же для всех свои адресов вообще
                   --  * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы

 ,"format" : "идентификатор формата вывода" 
             -- если формат вывода не используется, то выводится только адрес (member.email) или номер телефона (member.cellphone)

 ,"sort" : "коданкеты.кодвопроса" 
             -- сортировка по указаному полю (не важно будет оно в итоговых данных или нет)
             -- если параметр отсутствует или пуст, то выдача идёт в неком внутреннем порядке
             -- сортировка по произвольной анкете/полю может резко увеличить время выполнения запроса
             -- так как для его выполнения надо отсортировать всю выборку
             -- но сортировка по ниже перечисленным полям практически не влияет на скорость выполнения
             --   member.id
             --   member.email     - при выборке адресов (email)
             --   member.cellphone - при выборке телефонов (msisdn)
             --   member.domain    - сортировка по домену и внутри него по адресу
             --                    - при выборке телефонов эквивалентно просто member.cellphone

  ,"sort.order" : "asc|desc" -- направление сортировки asc - по возрастанию (по умолчанию), desc - по убыванию

  ,"result" : "response|email|save" 
               -- cпособ возврата результата: (по умолчанию - response) 
               -- response - сразу (в ответе), в этом случае вызов синхронен
               -- email    - выслать на почту, в этом случае вызов асинхронный и вместо результата возвращается track.id
               -- save     - сохранить на сервере, в этом случае вызов асинхронный и вместо результата возвращается track.id

---- дополнительные параметры запроса зависящие от result

-- для response

  ,"page" : "номер страницы" -- при отсутвии выдаётся всь список. должны быть указаны оба параметра или ни одного

  ,"pagesize": "размер страницы" 

-- email или save
  ,"result.format" : "csv|xlsx" -- формат файла с данными (необязательно, по умолчанию csv)

  ,"caption" :"id|name" 
              -- в первой строке выводить заголовок, содержащий для каждой колонки код анкеты и вопроса (id)
              -- или их названия (name)
              -- если параметр отсутствует или пуст, то такая строка не добавляется

-- email

 ,email : [ e@mail1 ,e@mail2 ... ]   -- адреса получателей списка подписчиков

--

}

ответ


{

    <общие поля>

-- для result = email или save

  ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*

-- для result = response

  ,order : [ -- описание порядка колонок выводимых результатов

              {

                anketa      : код анкеты

               ,anketa.name : название анкеты

               ,quest       : код вопроса

               ,quest.name  : названи вопроса

              }

             ....

           ]

   ,list : [ -- по одной записи для каждого адреса

              [ значения запрошеных полей в порядке указанном в параметре ответа order ]

             ,[ значения запрошеных полей в порядке указанном в параметре ответа order ]

             ,[ значения запрошеных полей в порядке указанном в параметре ответа order ]

             .....

           ]

}

вверх

Количество подписчиков

Расчёт быстр если ведётся по "всем", по группам-спискам, по группам-фильтрам состоящим из групп-списков.

Расчёт по группе-фильтру может быть долог - в зависимости от сложности фильтра и общего числа подписчиков.

По умолчанию вызов синхронный. Используйте sync = 0, что бы сделать его асинхронным.

Если ответ может быть получен из кэша и он там есть, то ответ будет сообщен сразу и асинхронный запрос не начнётся.


{

  "action" : "member.list.count" 

 ,"group" : "идентификатор группы" 
            -- задает фильтр по списку подписчиков группы
            -- если пусто или отсутствует, то подсчёт идёт по всем подписчикам

 ,"cache" : { параметры кэширования }

 ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный

}

ответ


{

  <общие поля>

-- для асинхронного запроса

,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*

-- для синхронного запроса

 ,"obj" : {
            "total" : всего подписчиков

           ,"active" : количество подписчиков которые могут участвовать в рассылках писем или смс

           ,"locked" : уникальное количество заблокированных - не могут быть в рассылке.

           -- подробности по причинам блокировок (у одного подписчика может быть больше одной блокировки)

           ,"locked.unsubscribed" : в том числе заблокированные так как отписались

           ,"locked.confirm" : в том числе заблокированные так как не подтвердили внесение в базу

           ,"locked.stoplist" : в том числе заблокированные так как находятся в стоп-листе

           ,"locked,hardbounced" : в том числе заблокированные так как имеют фатальные ошибки доставки

           -- при подсчёте по всем подписчикам, дополнительно появляются поля

           ,"total.email" : всего именно email

           ,"total.msisdn" : всего именно телефонов

           ,"active.email" : способных получать именно адреса

           ,"active.msisdn" : способных получать именно телефоны

           }

}

вверх

Внесение списка подписчиков

Вызов member.import.probe предназначет для проверки что думает система импорта о ваших входных данных.

В ответ будет сообщено как произошло авто-определение кодировки (сharset), разделителя столбцов, определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких анкет приписаны столбцы данных

Если вы знаете зарание ответы на эти вопросы, то можете сразу указать эти данные при вызове тогда выше указание будет иметь приоритет над авто-определением системы.

Вызов member.import реально импортирует данные, описаные выше параметры будет определены автоматически если их не указать сразу при вызове.

Вызов member.import асинхронный - получение положительного ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта - он может не состоятся из ошибок возникших позже. Следить за его исходом можно по возвращаемому номеру асинхронного запроса.

Обратите внимание: Все возможные проблемы (фатальные или нет - смотрите по cannot_import) связанные именно с импортом (настройки, данные) при вызове member.import.probe сообщаются только через параметр warnings. А параметр errors служит только для сообщения о проблемах вызова только с точки зрения API. При вызове же самого импорта, не фатальные ошибки остаются по прежнему в warnings, а фатальные переносятся в errors. Это может выглядеть не логично, но это так из-за назначения вызова member.import.probe - предупредить вас о возможных ошибках, а не выполнять само импортирование.


{

  "action" : "member.import" 

или 

  "action" : "member.import.probe" 

** данные импортирования

  ,"addr_type": "тип вносимых адресов подписчиков (email | msisdn)" 

и одни из источников данных:

   ,"users.list": адреса и данные для импортирования -- непосредственно в JSON или в СSV или XLSX
                                                     -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" 

или

   ,"users.url": "URL по которому находятся список адресов и данных для импортирования ftp:// или http(s)://" 
                  -- данные забираются в момент вызова

или

  ,"uid": "идентификатор уже загруженных данных" 
          -- возвращается после первого вызова member.import.probe, используется далее вместо cамих данных

** параметры (не обязательны)

  ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )",

  ,"separator": "разделитель символов ("," | ";" | "|" | "t")", -- t - табуляция

  ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )",

  ,"caption":  [ -- по порядку следования столбцов в данных. приписывают каждый столбец одному вопросу одной анкеты

                -- при addr_type = email  колонка с адресом это анкета member вопрос email

                -- при addr_type = msisdn колонка с номером телефона это анкета member вопрос cellphone

                {

                 "anketa": "id  анкеты",

                 "quest": "id вопроса в анкете",

                  или 

                 "ignore": "1" -- игнорировать столбец

                 },

                ......

              ]

** пробный импорт

  ,"action": "member.import.probe",

** импорт

  ,"action": "member.import",

  ,"if_exists": "overwrite|ignore|error" -- обязателен
                -- что делать если адрес уже существует 
                -- overwrite - перезаписывать данные
                -- ignore    - не вносить
                -- error     - не вносить и считать строку ошибочной

  ,"newbie.confirm" : "подписчик должен подтвердить внесение в базу (1|0)",

                      -- по умолчанию - внесение без необходимости подтверждения подписчиком (0)

                      -- внесение email без подтверждения ограничено величиной member.noconfirm.rest
                      -- (узнать можно через sys.settings.get) при её исчерпании остальные адреса
                      -- вносятся с подтверждением.

                      -- если количество адресов в базе превышает member.tarif.limit, то величина member.noconfirm.rest
                      -- равна нулю, иначе она равна member.noconfirm.limit за вычетом количества уникальных email
                      -- адресов внесённых в текущем месяце

                      -- на внесение номеров телефонов параметр newbie.confirm не влияет (они всегда вносятся без подтверждения)

  ,"newbie.letter.confirm" : "номер шаблона информационного письма" 
                           -- высылается если новый адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения
                           -- если параметр пуст или отсутствует, то ничего выслано не будет
                           -- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm
                           -- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт
                           -- продолжит вносить уже с подтверждением и этот параметр будет использоваться 
                           -- при внесении номеров телефонов ни какие уведомления не высылаются

  ,"auto_group" : {
                  -- автоматически создать группу-список для импортируемых адресов
                  -- или дополнить любую существующую группу-список импортируемыми адресами

                  -- отсутствие всего параметра auto_group означает ни создавать новую ни пополнять существующую группу
                  -- наличие auto_group но без id и без name означает создание группы со стандартным кодом
                  -- и со стандартным названием. код созданый группы можно узнать используя возвращаемый номер track.id
                  -- и вызов track.get

                  "id" : "идентификатор группы-списка для пополнения" 
                         -- при отсутствии такой группы она создаётся автоматически
                         -- если параметр пуст или отсутствует то используется стандартный
                         -- код вида importYYYYYMMDDhhmmss

                 ,"name" : "название группы" 
                            -- название для создаваемой группы.
                            -- если параметр пуст или отсутвует то используется стандартное "Внесены <дата-время импорта>" 

                 }, 

   ,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список указанную в auto_group перед началом импортирования
                      -- позволяет не дополнять группу, а полностью заменять её участников
                      --
                      -- сначал проверяются все возможные причины по которым импорт может не начаться. если они есть, то импорт заканчивается ошибкой и очистка не происходит
                      -- иначе импорт начинается с очистки списка участников, а внесение новых происходит только после этого
                      --
                      -- не путайте удаление адреса из списка участников с удалением адреса из базы - это разные вещи
                      --
                      -- при одновременном импортировании в одну группу несколькими вызовами у которых хоть у одного clean_group=1 результат
                      -- зависит от порядка выполнения и может быть неожиданным. для однозначного результата всегда выполняйте импорт с cleangroup=1
                      -- только по завершении всех предыдущих импортов в ту же самую группу и не запускайте новый импорт в такую группу до завершения текущего.

   ,"format" : " id-формата" -- дополнить данные каждого вносимого адреса данным из формата
                             -- отсутствие или пусто - не дополнять

   ,"sequence.event" : 0|1 -- будет ли внесение/изменение данных вызывать срабатывание событийных действий
                           -- отсутствие или пусто - вызова событий не будет
   ,"result": [
               -- один или несколько адресов для высылки отчёта с результатами импорта
               -- обратите внимание на обязательность mailto:

               "mailto:your@email.tld" 
               ,.....
              ]
}

ответ


{

   <общие поля>

-- только для member.import.probe

  ,"uid": "идентификатор уже загруженных данных" 

  ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )" 

  ,"separator": "разделитель символов ("," | ";" | "|" | "t")" 

  ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )" 

  ,"caption":  [ -- поля конфигурации

                {

               -- для колонки которой найдено соответствие анкете/вопросу

                 "name": "отображаемое имя колонки",

                 "anketa": "id  анкеты",

                 "quest": "id вопроса в анкете",

               -- для колонки которой не найдено соответствие

                 "name": "неопределенное начение из элемента строки конфигурации или null",

               -- для колонки для которой конфигурации задано игнорирование

                  "ignore" : 1

                 }

              ]

  ,"rows" : [ -- данные первых 15 значащих строк разбитые по полям с учёном указанного разделителя

             [ "колонка-1-строки-1" ,"колонка-2-строки-1" ,"колонка-3-строки-1" ]

            ,[ "колонка-1-строки-2" ,"колонка-2-строки-2" ,"колонка-3-строки-3"]

            .......

           ]

  ,"cannot_import" : 0|1  -- может ли быть выполнен импорт с текущими параметрами запроса
                         -- 1 - может
                         -- 0 - нет

                         -- Именно этот параметр, а не описанный далее параметр warnings сигнализирует о возможности/невозможности импорта,
                         -- т.к. параметр warnings может содержать и не влияющие на запуск процесса импорта предупреждения - например о том,
                         -- что в первых строках файла есть неверно указанные адреса подписчиков, что не говорит о том, что во всем
                         -- списке подписчиков будет так.

   ,"warnings" : [ -- предупреждения о проблемах при анализе данных
                   -- в первую очередь проверяйте параметр cannot_import
                   -- если он показывает, что импорт невозможен, то тут содержится описание почему

                   -- кроме этого, предупреждения могут показывать на проблемы с первыми адресами списка
                   -- импорта, что не препятствует самому импорту.

                  { "id":"код ошибки", "explain": "доп. информация (скаляр, массив или хэш)" }

                  ....

                ]

-- только для member.import

  ,"queue_position" : "номер в очереди импортирования" 

  ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*

}

вверх

Пригласить подписчиков

Запрос с указанием списка по умолчанию синхронный.

Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1 если вам реально нужен ответ с описанием какие адреса как были обработаны.

Асинхронные запросы возвращают номер трекера для отслеживания.


{

 "action" : "member.sendconfirm" 

 ,"letter" : "код информационного письма" -- обязательно

-- указание подписчиков одним из способов

 ,"email" : "адрес подписчика" 

или

 ,"list" : [

            "адрес подписчика" 

           ,"адрес подписчика" 

            ........

           ]

 ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный

или

 ,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации

 ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный

или

 ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip.

 ,"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 - асинхронный

или

 ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip.

 ,"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 используемый в вызовах это абсолютный путь по хранилищу начинающийся со слэша.

Cписок файлов

Если 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" : "полный путь с названием файла" 

}

ответ


{

 <общие поля>

} 

вверх

Cоздать каталог

Только для 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": "Имя отправителя", -- по умолчанию название аккаунта
                                    -- для SMS имя отправителя должно быть в списке уже промодерированных имён (вызовы issue.smssender.*)

    "from.email": "Адрес отправителя (email)",  -- игнорируется для SMS, по умолчанию базовый адрес аккаунта

    "subject": "Тема письма", -- игнорируется для SMS

    "message": {

                -- для выпуска по email-адресам одна или обе версии письма

                'html' : 'html-версия письма'

               ,'text' : 'текстовая версия письма'

                -- для выпуска по SMS

                'sms'  : 'sms cообщение'

               }

или черновик из которого их взять. при указании черновика другие параметры содержимого игнорируются

    "draft.id": "номер черновика содержимое которого даст выпуск", -- тип черновика определит вид и формат рассылки (email или sms)

* параметры способа выпуска. Тестовый выпуск не доступен для Экспресс-Выпуска, Транзакционных писем и 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",

             ......

           ]

* параметры преобразования ссылок для учёта перехода по ним (игнорируются для SMS)

    "relink" : 0|1 -- Преобразовывать ссылки автоматически
                   -- 1 - да, 0 - нет

    "relink.param" : {

                      "link" : 0|1 -- преобразовывать ссылки тега <A>
                                   -- 1 - да, 0 - нет

                      "image": 0|1 -- преобразовывать ссылка на внешние картинки для тега <IMG>
                                   -- и фоновых изображений в <BODY> и <TABLE>
                                   -- 1 - да, 0 - нет

                      "test": 0|1 -- проверять существование адресов
                                  -- при включённой проверке выпуск не выйдет если ссылка
                                  -- не действительна (ответ не 200, не 301 и не 302)
                                  -- 1 - да, 0 - нет
                     }

если relink = 1 и relink.param не указаны, то считается что: link=1, image=0, test=1

    "link.qsid": "Параметр для отслеживания переходов по ссылкам" 
                  -- добавляется ко всем ссылкам через query-string.
                  -- значение должно быть уже url-encoded

* параметр прикрепления файлов. тип файла определяется по расширению. (игнорируется для SMS)

    "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
                                                      -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" 
                                                      -- при указании только адреса данные персонализации берутся из базы
                                                      -- при нескольких адресах используется только первый

* ограничение на частоту и время отправки. только для sms
  --
  -- все ограничения касаются только первой попытки отправки сообщения в sms-центр.
  -- если sms-центр не принял сообщение сразу или принял, но внутри себя
  -- по какой-то причине не пытался доставить сразу, то ограничения могут не быть соблюдены.

  -- допустимы временные зоны относительно GMT от -23 до +23 и default. знаки "+" и "-" обязательны.

  -- временная зона телефонного номера сотовой связи определяется по базе Федерального Агентства Связи.

 ,"tz_limit" {

   "default" : { -- настройки по умолчанию для не описанных зон или отсутствующих описаний с описанной зоне

      -- ограничение на частоту отправки сообщений
      -- за rate минут будет передано в доставку в sms-центр не более number сообщений
      --
      -- если параметр отсутствует или пуст или обе величины равны 0,
      -- то ограничения нет

      "batch" : { -- или отсутствуют или указаны оба значения
                 "number" : "сколько cообщений" -- обязательно, >= 0
                ,"rate" : "за сколько минут"    -- обязательно, >= 0
                }

      -- ограничение по времени отправки
      -- *все даты и часы по местному времени временной зоны !!!*

     ,"time" : {
                 "dt" : "YYYY-MM-DD" -- отправка начнётся не ранее указанного дня.
                                     -- если не указано или пусто или в прошлом,
                                     -- то используется текущая даты зоны MSK/MSD

                ,"hour" : [ час, час, час, ... ] -- разрешённые часы местного времени (0-23) в которые будет осуществлять отправка 
                                                 -- если не указано или пусто, то разрешены часы с 9 по 21
                                                 -- подумайте, стоит ли расширять этот диапазон на утреннее и ночное время !
                                                 --
                                                 -- порядок следования часов важен для первого дня отправки !
                                                 -- запись
                                                 --        {
                                                 --         "dt"   : "2012-09-17" 
                                                 --        ,"hour" : [ 20, 21, 22, 23, 06 08 07 ]
                                                 --        }
                                                 -- задаёт разрешённые часы с 6, 7, 8, 20, 22 и 23 и начало рассылки 17го декабря
                                                 -- но именно 17го она начнётся не в 6 часов, а в 20, так как 20 указано первым
                                                 -- а 18го и далее - начиная с 6
                                                 --
                                                 -- разрешается весь час - последняя отправка в нём может быть
                                                 -- даже в 59 минут 59 секунд, что может выглядеть как уже "не разрешённый" час
                                                 -- т.к. сообщение будет доставлено уже явно в следующем часе.
                }

   }

  ,"+4" : { -- ограничение для временной зоны GMT+4

       -- полностью отсутствующий или пустой компонент берётся из default

      "batch" : { .... } -- используйте 0 для rate и number что-бы снять ограничение из default

     ,"time"  : { .... } -- *дата и часы по местному времени временной зоны !!!*
                         --
                         -- если задано только dt, то действуют стандартные разрешённые часы с 9 по 21
                         -- подумайте, стоит ли расширять этот диапазон на утреннее и ночное время !
                         --
                         -- если задано только time, то то используется текущая даты зоны MSK/MSD
                         --
                         -- если не задано ни dt ни time, то действуют ограничения из default

   }

  ,"-2" : { -- ограничение для зоны GMT-2
    ..........
  }

  ..........

 }

* данные произвольной структуры одинаковые для всех подписчиков
 --
 -- эти данные будут доступны для шаблонизатора выпуска как переменные с именем совпадающим с именем ключа хэша

 -- в настоящий момент зарезервированы имена:
 --   anketa - данные о конкретном подписчике
 --   lenta  - данные для подстановки rss/atom каналов
 --   date   - интерфейс к функциям работы с датой и временем
 --   form   - форма опроса

 -- во избежание пересечений с новыми стандартными именами рекомендуется
 -- свои имена начинать с большой буквы

,"extra" : {
            "Key1" : [ 12, 34 ,56 ] -- пример использования [% Key1[2] %]

           ,"City" : { -- пример использования [% City.rus.long %]
                      "rus" : {
                               "long"  : "Санкт-Петербург" 
                              ,"short" : "СПБ" 
                     ,"eng" : {
                               "long"  : "Leningrad" 
                              ,"short" : "LED" 
                     }

           }

}

ответ

{

    <общие поля>

   ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.*

}

Список отложенных выпусков


{

  "action" : "issue.later.list",

 ,"from" : "YYYY-MM-DD" -- от даты (не обязательно)

 ,"upto" : "YYYY-MM-DD" -- до даты (не обязательно)

 ,"group" : [ -- фильтр по группам (не обязательно)

               код-группы-1

              ,код-группы-2

               ... 

             ] 

 ,"format" :  "email|sms|html|text"  -- фильтр по формату (не обязательно).
                                      -- email это "html или text" 
}

ответ


{

  <общие поля>

 ,"list" :  [

              {

                 "id" : "код выпуска" 

                ,"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" : "код выпуска" 

}

ответ


{

  <общие поля>

}

Список имён sms-отправителей

{

  "action" : "issue.smssender.list" 

}

ответ

{

 <общие поля>

,"list" : [

            {

             "id" : "уникальный идентификатор" 

            ,"name" : "отправитель" 

            ,"onmoderation" : 0|1 -- 0 - имя одобрено, 1 - имя ещё на модерации
            }

            ...

           ]

}

Чтение имени sms-отправителя

{

  "action" : "issue.smssender.get" 

  ,"id" : "идентификатор sms-отправителя" 

}

ответ

{
  <общие поля>

  "obj" : {

       "id" : "идентификатор sms-отправителя" 

      ,"name" : "отправитель" 

      ,"onmoderation" : 0|1

          }

}

Создание или изменение имени sms-отправителя

Создание или изменённо имя автоматически попадает на модерацию

Если имя состоит из одних только цифр, то его длина не должна превышать 15 символов.

Иначе имя может содержать от 1 до 13 символов больших и маленьких латинских букв и цифр.

{
  "action" : "issue.smssender.set" 

  ,"obj" : {

       "name" : "отправитель" 

           }

 необязательные

  ,"id" : "идентификатор sms-отправителя" -- если не указан, создается новый

  ,"return_fresh_obj": "" -- вернуть объект в формате issue.smssender.get

}

ответ

{

 <общие поля>

 ,obj  { ... } -- объект в формате issue.smssender.get при наличии в запросе параметра "return_fresh_obj" 

}

Удаление имени sms-отправителя

{

  "action" : "issue.smssender.delete" 

  ,"id" : "идентификатор sms-отправителя" 

}

ответ

{

 <общие поля>

}

Динамический контент

Описание

Динамический контент позволяет вам задавать содержимое части выпуска или всего выпуска как текст забираемый готовым со страницы какого-либо сайта или собираемый на основе новостей из различных видов источников с помощью Лент Новостей.

Во всех ссылках поддерживается авторизация HTTP-Basic - укажите её обычным образов в самой ссылке.

Во всём содержимом подставляемым в текст письма с помощью динамического контента работает шаблонизатор - подставляемы части могут содержать любые его команды.

Готовые страницы сайта

"Готовая страница сайта" это доступная веб-страница любого сайта.

При использовании в выпуске рассылки команды шаблонизатора [% wget(url) %] указаная страница забирается с сайта в момент выпуска рассылки и подставляется в текст письма.

От страницы используется только содержимое между тегами <body></body>.

На странице можно дополнительно расставить метки фильтрации позволяющие указать только определённyю часть/части которую надо использовать в выпуске.

Такие части отмечаются в своём начале добавлением строки начинающейся с <!-- issueBegin --> и в конце добавлением строки начинающейся с <!-- issueEnd -->

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

Лента Новостей

"Лента новостей" это набор от одного до бесконечности каналов новостей, сообщения из которых собираются и могут быть использованы для формирования индивидуальных писем или общих рассылок.

Один источник новостей может входить в несколько лент - фактически он опрашивается один раз в 1-2 часа и все найденные свежие новости собираются в базу и становятся независимо доступны во всех лента и использование определенной новости в одной из них никак не повлияет на ее состояние в другой ленте.

Одна и та же лента может использоваться в выпуске несколько раз. Например первый раз для формирования "меню" из списка заголовков новостей, а второй для вывода полной новости.

В выпуске может быть использовано несколько лент.

Лента хранит отметку времени последнего использования в рассылке и основываясь на нём система включает в письма только те новости, которые были получены после этой даты.

После формирования рассылки (или индивидуального письма) отметка времени у всех использованных в рассылке лент устанавливается в текущее время. Таким образом новости одной ленты уже использованные в рассылке повторно использованы не будут.

Старые новости регулярно удаляются из базы как только проходит 15 дней с момента получения новости.

Использование лент новостей в Индивидуальных письмах

Индивидуальные письма подписчикам формируются из новостей накопившихся в их личных лентах которые к подписчикам привязаны владельцем ПРО при их создании (lenta.set).

Письмо формируется по указанному в ленте расписанию с оформлением по указанному шаблону выпуска с использованием новостей накопившихся с прошлой рассылки.

Если свежих новостей нет, то письмо не высылается.

Это позволяет организовать индивидуальное оповещение клиентов персонализированными подборками информации. Например, организовать на сайт подписку на результаты поиска по каталогу товаром - пользователи будут автоматически получать обновления в интересующих их разделах.

Предоставляются простые базовые шаблоны которые можно модифицировать на свой вкус. Они доступны по адресу https://pro.subscribe.ru/resources/help/lenta/drafts.html

Использование лент новостей в рассылках

Для использовании в рассылке новостей одной или нескольких лент надо воспользоваться функциям шаблонизатора news() или lenta().

Функция news() не требует специальной обработки и результатом её работы становится содержимо полей "content" всех свежих новостей. Это упрощает работу с лентами если готового источника у вас ещё нет и вы можете легко формировать его как нравится. Или когда имеющийся источник выдаёт в "content" новости то, что надо для выпуска.

Функция lenta() только присваивает переменной lenta специальную структуру данных описывающую все свежие на данный момент новости и их источники. Для их отображение требуется использование в теле письма оператора [% FOREACH %] для обработки каждой новости. Это сложнее, но вы можете оформить вывод новостей самым гибким образом.

Обе функции могут работать как с заранее созданной лентой новостей (указывается её номер), так и напрямую с каналом новостей (указывается его url).

При указании url механизм исключения уже использованных новостей не применим и в выпуск всегда попадают все новости канала имеющиеся в нём на момент выпуска.

Если свежих новостей нет ни в одной используемой в шаблоне ленте и новостей нет вообще ни в одном используемом в шаблоне источнике указанным напрямую, то выпуск рассылки не высылается.

По умолчанию новости отсортированы в порядке убывания и даты публикации. Задать свой порядок и группировку по источникам можно с помощью щаблонизатора - рассмотрите пример "Новости по источникам" по адресу https://pro.subscribe.ru/resources/help/lenta/drafts.html

Базовые шаблоны от индивидуальных писем применимы и тут - как отправная точка для кастомизации под ваши нужды.

Доступные источники новостей для лент новостей

Структура переменной lenta

Структура данных ленты в индивидуальных письмах и после вызовов lenta() и news() содержит информаци о ленте новостей, всех источниках новостей новости которых попали в ленту и содержимое всех свежих новостей.

Лента новостей

"lenta" : {
       "id" : "id ленты в базе" 

      ,"name" : "название ленты" 

      -- описания всех источников ленты, чьи новости попали в письмо
      ,"sources" : {
                    "id-источника" : { описание источника }
                   ,"id-источника" : { описание источника }
                   ......
                   }

      -- id источников упорядоченные так же как упорядочены новости
      ,"sources_order" : [ "id-источника", "id-источника" .........]

      -- описание новостей в заказаном порядке (по умолчанию по убыванию даты публикации новости)
      ,"news" : [
                 { описание новости }
                ,{ описание новости }
                ,{ описание новости }
                ]

}

Описание одного источника

{
 "id" : "id источника в базе" 

 -- индексы в lenta.news[] новостей именно этого источника в порядке совпадающем с порядком lenta.news[]
,"news' => [ индекс, индекс, индекс ....]

 -- параметры источника как получены из описания RSS/Atom-канала при его последнем анализе
 -- названия параметров совпадают с названиями тегов XML

,"title" : "название источника" 

,"descr" : "описание источника" 

,"link" : "ссылка на обычную версию источника" 

,"logo" : "ссылка на логотип источника" 

,"author" : "информация об авторе" 

,"copyright" : "информация об авторских правах" 

}

Описание одной новости

{
 "ID" : "id новости в базе" 

,"source" : "id в базе источника из которого получена новость. ключ в lenta.sources{}" 

,"n" : "номер по порядку в lenta.news[]" 

 -- параметры новости как получены из описания RSS/Atom-канала при его последнем анализе
 -- названия параметров в основном совпадают с названиями тегов XML

,"title" : "название источника",

,"content" : "содежимое новости" -- тег <description> или <yandex:full-text>

,"link" : "ссылка на обычную версию новости" -- тег <link>, если пусто и isPermaLink="true" и guid похож на урл, то guid

,"dt" : "YYYY-MM-DD hh:mm:ss" -- дата публикации новости (тег <pubDate> или <dc:creator>)

,"id" : "идентификатор новости" -- тег <guid>

,"author" : "информация об авторе новости" 

,"category" : { -- категории новости
               "домен" : {
                          "категория" : "метка" 
                         ,....
                         }
              ,...
              }

,"enclosure" : [ -- приложения к новости на основании тегов <enclosure> и <media:thumbnail>
                 -- обычно так указывают картинки и звуковые файлы
                {
                 "url" : "ссылка" 
                ,"type" : "mime-type" 
                ,"length" : "длина" 
                }
               ,....
               ]

 -- дополнительные параметры полученые из dt

,"ymd" => "YYYY-MM-DD" 

,"hm" => "hh:mm" 

}

Список лент

{
 "action" : "lenta.list" 
}

ответ

{
 "list" : [
            {
             "id" : номер ленты
            ,"name" : название ленты

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

            ,"member" : "получатель" 
            }

           ...........

          ]
}

Прочитать ленту

{
 "action" : "lenta.get" 

."id" : номер ленты
}

ответ

{
 "obj" : {
          "id" : номер ленты

         ,"name" : название ленты

         ,"source" : [ -- информация об RSS/Atom каналах входящих в ленту

                       {
                        "url" => "адрес канала" 
                       ,"dt.fetched" => "YYYY-MM-DD hh:mm:ss" -- дата последнего чтения канала
                       ,"dt.updated" => "YYYY-MM-DD hh:mm:ss" -- дата последнего пополнения новостей из канала
                       ,"error" : {
                                   'count': количество ошибок работы с каналом
                                  ,'dt'   : "YYYY-MM-DD hh:mm:ss" - дата последней ошибки
                                  ,'str'  : описание послденей ошибки
                                  }

                       }
                       ...
                     ]          

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

         ,"member" : "адрес получателя" 

         ,"decor"  : "черновик" -- номер черновика выпуска рассылки который будет использоваться
                                -- при выпуске накопившихся новостей

         -- расписание выпусков
         ,"schedule" : {
                        -- часы по которым высылать письма
                        'hour' : [ час, час, ... ]

                        -- номера дней недели по которым высылать письма
                        -- от 1 (Пн) до 7 (Вс)
                       ,'weekday' : [ номер, номер, ... ]
                       }
         }
}

Создать/изменить ленту

Создает ленту (при отсутствии id) или изменяет некоторые её параметры.

{
 "action" : "lenta.set" 

 ,"obj" : {

       "name" : "название ленты" 

      ,"member" : "адрес получателя" -- только при создании. измененить нельзя

-- для лент привязаных к получателю

      ,"decor"  : "черновик" 

      -- расписание выпусков
      -- если параметр полностью отсутствует, то с 8 по 18 с понедельника по пятницу
      ,"schedule" : {
                     -- часы по которым высылать письма. если не указано, то с 8 по 18
                     'hour' : [ час, час, ... ]

                     -- номера дней недели по которым высылать письма, если не указано, то с Пн по Пт
                     -- от 1 (Пн) до 7 (Вс)
                    ,'weekday' : [ номер, номер, ... ]
                    }

   }

-- необязательные

 ,"id" : номер ленты

 ,"return_fresh_obj": "" -- вернуть объект в формате issue.draft.get

}

ответ

{

 <общие поля>

 ,obj  { ... } -- объект в формате lenta.get при наличии в запросе параметра "return_fresh_obj" 

}

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

{

  "action" : "lenta.delete" 

  ,"id" : номер ленты

}

ответ

{

 <общие поля>

}

Добавление источника в ленту

{

  "action" : "lenta.source.add" 

  ,"lenta.id" : номер ленты

  ,"url" : "адрес источника добавляемого в ленту" 

}

ответ

{

 <общие поля>

}

Удаление источника из ленты

{

  "action" : "lenta.source.delete" 

  ,"lenta.id" : номер ленты

  ,"url" : "адрес источника удаляемого из ленты" 

}

ответ

{

 <общие поля>

}

Обновление источника

Указаный источник опрашивается вне расписания в поиске свежих новостей.

Если с момента прошлой провеки (плановой и этим вызовом) прошло меньше 15 минут, то опрос произведён не будет и количество свежих новостей будет возвращено как -1.

{

  "action" : "lenta.source.refresh" 

 ,"url" : "адрес обновляемого источника" 

}

ответ

{

 <общие поля>

,"news" : "количество найденех свежих новостей" 

}

Тестовый выпуск ленты

Вызов отправляет тестовое письмо с указанным количеством последних новостей ленты на указанный адрес (а не на адрес для которого создана лента).

В отличии от реального выпуска, отосланные новости не отмечаются как использованные и будут в итоге высланы подписчику.

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

Вызов предназначен только для тестирования шаблона оформления указанной ленты, чему помогает возможность явно указать нужное количество новостей, а не ждать пока свежие новости появятся в ленте.

Если в итоге новостей нет, то письмо не отправляется

{
 "action" : "lenta.send" 

."id" : номер ленты

,"email" : адрес для отсылки тестового письма

,"n" : количество последних новостей для теста
       -- если не указано, то используются все ещё не отосланные новости (их может не быть)
}

ответ

{
 "news" : "количество новостей попавших в письмо" 

 < параметры ответа issue.send если письмо было выслано >
}

Сплит-тестирование

Описание

Сплит-тестирование (A/B-тестирование) позволяет выпустить по некоторой части выбранной аудитории несколько писем различающихся между собой чем-либо и по результатам (если охват не 100%) выбрать в ручную или автоматически "лучший" вариант и послать его оставшейся не охваченной части аудитории.

Традиционный вариант использования - A/B-тестирование - предусматривает только два тестовых варинта писем и выпуск победителя.

Но данная реализация позволяет иметь произвольное количество тестовых вариантов и при желании не выпускать победителя, а покрыть тестами сразу всю аудиторию.

Параметры тестирования

Параметры одного варианта письма

Правила работы

Тестирование начинается автоматически не ранее даты указанной для запуска самого раннего варианта и если вариантов к этому моменту не менее двух.

Дата запуска какого-либо тестового выпуска или выпуска-победителя может быть пропущена если тестирование в приостановленном состоянии или не хватает вариантов.

Пропущенные запуски будут выполнены как только тестирование будет переведено в активное состояние или добавлен недостающий вариант.

В любом случае запуск победителя возможен только после выпуска всех тестовых частей даже если это потребует пропуска назначенного времени.

Список участников тестирования определяется как все участники указанной группы и формируется в момент или перед запуском первого варианта. В дальнейшем список неизменен вне зависимости от изменения списка участников группы за исключением адресов удаливших себя или внесённых в стоп-лист.

На время формирования списка тестирование находится в состоянии "подготавливается к запуску" и прогресс формирования может быть отслежен через вызов track.get

Данные персонализации каждого участника берутся на момент выпуска варианта.

Каждому варианту писем достанется процент аудитории равный Процент тестового охвата / Количество вариантов. Варианту победителю при повторном выпуске достанется оставшаяся часть аудитории.

Если участников меньше количества вариантов (при охвате 100%) или меньше количества вариантов + 1 (при охвате не 100%), то тестирование при запуске сразу перейдёт в состояние "завершено". Другими словами - каждому варианту и победителю должен достаться хотя бы один получатель.

Если процент тестового охвата равен 100, то выпуска-победителя не предусматривается.

Если тестирование НЕ в состоянии "ожидает запуска" то менять процент и группу уже нельзя.

Если тестирование НЕ в состоянии "ожидает запуска" то добавлять или удалять варианты писем уже нельзя.

Если тестирование НЕ в состоянии "ожидает запуска", то его нельзя удалить.

Изменить вариант письма можно только если тестирование в состоянии "ожидает запуска" или дата запуска варианта письма ещё не прошла или и тестирование не активно и изменяемый вариант ещё не выпущен.

Пока тестирование не в состоянии "победитель выбран" или "завершено" можно поменять способ выбора победителя.

Если тестирование в состоянии "завершено", то можно изменить только его название.

Список сплит-тестирований

{
 "action" : "issue.split.list" 
}

ответ

{
 "list" : [
            {
             "id" : "номер тестирования" 

            ,"name" : "название" 

            ,"group" : код группы

            ,"group.name" : название группы

            ,"active" : "активность" 

            ,"state" : "состояние" 
            }
          ]
}

Создать сплит-тестрование

{
 "action" : "issue.split.create" 

 ,"name" : "название" 

 ,"group" : "код группы" -- группа для получения аудитории. только группы c типом адресов email. не masssending и не personal.

 ,"percent" : процент аудитории для тестового охвата. от 1 до 100. целое число.

 ,"winner.by" : manual | read | click | unsub  -- способ выбора победителя
                                               -- manual - в ручную
                                               -- read   - больше чтений
                                               -- click  - больше кликов
                                               -- unsub  - меньше отписок
                                               -- игнорируется, если процент равен 100

 ,"winner.after" : "DD hh" -- момент запуска победителя - через сколько дней (DD) и часов (hh) после выпуска последнего
                           -- теста автоматически выбрать победителя
                           -- игнорируется, если процент равен 100 или способ выбора победителя manual

 ,"active" : 0|1 -- активность. 0 - приостановлено. 1 - активно

 ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" 
}

ответ

{
   <общие поля>

 ,"id" : номер тестирования
}

если "return_fresh_obj" : "1" 

ответ -- как на запрос "issue.split.get" соответствующего тестирования

Прочитать сплит-тестрование

{
 "action" : "issue.split.get" 

 ,"id" : номер тестирования
}

ответ

{
   <общие поля>

 ,"id" : номер тестирования

 ,"name" : "название" 

 ,"group" : код группы для получения аудитории

 ,"group.name" : название группы

 ,"percent" : процент аудитории для тестирования

 ,"winner.after" : "DD hh" -- момент выбора победителя.

 ,"winner.by" : "способ выбора победителя" 

 ,"active" : "активность" 

 ,"state" : "состояние тестирования" -- назначается автоматически
             -- 0 - ожидает запуска
             -- 1 - подготавливается к запуску
             -- 2 - запущено
             -- 3 - ожидает выбора победителя
             -- 5 - победитель выбран (да именно 5, а не 4)
             -- 4 - завершено
             -- -1 - ошибки

 ,"parts" : [ -- список вариантов тестовых писем
             {
              "id" : "номер варианта" 

             ,"start.at" : "время запуска" 

             ,"issue.at" : "номер выпуска" -- если вариант уже выпущен для теста

             ,"issue.winner" : "номер выпуска" -- если вариант уже выпущен как победитель

             ,"is_winner" : 0|1 - вариант выбран как победитель
             }

            ,{
              ......
             }

             .......
            ]
}

Изменить сплит-тестрование

{
 "action" : "issue.split.set" 

 ,"id" : номер тестирования

-- не обязательные поля. не указанное поле сохранит прежнее значение

 ,"name" : название

 ,"group" : группа для получения аудитории. не masssending и не personal
            -- изменение игнорируется если состояние тестирования не "ожидает запуска" 

 ,"percent" : процент аудитории для тестового охвата. 
            -- изменение игнорируется если состояние тестирования не "ожидает запуска" 
            -- при установке в 100 очищаются поля winner.by и winner.after

 ,"winner.by" : способ выбора победителя
            -- изменение игнорируется, если процент равен 100
            -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено".
            -- при установке в manual очищается поле winner.after

 ,"winner.after" : момент запуска победителя
            -- изменение игнорируется, если процент равен 100 или способ выбора победителя manual
            -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено".

 ,"active" : активность
             -- изменение игнорируется, если состояние тестирования "победитель выбран" или "завершено".

 ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 - по умолчанию)" 
}

ответ

{
   <общие поля>
}

если "return_fresh_obj" : "1" 

ответ -- как на запрос "issue.split.get" соответствующего тестирования

Удалить сплит-тестирование

Нельзя удалять тестирование в состоянии "запущено" и выше, так как при таком состоянии уже был как минимум один выпуск.

{
 "action" : "issue.split.delete" 

 ,"id" : номер тестирования
}

ответ

{
   <общие поля>
}

Выпустить победителя

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

Допустимо при ручном способе выбора победителя если уже вышли все варианты, но победитель ещё не выбран.

Допустимо при автоматическом способе выбора победителя если уже вышли все варианты и не прошло время автоматического выбора.

Не допустимо если процент тестирования 100.

{
 "action" : "issue.split.winner" 

 ,"variant.id" : номер варианта
}

ответ

{
   <общие поля>
}

Список вариантов писем сплит-тестирования

{
 "action" : "issue.split.variant.list" 

,"split.id" : номер тестирования
}

ответ

{
   <общие поля>

 ,"list" : [
             {
               "id" : номер варианта

               ,"start.at" : время запуска

               ,"issue.at" : "номер выпуска" 

               ,"issue.winner" : "номер выпуска" 

               ,"is_winner" : 0|1 - вариант выбран как победитель
             }
            ,........
           ]
}

Создать вариант

Нельзя создать новый вариант если тестирование не в состоянии "ожидает выпуска"

{
 "action" : "issue.split.variant.create" 

 ,"split.id" : номер тестирования

-- параметры варианта

 ,"start.at" : "YYYY-MM-DD hh:mm" -- время запуска. дата и время с точностью до минуты

 ,"letter" : { -- высылаемое письмо

      ,"format" : "html|sms|text" -- формат письма. в данный момент поддерживается только html

      ,"from" : "email отправителя",

      ,"sender" : "имя отправителя",

      ,"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" : "номер выпуска" -- если вариант уже выпущен как победитель

 ,"is_winner" : 0|1 - вариант выбран как победитель

}

Изменить вариант

Изменить вариант письма можно только если тестирование в состоянии "ожидает запуска" или дата запуска варианта письма ещё не прошла или и тестирование не активно и изменяемый вариант ещё не выпущен.

{
 "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.accesss,
                               за исключением отсутствия варианта default" }

          ,"text" : "содержимое выпуска" 

          ,"draft.id" : "уникальный идентификатор черновика, по которому сделан выпуск",

          ,"sequence.id" : "уникальный идентификатор последовательности, событие в которой вызвало выпуск",

          ,"variant.id" : "уникальный варианта сплит-тестирования для которого сделан выпуск",

          ,"attach" : [ -- прикрепленные файлы

                         "aaa.doc" 

                        ,"bbb.doc" 

                        ...

                       ]

           ,"archive" : "ссылка на выпуск в архиве" 

           -- ссылки на изображения письма выпуска
           -- только для html выпусков, и только для групп отличных от personal
           -- в настоящий момент поддерживаются картинки 640x1100 и 150x180
           -- надо учитывать что ссылка может вести на отсутствующее изображение
           -- например, из-за сбоя при её формировании

           ,"thumbnail" : [
                          {
                           "url" : "ссылка на изображение" 
                          ,"width" : ширина в пикселах,
                          ,"height" : высота в пикселах
                          },

                         ...............

                         ],

         }

}

Получение файлов, приложенных к выпуску


 {

  "action" : "issue.get.attach" 

  ,"id" : "уникальный идентификатор выпуска" 

  ,"attach" : [  -- имена файлов вложений, которые необходимо получить (если параметр не указан - все вложения)

                "aaa.doc" 

               ,"bbb.doc" 

                ...

              ] 

 }

ответ


{

 <общие поля>

 ,"list" : [

            "aaa.doc" : "содержимое файла|null - если файл не найден",

            "bbb.doc" : "содержимое файла|null - если файл не найден",

            ...

           ]

}

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


 {

  "action" : "issue.set.acсess" 

  ,"id" : "уникальный идентификатор выпуска" 

  ,'access' : { -- доступ к выпуску на вебе разрешён 

                "who" : default  -- использовать значение из глобальной настройки "issue.access" вызова sys.settings.get

                        all      -- всем

                        member   -- внесённым в базу

                        issue    -- участникам группы по который был выпуск

                        group    -- участникам группы с кодом в параметре "group" 

                        none     -- никому

               ,"passwd" : "индивидуальный пароль для доступа к выпуску" -- дополнительно для доступа запрашивается этот пароль

                                                                         -- не применим если who = default или none

               ,"group" : код группы -- обязателен для who = group

               }

 }

ответ


{

 <общие поля>

}

Черновики выпусков

Список черновиков


{

  "action" : "issue.draft.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

             "id" : "уникальный идентификатор черновика" 

            ,"format" : "html|sms|text" -- формат черновика

            ,"name" : "название" 

            ,"template" : "0|1" -- признак шаблона (шаблон - заренее предустановленный черновик с оформлением)
            }

            ...

           ]

}

Чтение черновика


{

  "action" : "issue.draft.get",

  "id" : "код черновика",

}

ответ


{

  <общие поля>

  "obj" : {

      "id" : "идентификатор черновика" 

      ,"name" : "название черновика" 

      ,"format" : "html|sms|text" -- формат черновика

      ,"division" : "идентификатор подразделения, имеющего доступ к черновику" 

      ,"from" : "email отправителя (для выпуска)",

      ,"sender" : "имя отправителя (для выпуска)",

      ,"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" 

 ,"email" : "адрес для параметеризации подстановок" -- не обязательно

-- одно из

 "id" : "номер черновика" 

-- или

 ,"obj" : { -- можно передавать объект из issue.draft.get - лишние поля проигнорируются

            ,"format" : "html|sms|text" -- формат черновика

            ,"text" : "текст черновика в соответствующем формате" 

           }

}

ответ


{

 <общие поля>,

 "text" : "текст выпуска" 

}

вверх

Шаблоны информационных писем

Список шаблонов информационных писем


{

  "action" : "infolett.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

             "id" : "уникальный идентификатор" 

            ,"format" : "html|sms|text" -- формат

            ,"name" : "название" 

            ,"onmoderation" : 0|1 -- 0 - шаблон одобрен для использования, 1 - шаблон на модерации

            }

            ...

           ]

}

Чтение шаблона информационного письма


{

  "action" : "infolett.get" 

 ,"id" : "идентификатор шаблона" 

}

ответ


{

  <общие поля>

  "obj" : {

      "id" : "идентификатор шаблона" 

      ,"name" : "название" 

      ,"onmoderation" : 0|1 -- 0 - шаблон одобрен для использования, 1 - шаблон на модерации

      ,"format" : "html|sms|text" -- формат

      ,"from" : "email отправителя",

      ,"sender" : "имя отправителя",

      ,"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" 

 ,"email" : "адрес для параметеризации подстановок" -- не обязательно

-- одно из

 ,"id" : "номер письма" 

-- или

 ,"obj" : { -- можно передавать объект из infolett.get - лишние поля проигнорируются

            ,"format" : "html|sms|text" -- формат черновика

            ,"text" : "текст черновика в соответствующем формате" 

           }

}

ответ


{

 <общие поля>,

 "text" : "текст письма" 

}

вверх

Группы

Cписок групп


{

 "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 годов и/или месяцев

  1. сначала точность даты автоматически понижается до года или года-месяца
  2. к/из полученой даты прибавляются/вычитаются указаные года и месяца
  3. после чего результат преобразуется обратно к точности год-секунда установкой первого месяца (если надо) первого числа 0 часов 0 минут 0 секунд
  4. к/из полученого результата прибавляются/отнимаются остальные компоненты от месяца до секунда
  5. результат приводится к точности поля заданой в "a"

Строго формально всё ещё хуже - бывает 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.* - информация о домене подписчика

member.anketa.ANKETA.QUEST - значение ответа QUEST из анкеты ANKETA. 
                           - при отсутствии ответа на указаный вопрос результат null
                           - *в данный момент допустимо только в select* 
                           - *в данный момент не может быть параметром функций агрегации*

Существует специальная особенность связанная с выборкой данных подписчика.

Пока вы используете в запросе поля id и email, вы получаете данные о всех подписчиках.

Как только в запросе появляется поле haslock, вы начинаете получать данные только о тех подписчиках, запись о которых до сих пор есть в вашей базе.

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

Пример когда проявится разница - запрос адресов участвовавших в выпуске ("select":["member.email"]) вернёт все адреса попавшие в выпуск, а такой же запрос с дополнительной выборкой текущего состояния блокировки ("select":["member.email", "member.haslock"]) вернёт только тех, кого вы ещё не удалили из своей базы.

Эту особенность можно использовать специально для отсечения тех кто из базы уже удалён. Фильтр member.haslock >= 0 выберет подписчиков с любым состоянием блокироваки, но приведёт к исключению из результатов тех кто уже удалён.

Информация o группе


group.id - id группы

group.gid - символический код группы

group.name - название группы

Информация o выпуске

Поля с количеством отсеяных участников содержат актуальное значение для выпусков начиная с 26-07-2013.
Для более ранних выпусков поля содержат 0.


issue.id - id выпуска

issue.dt - дата выпуска (dt:Ys)

issue.name - тема выпуска

issue.members - число получателей выпуска

issue.format - формат выпуска

issue.size  - размер выпуска. Для email - размер одного письма, для sms - количество потраченых смс.

issue.archive - ссылка на копию выпуска в веб-архиве (доступ ограничивается - см. issue.set.accesss)

issue.hardbounce - количество участников группы не допущенных в выпуск из-за большого количества ошибок доставки

issue.stoplist - количество участников группы не допущенных в выпуск из-за нахождения их адреса в стоп-листе

issue.lockunsub - количество участников группы не допущенных в выпуск из-за того что их адрес отписан

issue.lockconfirm - количество участников группы не допущенных в выпуск из-за того то внесение в базу ими ещё не подтверждено

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)

issue.thumbnail_640x1100 - ссылка на изображения письма выпуска 640x1100 (подробности в issue.get) (null)

issue.thumbnail_150x180 - ссылка на изображения письма выпуска 640x1100 (подробности в issue.get) (null)

Информация o ссылке


link.id - id ссылки

link.url - url ссылки

link.linkgroup.* - информация о группе в которую входит ссылка

Информация o группе ссылок


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обытия") в каком порядке ("Шаги","Варианты") должно происходить.

На каждом Шаге последовательности можно задать несколько сценариев развития событий создав несколько Вариантов описав какие События активируют какой вариант (один вариант могут активировать несколько разных действий) и задать какие Действия (одно или несколько) должны быть выполнены в каждом из вариантов.

Как простой частный случай с помощью событийных действий можно реализовать триггерные рассылки (автоответчики) - задайте на первом шаге условие начала последовательности и как действие - первое высылаемое письмо.
На следующий шагах задавайте интервал времени до высылки следующего письма и его высылку в действиях.

Для придания автоответчику интелектуальности можно, например, сочетать события "Клик" и "Прошло время" для выбора какое из писем высылать далее, действия "Изменить данные" что бы учитывать на какое из высланых писем пользователь среагировал, действия "Завершить последовательность" что бы прекратить высылать подписчику письма при отсутствии инетереса, действие "Перейти на другую последовательность" что бы сменить тематику в зависимости от его реакции.

В более сложных случаях можно организовать автоматические напоминания о забытых корзинах в интернет-магазинах, автоматическое изменение статуса покупателя в зависимости от числа покупок и даже квест-игры по электронной почте.

Обработка событий

Каждое событие произошедшее в системе проверяется не подходит ли оно в какой-либо последовательности к её первому шагу или к текущему шагу уже находящегося на последовательности пользователя.

Проверка производится путём просмотра всех условий каждого из вариантов шага. Если в данном варианте шага событие подходит к одному из условий, то дальнейший поиск в данном шаге последовательности прекращается и выполняются все действия описанные в том варианте к которому подошло событие после чего пользователь переходит на следующий шаг последовательности.

Подходящее событие может быть проигнорировано если пользователь или последовательно находятся в состоянии паузы.

Подходящее событие может не вызвать начало прождения пользователем последовательности если этому мешают настройки разовости и закрытости последовательности.

Свойства последовательности

Однократность

Можно ли ещё раз начать прохождение последовательности, если она уже была пройдена или проходится в данный момент.

Параллельность

В данный момент не реализовано !

Можно ли одновременно проходить последовательность несколько раз и если можно, то при запуске нового прохождения прервать ли текущие

Закрытость

Новые участники не могут начать последовательность. Ни как не влияет на прождение последовательности уже имеющимися участниками.

Пауза

Cобытия не учитываются и значит ни кто не продвигается по последовательности и не начинает её. Пропущенные события теряются.

Возобновляемость

Возобновление прохождения при увеличении количества шагов.

Участники, завершившие ранее прохождение последовательности путём дохождения до её последнего шага, автоматически возобновят её прохождение с шага, следующего за тем на котором они закончили.

Для одного участника возобновляется только одно, имеющее максимальный номер шага-окончиния, прохождение.

Не возобновляется участник и так проходящий последовательность в момент её удлиннения не смотря на параметр parrallel.

вверх

События

Новая регистрация без подтверждения

Наступает когда пользователь первый раз вносится в базу и на это от него не требуется подтверждения регистрации.

Обратите внимание, что это событие должно быть в последовательности только первым и в другой позиции просто не сработает никогда по логике.

{

 "type" : "member.new.no-confirm" 

}

Новая регистрация c подтверждением

Наступает когда пользователь первый раз вносится в базу и от него требуется подтверждение регистрации.

Обратите внимание, что это событие должно быть в последовательности только первым и в другой позиции просто не сработает никогда по логике.

{

 "type" : "member.new.confirm" 

}

Подтверждение регистрации

Наступает когда пользователь подтверждает регистрацию.

{

 "type" : "member.confrim" 

}

Самостоятельное удаление регистрации

Наступает когда пользователь отписывается (т.е. запрещает дальнейшую высылку ему чего-либо)

{

 "type" : "member.unsubscribe" 

}

Прошло временя

Не может быть в списке у вариантов первого действия последовательности.

Наступает когда с момента попадания на данных шаг прошёл указаный интервал времени равный указанному количеству дней, часов и минут.

{

 "type" : "time.elapsed" 

,"interval" : "DDDDD hh:mm" или "hh:mm" или "mm" 
             -- DDDDD - до пяти цифр количества дней
             -- hh    - количество часов
             -- mm    - количество минут

}

Точное время

Не может быть в списке у вариантов первого действия последовательности.

Наступает когда текущее время совпало с заданными ожидаемыми.

Зачем ? Например удобно накопить желающих начать какой либо курс и разом начать его в удобный день высылкой первого письма.

Можно указать:

  1. месяц, день и время - сработает раз в год
  2. день и время - сработает раз в месяц если в нём есть такой день
  3. только время - сработает раз в день
  4. день недели - сработает раз в неделю в 0 часов 0 минут
  5. день недели и время - сработает раз в неделю в указанный момент
{

 "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
}

вверх

Список последовательноcтей

{

 "action" : "sequence.list" 

}

ответ

{

 <общие поля>

,"list" : [

            {

             "id" : "код последовательности" 

            ,"name" : "название" 

            }

            ...

           ]

}

вверх

Cоздать последовательность

{

  "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

,"sms.unlimited" : 0|1 - тираж sms не ограничен купленым количеством

,"sms.used" : "использовано sms за всё время" 

,"sms.byed" : "куплено 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.accesss,
                     за исключением отсутствия варианта 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"  : "код вопроса" 

 }

вверх

Cтрочное сравнение

Это медленый фильтр.

В будущем он может быть удалён.

В большинстве случаев его использования можно избежать, если изначально делать вопрос не полем ввода, а списком выбора

Строка ответа на вопрос не равна (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" } ] 

}

Замена вызова stat.issue.delivering


{

  "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"]

}

Суммарное число чтений, кликов по месяцам с 2011 года


{ 

  "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.

_Порядок определения формата при использовании users.list

1) Если значение массив, то данные считаются заданными в формате JSON-массив

2) Если значение объект, то данные считаются заданными в формате JSON-объект

3) Если значение строка представляющая zip-архив и он содержит файл workbook.xml, то считается что это XLSX (технически XLSX это zip-архив со специальным набором файлов)

4) Если значение строка представляющая zip-архив и он не содержит файл workbook.xml, берётся первый по порядку файл архива и cчитается, что это данные в формате CSV

5) Если значение строка не-zip-архив, то считается, что это данные в формате CSV

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

1) Если content-type ответа application/json, то данные должны описывать массив или объект и формат выбирается как описано выше в пунктах 1 и 2.

2) При другом значении content-type выбор происходит как описано выше в пунктах 3, 4 и 5.

Пример задания JSON-массив

"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" },

 .........

},

.....

]

Пример задания JSON-объект

"users.list" : {

  "caption" : [
      {
       "anketa" : "member" 
      ,"quest" : "cellphone" 
      },
      {
       "anketa" : "info" 
      ,"quest" : "firstname" 
      },
      {
       "anketa" : "info" 
      ,"quest" : "title" 
      },
      {
       "anketa" : "info" 
      ,"quest" : "middlename" 
      },
  ],

 "rows" : [
     [ "+70000000000","Павел","Иванович","Уважаемый" ],
     [ "+70000000000","Алексей","Алексеевич","Глубоко уважаемый" ],
     ......
 ]

}

Пример задания XLSX

В виду двоичного содержимого файла, он не может быть приведён в документации и доступен по ссылке

https://pro.subscribe.ru/API/sample.xlsx

Пример задания CSV

"users.list" : "member.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.108     2013-09-20
                          * Новые возможности динамического контента  из RSS и социальных сетей - lenta.*
                          * Выпуск sms c ограничением частоты, времени дня и учётом временной зоны получателя - параметр tz_limit вызова issue.send
                          * Параметры шаблонизатора общие для всех - параметр extra вызова issue.send
                          * Забытое описание параметра email в issue.draft.preview и infolett.preview
                          * Окончание совместимости со старым способом возврата ошибок
                          * Окончание совместимости со старым способом указания уведомлений

0.107     2013-08-01      
                          * Получение анкетных данных из Универсальной статистки через member.anketa.*
                          * Новые переменные в Универсальной статистике
                                issue.archive - адрес архива выпуска
                                issue.thumbnail_* - адреса изображений предпросмотра выпуска 
                                issue.hardbounce, issue.stoplist, issue.lockunsub, issue.lockconfirm - количество адресов не допущенных в выпуск с разбивкой по причинам
                                member.haslock = 4 - информация о новой блокировке адреса - из-за фатальных ошибок доставки
                          * Отчёты со статистикой и об ошибках в результатах отслеживания асинхронного вызовы issue.send при рассылке "Экспресс-Выпуск" 
                          * Новые статистические данные в member.list.count: locked.stoplist и locked.hardbounced
                          * Указание списка для member.update/delete/sendconfirm с помощью ссылки
                          * Получение адреса изображений предпросмотра выпуска рассылки в issue.get
                          * track.list - в фильтре по статусу можно указать список статусов, а не только один
                          * issue.get ссылка на архив теперь возвращается в параметре archive вместо url
                          * Отменены ни где не используемые параметры:
                                Анкета - member_fill
                                Вопрос анкеты - listsubtype, mustselect, onetime, defval
                                Параметр subtype - только для вопросов dt
                                Параметр width - только для вопросов free
                          * Окончание поддержки старого вызова issue.running "Список выпусков формируемых прямо сейчас" 

0.106     2013-07-04      * Модерация имени отправителя sms - вызовы issue.smssender.*
                          * Дополнительный параметр "report_file.json" в результате отслеживания асинхронного вызова member.import
                          * Новый параметр в ответе member.set - newbie
                          * Новые состояния асинхронного запроса - "Отменено" и "Генерация отчёта" 
                          * Новые события тригерных действий - "Регистрация с подтверждением" и "Регистрация без подтверждения" 
                          * Новый способ выбора победителя сплит-тестирования - "меньше отписок" 
                          * Новое состояние сплит-тестирования - "Победитель выбран" 
                          * Новый параметр в свойствах варианта сплит-тестирования - is_winner
                          * Новые настройки sms.used, sms.byed и sms.unlimited  в вызове sys.setting.get
                          * Окончание совместимости со старыми параметрами вызовов member.import/member.import.probe/anketa.quest.add/anketa.quest.set
                          * !!! Изменился способ указания высылаемых уведомлений в вызовах member.import, member.set, member.sendconfirm
                            !!! ПОДРОБНОСТИ В РАЗДЕЛЕ "Общие замечания" 
                            !!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 15 СЕНТЯБРЯ 2013 ГОДА

0.105     2013-06-07      * Новая возможность - Отслеживания состояния и хода асинхронных вызовов - track.*
                          * Измененения в вызовах issue.send, member.* и stat.* для поддержки отслеживания
                          * Новое статистическое поле "отписок" в объекте Выпуск (issue) вызова Универсально Статистики stat.uni
                          * Новая настройка about.user в вызове sys.setting.get
                          * Уточнение формата параметров sys.log
                          * Уточнение описания параметра newbie.confirm и названия вызова member.set
                          * Уточнение описания параметра users.list для member.import
                          * Правильное написание параметра clean_group для member.import
                          * !!! ВЫЗОВ issue.running "Список выпусков формируемых прямо сейчас" УСТАРЕЛ.
                            !!! ИСПОЛЬЗУЙТЕ ЗАМЕНУ "Список асинхронных вызовов" 
                            !!! ПЕРЕЙДИТЕ НА НОВЫЙ СПОСОБ ДО 01 АВГУСТА 2013 ГОДА

0.104     2013-05-07      * Уточнение поведения issue.send c отложеным выпуском

0.103     2013-04-29      * Универсальная статистика stat.uni
                               резко повышенное быстродействие при использовании новых полей
                               новые статистические поля доставки/кликов/чтений в объекте Выпуск (issue) вызова stat.uni и примеры с их использованием
                               новый объект domain - домен подписчика
                          * Новый движок импорта подписчиков. Из видимых изменений
                               у вызовов member.import(.probe) изменился способ возврата ошибок и предупреждений
                               новый параметр clean_group - очистить группу-список перед импортом
                               JSON-объект можно использовать как источник данных 
                          * Новая настройка "Не высылать на отсутствующие адреса" issue.dontsend.550 в вызовах sys.settings.get/set
                          * Модерация информационных писем и поле onmoderation в вызовах infolett.*
                          * Работа с анкетами
                               anketa.quest.add/anketa.quest.set -- описание параметра id в ответе
                               anketa.quest.set - изменение нескольких вопросов сразу. новый способ передачи параметров
                               anketa.quest.add - создание нескольких вопросов за раз. новый способ передачи параметров
                          * Вызовы rfs.*
                               новый параметр url
                               уточнение описания
                          * Замечание про тестирование с локальным адресам
                          * Замечание про последовательность обработки

0.102     2013-03-15      * !!! ИЗМЕНИЛСЯ СПОСОБ ВОЗВРАТА ОПИСАНИЯ ОШИБОК !!!
                            !!! ПЕРЕЙДИТЕ НА НОВУЮ СХЕМУ ДО 15 СЕНТЯБРЯ 2013 ГОДА !!!
                          * Новый вызов member.list.count - Количество участников в группе
                          * Список подписчиков member.list: новый параметр member.haslock
                          * Список групп group.list: вставлено забытое описание параметров type и add_type
                          * Прочитать группу group.get
                               новый параметр with_filter
                               параметр id позволяет задавать список групп
                          * Универсальная статистика stat.uni
                               новый параметр "cache" - подсказки как в итоге использовался кэш
                               уточнения про временную зону, 61ю секунда, 23 и 25 часов
                               исправление в примерах
                          * кэширование ответов - уточнение описания режима cache : "fetch" 

0.101     2013-01-25      * система кэширования результатов вызовов
                          * Универсальная статистика stat.uni
                               поддержка кэширования и специальный ответ result = "none" 
                               поддержка вычитания годов и месяцев из текущей даты и полезны к этому примеры
                               информация об отписках
                               полностью переработаное и расширеное описание всех доступных данных
                          * кэширование условий stat.uni в условиях отбора группы
                          * уточнения описания полей с массивами аресов в sys.settings.*
                          * уточнение описания параметра sort вызова member.list

0.100     2012-12-18      * issue.send: возможность задания данных произвольной сложной структуры для "Экспресс-Выпуска" 
                          * новый вызов issue.later.get
                          * новый вызов sys.password.set
                          * новые специальные ответы "Перенаправление" и "Смена пароля" 
                          * member.import/member.import.probe: новые поля в ответе rows и queue_position
                          * sys.settings.*: новые параметры redirect.member.join.exists и sec.*
                          * decor,siteform: новый параметр redirect_exists_to
                          * issue.send: возможность указать время отложенного выпуска с точностью до минуты
                          * issue.later.send: возможность указать новое время отложенного выпуска с точностью до минуты
                          * issue.later.list: новое поле draft.id
                          * email.test: новые поля ip и ptr
                          * уточнение описания как работать с сессией авторизации

0.99      2012-11-13      * Описаны лимиты внесения без подтверждения для импорта адресов списком
                          (member.import) и внесения по одному адресу (member.set)
                          * Новый параметр sequence.event в member.import
                          * issue.send: исправлено неверное название параметра draft на верное draft.id
                          * Отслеживание переходов в сплит-тестирования: link.qsid для issue.split.variant.*
                          * Вызовы decor.issue.* (Общее оформление) удалены
                          * issue.later.list - изменения и новые поля в ответе
                               format, group, status.reason, issue.date, status
                          * sys.settings.get - новые значения
                               trial, trial.issue.limit, trial.issue.rest
                               allow.email, allow.sms
                               member.tarif.limit, member.hard.limit,
                               member.noconfirm.limit, member.noconfirm.limit

0.98      2012-10-02      * Группы по результатам статистических запросов (group.filter.set/get)
                          * Прочитать выпуск (issue.get):
                               параметр draft переименован в draft.id
                               новые параметры sequence.id и variant.id
                          * Универсальная статистика (stat.uni)
                               новые поля - issue.draft.id, issue.sequence.id, issue.variant.id, member.haslock
                               новые операции в фильтре - is_null и !is_not
                               сравнение значения поля с текущим временем

0.97      2012-09-06      Сплит-тестирование / А-B тестирование

0.96      2012-08-06      Cобытийные действия / Триггерные рассылки 

0.95      2012-07-23      * Новый вызов issue.running
                          * Новый параметр  format в вызове issue.list
                          * Новые параметры from,upto,group,format в вызове issue.later.list

0.94      2012-06-26      Транзакционные выпуски. Описание различия между четырмя способами выпуска.

0.93      2012-04-19      * Добавление поддержки списка email или одного email в вызове member.update
                          * Добавлен параметр addr_type для уточнения типа адреса в вызове member.set.
                          * Вызов issue.draft.set - division стало необязательно.
                          * В вызовах issue.draft.get,issue.draft.set,issue.draft.list для использования
                              предустановленных черновиков добавлены параметры "template", "template.thumbnail".
                          * Форматирование, уточнения (group.create, issue.draft.get).

0.92      2012-02-15      * Формат данных подписчиков для импортирования и экспресс выпуска (users.list) изменен
                          * Поддерживается формат XLSX или стандартный CSV
                          (разделитель колонок - запятая, допускается заключение текста ячейки в кавычки)

0.91      2012-01-31      * Добавлена поддержка параметра "result", для вызовов stat.issue и stat.uni.
                          * Во всех запросах использующих параметр "result" = (response|email|save) добавлен
                            дополнительный параметр "result.format" для возможности выбора формата XLSX,
                            если "result" равен "save" или "email".
                          * Сам параметр "result" стал необязательным, по умолчанию -"response".  

0.90      2012-01-20      Поддержка авторизация с помощью биометрических карт AGSES

0.89      2011-11-11      * Исправления stat.issue (описание, добавлен итог по выпускам и получателям),
                          * stat.activity (добавлена возможность сохранения и высылки,обратная сортировка,
                             изменения в описании),
                          * stat.uni (добавлены типы статистики deliv_ok deliv_bad deliv_unk и пример их
                             использования в сводной статистике) 

0.88      2011-10-26      Возможность влиять на код группы-списка создваемой при внесении списка подписчиков

0.87      2011-10-20      Не совместимое изменение работы member.get и member.set с участием в группах-списках.

0.86      2011-10-18      Возможность разовой авторизации.

0.85      2011-10-17      Новые вызовы user.create, user.delete, user.set (вместо sys.password.set)

0.84      2011-10-13      Новые вызовы issue.later.*, rights.*, user.list, issue.draft.preview и infolett.preview.

0.83      2011-10-10      Новые вызовы link.* и sys.messaage. Вызов about.get удалён.

0.82      2011-09-27      Вызов "Универсальная статистика" 

0.81      2011-09-26      Новый вызов "Окончание работы". Уточнение что импорт может добавлять в любую группу-список

0.80      2011-09-22      Вызов создания группы group.create теперь полностью поддерживает создание группы-списка

0.79      2011-09-14      Только протокол https;  Вызов about.get будет удалён

0.78      2011-09-13      Добавлены разделы "Журнал работы", "Пароль", "Чтение настроек", "Изменение настроек",
                          "Общая статистика по группе", "Статистика выпусков", "Портрет аудитории", "Доставка выпусков" 

0.77      2011-08-11      Добавлены разделы "Пригласить подписчиков","Общее оформление выпусков",
                          "Массовое изменение данных подписчиков", "Форма подписки для сайта", "Файлы изображений и отчетов" 

0.76      2011-06-27      Добавлен раздел "Форматы просмотра и шаблоны заполнения" 

0.75      2011-06-23      Вызов member.delete может работать со списком и группой

0.74      2011-05-30      Уточнение описания member.list

0.73      2011-05-30      Форматирование

0.72      2011-05-30      Добавлен раздел "Список подписчиков" (вызов member.list), и "Архив выпусков" (вызов issue.list)

0.71      2011-05-11      Добавлен раздел "Черновики выпусков" 

0.70      2011-04-29      Расширение функций вызова stat.activity

0.69      2011-04-27      Вызов email.test

0.68      2011-04-26      Добавлен раздел "История изменений" 

0.67      2011-04-26      * Вынос вызовов <OBJ>.list к своим объектам. Описание синхронных и асинхронных вызовов.
                          * Уточнение про медленные фильтры. Форматирование.

0.66      2011-04-25      Вызовы issue.draft.*, и infofett.*

0.65      2011-04-25      Форматирование

0.64      2011-04-25      Уточнения в описании стоп-листа

0.63      2011-04-25      Форматирование

0.62      2011-04-25      Добавление вызовов stoplist.*  Удаление stoplist.list

0.61      2011-04-12      Описание параметра group в вызове member.set

0.60      2011-04-12      Описание параметра newbie.confirmв вызове member.set

0.59      2011-04-11      Уточнения типа _plain после quest пугали людей и они писали fio_plain

0.58      2011-04-11      Описан member.get

0.57      2011-03-17      Списковые ответы опять хэш.Разница между получением и установкой фильтра. Пример расширен работой с датой

0.56      2011-03-16      Форматирование

0.55      2011-03-16      Улучшено описание параметра session, вызов about.get отнесён в статистику

0.54      2011-03-16      Форматирование

0.53      2011-03-16      Описание фильтра отбора в группе

0.52      2011-03-15      Форматирование

0.51      2011-03-15      Форматирование

0.50      2011-03-15      Форматирование

0.49      2011-03-15      Форматирование

0.48      2011-03-14      member.set::newbie.notify иmember.set::newbie.notify.letter

0.47      2011-03-11      Более внятное название название метода

0.46      2011-03-10      member.set/confirm/delete

0.45      2011-03-10      anketa.save/anketa.quest.save ->anketa.set/anketa.quest.set

0.44      2011-03-01      Уточнение, что дополнятся при импорте может не любая группа

0.43      2011-02-17      Общее описание методов получение изамены фильтра в группе

0.42      2011-02-17      Описание общих методов работы сгруппами

0.41      2011-02-15      Форматирование

вверх