API, Betta 0.99 2012-11-13

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

Вызов

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

https://pro.subscribe.ru/api

Метод вызова

Настоятельно рекомендуется POST как не кэшируемый.

Не забывайте, что вы будете использовать протокол HTTP и, следовательно, название и значение параметров вызова надо передавать в кодировке urlencode.

Метод GET поддерживается, но крайне не рекомендуется так как формально ответы на GET могут кэшироваться.

Возможно, с одной из новых версий, метод GET перестанет поддерживаться.

Параметры вызова

Пример данных для вызова функции login методом POST:


apiversion=100&json=1&request.id=777&request={"action":"login","login":"jondoe","passwd":"secret"}

вверх

Ответ

Ответ выдаётся в формате JSON и кодировке UTF-8

Синхронность

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

Общие поля ответа


{

 "request.id" : "то что было в запросе в параметре request.id" 

,"duration" : null или "время обработки запроса" 

}

Нормальный ответ


{

 <общие поля>

,<поля специфические для конкретного запроса>

}

Формат ответа при ошибке


{

 <общие поля>

,'error' : "код ошибки" 

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

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

}

вверх

Проверка работоспособности

Пинг без авторизации


{

 "action" : "ping" 

}

ответ


{

 <общие поля>

,"pong" : "что-то каждый раз разное" 

}

вверх

Пинг с авторизацией


{

 "action" : "pong" 

}

ответ


{

 <общие поля>

,"ping" : "что-то каждый раз разное" 

}

вверх

Авторизация

Авторизация по логину и паролю

Полученный в ответ номер сессии должен передаваться во всех запросах в параметре "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" : "anketa.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

             "system" : "системная, да, нет (1, 0)" 

             ,"member_fill" : "заполняется подписчиком, да, нет (0, 1)" 

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

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

            }

            ...

           ]

}

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


{

 "action" : "anketa.get" 

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

}

ответ


{

 <общие поля>

,'obj' : {

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

          "param" : {

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

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

                     "member_fill" : разрешено заполнять пользователю да/нет

                    },

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

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

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

                     .....

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

                    ]

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

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

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

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

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

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

                             "subtype" : под-тип вопроса,

                             "width" : ширина ответа в байтах,

                             "onetime" : заполняется однократно да/нет,

                             "mustselect" : обязателен для заполнения да/нет,

                             "defval" : значение по умолчанию,

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

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

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

                                           .....

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

                                         },

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

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

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

                                        .....

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

                                       ],

                            },

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

         },

}

тип/под-тип вопроса:

вверх

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


{

    "action" : "anketa.delete" 

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

}

ответ


{

    <общие поля>

}

вверх

Создание анкеты


{

    "action" : "anketa.create" 

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

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

    ,"copy_from" : "уникальный идентификатор анкеты (не нужен для создаваемой с нуля, а не копируемой анкеты)" 

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

Сохранение анкеты


{

    "action" : "anketa.set" 

    ,"id" : "идентификатор анкеты" 

    ,"member_fill" : "заполняется подписчиком -- да, нет( 1 | 0 )" 

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

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

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


{

   "action" : "anketa.quest.add" 

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

  ,"name" : "Название или текст вопроса" 

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

  ,"mustselect" : "Обязательно подписчику для заполнения - да , нет ( 1 | 0 )" 

  ,"onetime" : "Ответ подписчиком дается только один раз - да , нет ( 1 | 0 )" 

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

   для type=free:

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

   для  type=dt:

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

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

   ,"listsubtype" : "из списка ('yn' ,'year', 'month', 'day'), не обязателен" 

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

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

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

        ..... 

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

   }

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

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

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

         .....

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

   ]

   необязательные для запроса в целом

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

   ,"defval" ; "значение по умолчанию (для has не нужен вообще, для 1m и nm - код ответа, для остальных - значение ответа)" 

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

Сохранение вопроса анкеты


{

   "action" : "anketa.quest.set" 

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

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

  ,"name" : "Название или текст вопроса" 

  ,"mustselect" : "Обязательно подписчику для заполнения - да , нет ( 1 | 0 )" 

  ,"onetime" : "Ответ подписчиком дается только один раз - да , нет ( 1 | 0 )" 

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

   для type=free:

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

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

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

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

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

        ..... 

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

   }

   ,"order" : [ -- порядок ответов (обязательный?)

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

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

         .....

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

   ]

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

   ,"defval" ; "значение по умолчанию (для has не нужен вообще, для 1m и nm - код ответа, для остальных - значение ответа)" 

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

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


{

     "action" : "anketa.quest.delete" 

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

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

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

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


{

     "action" : "anketa.quest.order" 

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

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

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

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

          .....

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

     ]

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

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


{

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

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

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

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

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

вверх

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


{

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

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

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

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

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

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

        .....

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

]

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

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

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

}

ответ


{

    <общие поля>

}

если "return_fresh_obj" : "1" 

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

Подписчики

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

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

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

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

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

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

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

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

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

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

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

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

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


{

  "action" : "email.test" 

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

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

 ,"list" :  [

             "     PRO@subscribe.ru   " 

            ,"123@test@test.ru  " 

            ," missing@CityCat.ru" 

            ......

            ]

}

ответ


{

    <общие поля>

   "list" : {

              "     PRO@subscribe.ru   " :  { "email" : "pro@subscribe.ru" -- нормализованая форма адреса

                                             ,"syntax" :'ok'

                                             ,"smtp" : { 'status' : 'ok' }

                                            }

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

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

                                      }

             ," missing@CityCat.ru" : { "email" : "missing@citycat.ru" 

                                       ,"syntax" : "ok" 

                                       ,"smtp"  : {

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

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

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

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

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

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

                                                  }

                                       }

         }

}

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


{

  "action" : "member.get" 

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

}

ответ


{

    <общие поля>

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

  ,'obj' : { 

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

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

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

            'ank1' : {

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

                       'quest' : 'val'

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

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

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

                      ,'quest' : [ 'val' ]

                      }

          ,'ank2' : {

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

                     }

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

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

              'id1' : 1

              ,id2' : 1

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

              ,idN' : 1

            }

          }

}

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

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


{

  "action" : "member.set" 

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

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

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

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

  ,"newbie.notify" : "уведомлять подписчика о внесении в базу (1|0)" 
                     -- если адрес до этого отсутствовал в базе,то ему высылается запрос для подтверждения регистрации
                     -- отсутствие параметра (или значение 0) приведёт только кто тому, что не будет выслан запрос.
                     -- а неоходимость подтвердить регистрацию никуда не денется
                     -- при внесении номеров телефонов ни какие уведомления не высылаются

  ,"newbie.notify.letter" : "номер шаблона письма" 
                            -- Текст запроса будет стандартный (параметр отсутствует) или будет
                            -- использован текст из указанного шаблона информационных писем

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

  ,"obj" : {

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

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

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

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

            'ank1' : {

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

                       'quest' :'val'

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

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

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

                      ,'quest' : [ 'val' ]

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

                      ,'quest' : null

                      }

          ,'ank2' : {

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

                     }

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

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

          ,'-group': {

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

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

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

                  'id1' : "(0|1)" 

                  ,id2' : "(0|1)" 

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

                  ,idN' : "(0|1)" 

                }

          }

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

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

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

}

ответ


{

 <общие поля>

}

если "return_fresh_obj" : "1" 

ответ -- как на запрос чтения "action" : "member.get" соответствующего адреса

вверх

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


{

  "action" : "member.confirm" 

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

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

}

ответ


{

 <общие поля>

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

}

вверх

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

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


{

  "action" : "member.delete" 

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

или

 ,"list" : [

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

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

            ........

           ]

или

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

}

ответ


{

 <общие поля>

}

вверх

Список подписчиков


{

  "action" : "member.list" 

 ,"addr_type": "тип выбираемых адресов подписчиков (email | msisdn)" 
                -- при отсутвии определяется по типу адресов в указанной группе
                -- если указан, то должен совпадать с типом адресов в группе, если и та указана
                -- если не указан и не указана группа, то выбираются еmail-адреса

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

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

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

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

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

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

-- для response

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

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

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

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

-- email

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

--

}

ответ


{

    <общие поля>

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

              {

                anketa      : код анкеты

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

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

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

              }

             ....

           ]

-- при "result" : "response" 

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

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

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

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

             .....

           ]

}

вверх

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

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

В ответ будет сообщено как произошло авто-определение кодировки (сharset), разделителя столбцов,

определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких

анкет приписаны столбцы данных

Если вы знаете зарание ответы на эти вопросы то можете сразу указать эти данные при вызове

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

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

автоматически если их не указать сразу при вызове. Этот вызов асинхронный - получение положительного

ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта - он

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

быть забран список импорта)

При указании источников данных ссылкой и при наличии там файла настроки параметров приоритет

таких параметров средний - он выше приоритета авто-определения, но ниже приоритета

параметров указанных прямо в вызове


{

  "action" : " member.import" 

или 

  "action" : " member.import.probe" 

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

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

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

  ,"users.list": "данные для импорта" 
                 -- данные в формате XLSX (Excel 2007) или CSV (разделитель колонок - запятая (;),
                 -- содержимое ячейки может быть заключено в кавычки ("))  

  ,"users.url": "адрес с данными для импортирования, http/https/ftp",

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

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

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

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

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

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

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

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

                {

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

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

                  или 

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

                 },

                ......

              ]

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

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

** импорт

  ,"action": "member.import",

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

  ,'newbie.notify' : "уведомлять подписчика о внесении в базу (1|0)" 
                    -- если адрес до этого отсутствовал в базе то ему высылается запрос для подтверждения регистрации
                    -- отсутствие параметра (или значение 0) приведёт только кто тому, что не будет выслан запрос.
                    -- а неоходимость подтвердить регистрацию никуда не денется
                    -- при внесении номеров телефонов ни каких уведомлений не высылается

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

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

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

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

                      внесение newbie.confirm не приводит к расходованию member.noconfirm.rest

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

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

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

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

                 }, 

   ,"letter" : "id информационного письма" 
                -- это письмо с просьбой подтвердить регистрацию, которое будет выслано при внесении
                -- если это указано настройкой newbie.*",

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

   ,"sequence.event" : 0|1 -- будет ли внесение/измение данных вызывать срабатывание событийных действий
}

ответ


{

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

  "uid": "идентификатор уже загруженных данных" (только для member.import.probe,

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

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

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

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

                {

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

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

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

                  или

                  "ignore" : 1

                 }

              ]

   "warnings" : [ -- не фатальные ошибки

                  [ "name":"код предупреждения", "explain": "доп. информация (скаляр, массив или хэш)"  ] 

                  ....

                ],

   "errors" : [ -- фатальные ошибки

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

                  ....

              ],

    },

}

вверх

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


{

 "action" : "member.sendconfirm" 

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

* указать подписчиков одним из способов

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

или

 ,"list" : [

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

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

            ........

           ]

или

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

}

ответ


{

    <общие поля>

}

вверх

Массовое изменение данных подписчиков


{

 "action" : "member.update" 

-- обязателен один из параметров:

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

или

 ,"list" : [

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

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

            ........

           ]

или

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

--

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

 ,"if_has" : что делать, если изменяемый пункт анкеты уже заполнен

             -- "overwrite" - заменить старое значение новым из формата

             -- "merge"     - объединить старое и новое значения

             -- "skip"      - оставить старое значение

 ,"if_hasnt" : что делать, если изменяемый пункт анкеты ещё не заполнен

             -- "set"  - заполнить указанным в формате значением

             -- "skip" - оставить пункт незаполненным

}

ответ


{

    <общие поля>

}

вверх

Форма подписки для сайта


{

 "action" : "decor.siteform" 

 ,"format" : "html" (в данный момент только одно это значение)

 ,"fields" : [ -- список вопросов в порядке, в котором они должны быть в форме

              {

                "anketa" : "код анкеты" 

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

             }

             .....

           ]

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

 ,"redirect_to" : "полный урл для перенаправления после заполнения формы" (не обязательно)

}

ответ


{

  <общие поля>

 , "siteform" : "html код формы" 

}

вверх

Файлы изображений и отчетов

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

Если path указывает на файл то возвращается информация только о нём

Если path указывает на каталог то возвразается список его файлов и подкаталогов

Параметр domain указывает на используемую область - хранилище картинок (image) или хранилище отчётов (report)


{

 "action" : "rfs.list" 

 ,"domain" : "image|report" 

 ,"path" : "полный путь - каталог или файл" 

}

ответ


{

 <общие поля>

 ,"file" : [

            {

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

             ,"path" : полный пусть до файла

             ,"size" : размер

             ,"date" : дата изменения (в формате yyyy-mm-dd hh:mm:ss)

            }

            ......... 

           ]

 ,"dir" : [

           {

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

           ,"path" : полный пусть до каталога

           }

           ......... 

          ]

} 

вверх

Получить файл


{

 "action" : "rfs.file.get" 

 ,"domain" : "image|report" 

 ,"path" : "полный путь до файла" 

}

ответ


{

 <общие поля>

 ,"datа" : содержимое файла

} 

Записать файл

Только для domain = image


{

 "action" : "rfs.file.put" 

 ,"domain" : "image" 

 ,"path" : "полный путь до файла (отсутвующие попутные подкатлоги сами по себе на создаются)" 

 ,"datа" : содержимое файла

}

ответ


{

 <общие поля>

} 

вверх

Удалить файл


{

 "action" : "rfs.file.delete" 

 ,"domain" : "image|report" 

 ,"path" : "полный путь до файла" 

}

ответ


{

 <общие поля>

} 

вверх

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

Только для domain = image


{

 "action" : "rfs.dir.make" 

 ,"domain" : "image" 

 ,"path" : "полный путь до каталога (отсутвующие попутные подкатлоги сами по себе на создаются)" 

}

ответ


{

 <общие поля>

} 

вверх

Удалить каталог

Только пустой каталог

Только для domain = image


{

 "action" : "rfs.dir.delete" 

 ,"domain" : "image" 

 ,"path" : "полный путь до каталога" 

}

ответ


{

 <общие поля>

} 

вверх

Выпуски рассылки

Варианты выпуска рассылок

Все рассылки (и email и sms) выпускаются через вызов issue.send

Есть четыре варианта его использования.

Группа-спискок Группа-фильтр Экспресс-Выпуск Транзакционное письмо
Адреса получателей Зарнее созданые в базе список Динамический поиск по всей (!) базе адресов данные которых удовлетворяют фильтру Указываются при выпуске или забираются по ссылке Указывается при выпуске
Данные для персонализации Из базы Из базы Указываются при выпуске Из базы если не указаны при выпуске
Количество переменных Не ограничено Не ограничено Не ограничено Не ограничено
Шаблонизатор Продвинутый Продвинутый Продвинутый Продвинутый
Собственные функции-плагины к шаблонизатору Да Да Да Да
Сложные вложенные структуры данных Нет Нет Да Да, если указаные сразу
Подтверждение от владельца адреса Требуется Требуется Требуется Не обязательно
Разбор жалоб на спам Согласно договора Согласно договора Согласно договора С особым пристрастием
Лимит в месяц Не ограничено Не ограничено Не ограничено Первоначально равен максимально допустимому количеству адресов в базе. Далее в зависимости от репутации

Отослать выпуск

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

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


{

* начальные параметры:

    "action" : "issue.send",

    "gid" : "id группы | masssending - если это Экспресс-Выпуск | personal - Транзакционное письмо",

    "lang": "язык выпуска" (ru - Русский |uk - Украинский |be - Белорусский)", (по умолчанию "ru") (игнорируется для SMS)

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

    "from.name": "Имя отправителя", (по умолчанию название аккаунта)

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

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

    "message": {

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

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

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

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

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

               }

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

    "draft.id": "номер черновика содержимое которого даст выпуск",

* параметры способа выпуска. Тестовый выпуск не доступен для Экспресс-Выпуска и Транзакционных писем.

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

    "sendwhen": "Когда выпустить (now - сейчас | later - отложенный | delay - задержаные | save - отложить на хранение | test - тестовый)",

при отложеном выпуске (later) указывается дополнительно дата и час не ранее которых выпускать 

    "later.time" : "YYYYMMDDhh" 

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

     например "2010-12-31 23" то же самое что и "2010-12-31T23" 

     и будут восприняты как "2010123123" - 23 часа 31го декабря 2010 года)

при задержаном выпуске (delay) указывается дополнительно на сколько минут задержать выпуск 

    "delay.time" : "mm" 

при выпуске теста (test) указываются адреса получателей. не более пяти.

    "mca": [

            "e@mail.1",

            "e@mail.2",

             ......

           ]

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

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

    "relink.param" : {

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

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

                      "test": "проверять существование адресов (1 - да|0 - нет)",

                               при включённой проверке выпуск не выдет если ссылка не действительна (ответ не 200, не 301 и не 302)

                     }

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

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

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

    "attaches": [ 

                  { "name": "имя файла", "content": "содержимое файла" },

                  { "name": "имя файла", "content": "содержимое файла" },

                  { "url": "url откуда заборать" },

                  { "url": "url откуда заборать" },

                  ...

                ],

* список получателей для Экпресс-Выпуска

    "users.list": "данные подписчиков"  -- адреса и данные для персонализации в формате XLSX (Excel 2007) или CSV (разделитель колонок - запятая (;), содержимое ячейки может быть заключено в кавычки ("))" 

или

    "users.url": "URL по которому находится список подписчиков (ftp://... | http(s)://...) в том же формате",

* параметры списка получателей для Экпресс-Выпуска

    "only_unique": "Следить за уникальностью адресов в списке (1 - да, повторно встреченные адреса пропускаются | 0 -нет, повторно встреченные адреса получают письма тоже )",

* получатель для Транзакционных писем

    "email" : "адрес получателя" -- данные для персонализации берутся из базы

или

    "users.list": "данные подписчика"  -- адрес и данные для персонализации в формате XLSX (Excel 2007) или CSV (разделитель колонок - запятая (;), содержимое ячейки может быть заключено в кавычки ("))" 
                                       -- при указании только адреса данные персонализации берутся из базы
                                       -- при нескольких адресах используется только первый

}

ответ

{

    <общие поля>

}

Список выпусков формируемых прямо сейчас

 {
  "action" : "issue.running" 
 }

ответ

{
 "list" : [ -- выпуски рассылок выходяще прямо сейчас
           {
           ,"dt.updated : дата-время последнего обновления записи

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

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

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

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

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

           ,"issue.id" : id выпуска

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

           -- в некоторых случаях информация для прогноза окончания выпуска отсутсвует
           -- и тогда параметры eta имеют пустое значение

           ,"eta"             : примерное количество секунд до окончания формирования выпуска

           ,"eta.perc"        : примерный процент обработки списка получателей

           ,"eta.dt.finished" : примерное дата-время окончания формирования выпуска
           }
           ,......
          ]
}

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


{

  "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" : "название выпуска (тема)" 

                ,"create.date" : "YYYY-MM-DD hh:mm:ss" -- дата постановки задания

                ,"status" : "статус задания" -- hold  - отложено на хранение
                                             -- later - отложено для выпуска
                                             -- error - ошибка выпуска

                -- если статус "отложено для выпуска" 

                ,"issue.date" : "YYYY-MM-DD hh:mm" -- запланированная дата выпуска

                -- если статус "отложено из-за ошибки" 

                ,"status.reason" : код ошибки

              },

             ...

            ]

}

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


{

 "action" : "issue.later.send",

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

 "issue.date" : "новая дата выпуска" -- если не указано, устанавливается текущая (выпускается немедленно)

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

}

ответ


{

  <общие поля>

}

Удаление отложенного выпуска


{

 "action" : "issue.later.delete",

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

}

ответ


{

  <общие поля>

}

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

Описание

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

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

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

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

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

Правила

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ответ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

ответ

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

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

если "return_fresh_obj" : "1" 

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

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

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

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

ответ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            ,{
              ......
             }

             .......
            ]
}

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

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

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

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

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

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

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

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

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

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

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

ответ

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

если "return_fresh_obj" : "1" 

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

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

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

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

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

ответ

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

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

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

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

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

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

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

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

ответ

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

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

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

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

ответ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      ,"subject" : "тема письма",

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

      ,"link.qsid" : "параметр отслеживания переходов" -- аналогичен параметру issue,send

           }

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

ответ

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

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

если "return_fresh_obj" : "1" 

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

Прочитать вариант

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

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

}

ответ

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

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

 ,"split.id" : номер тестирования куда входит этот вариант

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

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

      ,"format" : "формат письма" 

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

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

      ,"subject" : "тема письма",

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

      ,"link.qsid" : "параметр отслеживания переходов" 

           }

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

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

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

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

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

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

-- параметры варианта, изменятся только явно указанные. параметр letter заменяется полностью

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

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

      ,"format" : "формат письма" 

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

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

      ,"subject" : "тема письма",

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

      ,"link.qsid" : "параметр отслеживания переходов" 

           }

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

ответ

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

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

если "return_fresh_obj" : "1" 

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

Удалить вариант

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

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

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

ответ

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

вверх

Архив выпусков

Список выпусков в архиве


 {

  "action" : "issue.list" 

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

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

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

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

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

               ... 

             ] 

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

ответ


{

 <общие поля>

,"list" : [

            {

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

            }

            ...

           ]

}

Чтение выпуска в архиве


 {

  "action" : "issue.get" 

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

 }

ответ


{

 <общие поля>

 "obj" : {

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

          ,"date" : "дата выпуска",

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

          ,"format" : "html|text|sms", -- формат выпуска

          ,"title" : "тема письма" 

          ,"issue.access" : { "права доступа у выпуску. структура аналогичная параметру access вызова issue.set.acesss,
                               за исключением отсутствия варианта default" }

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

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

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

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

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

                         "aaa.doc" 

                        ,"bbb.doc" 

                        ...

                       ]

          ,"url" : {

                     "public" : "http://..." -- ссылка на выпуск для доступа без авторизации подписчика

                     ,"member" : "http://..." -- ссылка на выпуск для доступа с авторизацией подписчика

                    }

         }

}

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


 {

  "action" : "issue.get.attach" 

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

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

                "aaa.doc" 

               ,"bbb.doc" 

                ...

              ] 

 }

ответ


{

 <общие поля>

 ,"list" : [

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

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

            ...

           ]

}

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


 {

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

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

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

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

                        all      -- всем

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

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

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

                        none     -- никому

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

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

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

               }

 }

ответ


{

 <общие поля>

}

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

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


{

  "action" : "issue.draft.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

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

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

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

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

            ...

           ]

}

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


{

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

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

}

ответ


{

  <общие поля>

  "obj" : {

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

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

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

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

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

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

      ,"subject" : "тема письма (для выпуска)",

      ,"text" : "текст" 

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

-- У предустановленных черновиков (при template = 1)

      ,"template.thumbnail" : "http://.." -- расположение (URL) изображения шаблона

}

Создание или изменение черновика

Создает или изменяет параметры и содержимое черновиков. Вызов не может быть применён к шаблонам (предустановленным черновикам) с оформлением.


{

  "action" : "issue.draft.set" 

  ,"obj" : {

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

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

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

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

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

      ,"subject" : "тема письма (для выпуска)",

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

           }

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

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

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

}

ответ


{

 <общие поля>

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

}

Удаление черновика


{

  "action" : "issue.draft.delete" 

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

}

ответ


{

 <общие поля>

}

Предпросмотр черновика


{

 "action" : "issue.draft.preview" 

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

или

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

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

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

           }

}

ответ


{

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

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

}

вверх

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

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


{

  "action" : "infolett.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

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

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

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

            }

            ...

           ]

}

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


{

  "action" : "infolett.get" 

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

}

ответ


{

  <общие поля>

  "obj" : {

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

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

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

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

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

      ,"subject" : "тема письма",

      ,"text" : "текст" 

          }

}

Создание или изменение шаблона информационного письма


{

  "action" : "infolett.set" 

  ,"obj" : {

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

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

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

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

      ,"subject" : "тема письма",

      ,"text" : "текст" 

           }

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

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

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

}

ответ


{

 <общие поля>

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

}

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


{

  "action" : "infolett.delete" 

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

}

ответ


{

 <общие поля>

}

Предпросмотр информационного письма


{

 "action" : "infolett.preview" 

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

или

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

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

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

           }

}

ответ


{

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

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

}

вверх

Группы

Cписок групп


{

 "action" : "group.list" 

}

ответ


{

 <общие поля>

,"list" : [

            {

             "id" : "код группы" 

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

            }

            ...

           ]

}

Создать группу

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

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


{

  "action" : "group.create" 

 ,"id" : "смысловой код группы. символы a-zA-Z0-9" 
         -- например "clients2011" 
         -- не обязателен. при отсутвии будет назначен автоматически

 ,"name" : "название группы" -- обязательно

 ,"issue.passwd" : "пароль выпуска по почте" -- не обязательно, используйте только если будете отсылать задания
                                             -- на выпуск рассылки через почтовый интерфейс

 ,"type" : "list | filter" - обязательно. тип группы.

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

                            filter - группа является набором фильтров для отбора по всей базе

 ,"addr_type" : "email | msisdn" - обязательно, тип адресов на работу с которыми будет ориентирована группа

}

ответ


{

 <общие поля>

 , "id" : "код созданой группы" 

}

вверх

Прочитать группу


{

  "action" : "group.get" 

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

}

ответ


{

 <общие поля>

 ,"obj" : {

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

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

             ,"issue.passwd" : "пароль выпуска по почте" 

             ,"type" : "тип группы" 

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

          }

}

вверх

Изменить группу


{

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

                                      --   save     - сохранить на сервере, в этом случае вызов асинхронный

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

    -- email

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

    -- email или save

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

}

ответ


{

    <общие поля>

   ,'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    - выслать на почту, в этом случае вызов асинхронный

                                   --   save     - сохранить на сервере, в этом случае вызов асинхронный

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

-- email

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

-- email или save

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

}

ответ


{

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

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

                                   --   save     - сохранить на сервере, в этом случае вызов асинхронный

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

-- email

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

-- email или save

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

}

ответ


{

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

  selected : количество адресов участвовавших в выборке

  list : {

        "код анкеты" 

          : {

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

               : {

                  "код ответа" 

                    : {

                       "num" : "число ответов" 

                      ,"perc" : "процент от количества ответов на этот вопрос" 

                      }

                   .....

                 }

             .....

            }

        .....

       }

}

вверх

Общая статистика по группе


{

 "action" : "stat.group.common",

 "group" : [ ], -- коды групп. Если пусто - по всем

 ,"result" : "response|email|save" -- cпособ возврата результата:

                                   --   response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен

                                   --   email    - выслать на почту, в этом случае вызов асинхронный

                                   --   save     - сохранить на сервере, в этом случае вызов асинхронный

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

-- email

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

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

}

ответ


{

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

 "members" : { -- сумма locked.* может не равняться просто locked

               "total"                : "всего адресов" 

              ,"active"               : "активных" 

              ,"locked"               : "заблокированых" 

              ,"locked.unconfirmed"   : "заблокированых, так как не подтвердили регистрацию" 

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

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

            },

  "tld" : { -- количество адресов по доменам первого уровня. для телефонов - кода стран (+7)

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

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

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

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

          },

  "sld" : {  -- количество адресов по доменам второго уровня. для телефонов - коды стран и следующие три цифры (например, +7921)

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

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

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

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

          }

}

вверх

Универсальная статистика

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


{

 "action" : "stat.uni" 

,"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'  : значение.
                    -- для полей типа дата (помечены dt) возможно сравнение с текущим временем +/- сдвиг
                    -- для этого значение v записывается в виде "сurrent +D day +h hour +m minute +s second" 
                    -- все поля задающие сдвиг не обязательны, но их порядок важен.
                    -- к названию величины можно добавлять на конце "s" 
                    --
                    -- примеры:
                    --
                    -- current
                    --
                    -- current -1 hour -3 minutes +4 second
                    --
                    -- current -40 days + 78 hours
                    --
                    -- обратите внимание, что единиц "год" и "месяц" нет. Это вызвано тем, что не всегда можно
                    -- вычитать из/прибавлять к текущей дате некоторое количество месяцев или лет, так как в
                    -- получившемся месяце может не быть текущего дня.
                    --
                    -- например, если сегодня 30е марта, то вычитание 1го месяца даст февраль, а 30е февраля было
                    -- ранее только в 1712 году и следующий раз может быть, предположительно, в 3328 году.
                    --
                    -- например, если сегодня 31 декабря, то вычитание 3х месяцев даст 31 сентября.
           }

           ,{

             'a'  : имя поля

            ,'op' : операции (не-)вхождения в список (in !in)

            ,'v' : [ значение, значение, ...] список значений для проверки вхождения (in) или не вхождения (!шт)
           }

           ,{

             'a'  : имя поля

            ,'op' : операции (не-)определённости (is_null !is_null)
                    только для полей помеченных (null)
                    параметр "v" должен или отсутствовать или быть равен "" 
           }

           .........

          ]
,"result" : "response|email|save" -- cпособ возврата результата:

                                   --   response (по умолчанию) - сразу (в ответе), в этом случае вызов синхронен

                                   --   email    - выслать на почту, в этом случае вызов асинхронный

                                   --   save     - сохранить на сервере, в этом случае вызов асинхронный

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

-- email

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

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

}

ответ


{

 list => [

          [строка1,данные в порядка заданом в select]

          [строка2,данные в порядка заданом в select]

          [строка3,данные в порядка заданом в select]

          ........

         ]

}

Поля для использования.

Отметка (null) обозначает, что поле может иметь неопределённое значение.
Например если выпуск рассылки не использовал ни какой черновик, то значение поля issue.draft.id будет не опеределено.

Все логические операции с полем имеющим неопределённое значение всегда не выполняются.
Например, неопределённое значение номера черновика не попадёт под фильтр issue.draft.id > 10, но так же оно не попадёт и под фильтр issue.draft.id <= 10.

Cтатистика чтений



read.dt - дата и время чтения (dt:Ys)

Cтатистика переходов


click.dt - дата и время клика (dt:Ys)

click.ip - ip кликнувшего

click.link.id - id ссылки

click.link.url - url ссылки

click.linkgroup.id - группы ссылок

click.linkgroup.name - name группы ссылок

Cтатистика доставки


deliv.status - код статуса доставки

Статистика успешной доставки


deliv_ok.status - статус доставки

Статистика не успешной доставки


deliv_bad.status - статус доставки

Статистика доставки по еще доставляемым письмам


deliv_unk.status - статус доставки

Статистика выпусков


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

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

issue.group.id - id группы выпуска

issue.group.gid - код группы выпуска

issue.group.name - name группы выпуска

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

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

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

issue.draft.id - номер черновика использованного при выпуске (null)

issue.sequence.id - номер последовательности вызвавшей выпуск (null)

issue.variant.id - номер варианта сплит-тестирования для которого вышел выпуск (null)

Поля связанные с подписчиком


member.id - id подписчика

member.email - значение email или телефона подписчика

member.haslock - блокировка подписчика
                  0 - нет            - может получать письма или sms
                  1 - отписался      - не может получать письма или sms
                  2 - не подтверждён - не может получать письма или sms
                  3 - 1 и 2 сразу    - не может получать письма или sms

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

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

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

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

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

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

Возможно одновременное использование следующих сочетаний полей в одном запросе

Сводная статистика

Специальные названия полей используются для функций 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.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.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" : "код тарифа" 

,"trial"       : 0|1 - тестовый режим. действуют некоторые ограничения

,"trial.issue.limit" : лимит на тираж писем. null - ограничения нет

,"trial.issue.rest"  : доступный остаток тиража писем. null - ограничения нет

,"allow.email" : 0|1 - доступна работа с email

,"allow.sms"   : 0|1 - доступна работа с sms

,"member.tarif.limit" : лимит на количество адресов в базе используемый при расчёте оплаты. null - ограничения нет

,"member.hard.limit" : лимит на количество адресов в базе который не превысить. null - ограничения нет

,"member.noconfirm.limit" : лимит на количество адрес которые можно внести без подтверждения. null - ограничения нет

."member.noconfirm.rest" : доступный остаток на внесение без подтверждения. null - ограничения нет

Список настроек которые можно и прочесть и поменять


 "about.owner.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.member.confirm" : "url", -- После подтверждения регистрации

 "redirect.member.remove"  : "url", -- После удаления регистрации

 -- Использование шаблонов информационных писем

 "infolett.confirm.need" : "код шаблона", -- Высылается когда адрес регистрируется или при использовании вызова
                                          -- "member.sendconfirm" без указания желаемого черновика.
                                          -- Пусто - стандартный системный текст

 "infolett.confirm.done" : "код шаблона", -- Высылается сразу после подтверждения регистрации.
                                          -- Пусто - не высылается ничего

 "infolett.info"         : "код шаблона", -- Высылается когда требуется сообщить подписчику его регистрационные
                                          -- данные и он уже подтвердил регистрации.
                                          -- Пусто - стандартный сиситемный тест
 --

 "msisdn.country" : "число", -- код страны (без +) для нормализации регистрируемых не полных номеров телефонов

 "msisdn.zone"    : "число", -- код зоны для нормализации регистрируемых не полных номеров телефонов

 --

 "issue.link.qid" : "строка", -- добавка к ссылкам в письмах

                              -- переходы из писем рассылок плохо видны в статистике именно как переходы из рассылки
                              -- и часто попадают в общую кучу "прямые переходы" (typed in).

                              -- Вы можете указать параметр (например source=pro) который будет добавляться ко всем
                              -- ссылкам в вашем выпуске (например, было http://site.tld/,а станет http://site.tld/?source=pro)
                              -- и, соответственно, позволит однозначно определить при анализе посещаемости сайта
                              -- что посетитель пришёл именно из выпуска рассылки. 

 "issue.access" : { "права доступа у выпуску. структура аналогичная параметру access вызова issue.set.acesss,
                     за исключением отсутствия варианта default" }

Список пользователей


{

 "action": "user.list" 

}

ответ


{

 <общие поля>

 ,"list" : [

           {

             "sublogin" : "саблогин пользователя",

             "status" : "-1 - ожидает смены пароля |0 - активен | 1 - заблокирован",

            },

           ..

         ]

}

вверх

Создание пользователя


{

 "action" : "user.create",

 "sublogin" : "саблогин",

 "password" : "пароль",

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

}

ответ


{

  <общие поля>

}

вверх

Удаление пользователя


{

 "action" : "user.delete",

 "sublogin" : "саблогин" 

}

ответ


{

  <общие поля>

}

вверх

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


{

 "action" : "user.set",

 "sublogin" : "саблогин пользователя", -- обязательно. 

  -- Пароль логину может менять только авторизованный логином (sublogin = пусто). 

  -- Пароль саблогину может менять авторизованный логином или любой саблогин, с правом изменения user.set.

 "status" : "-1 - ожидает смены пароля | 0 - активен | 1 - заблокирован" -- необязательно

 "password.new" : "новый пароль", -- необязательно

 "password.old" : "старый пароль", -- обязательно, если указан password.new

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

}

ответ


{

 <общие поля>

}

вверх

Обращение в саппорт


{

 "action" : "sys.message" 

 "email" :  "email для связи" 

,"message" : "текст сообщения" 

}

ответ


{

 <общие поля>

}

вверх

Журнал работы


{

 "action" : "sys.log",

 "from"   : "дата события от",

 "upto"   : "дата события по" 

}

ответ


{

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

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

 }

вверх

Любой из списка ответов

Хотя бы одни ответ из списка есть в ответах подписчика


 {

  "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" ,"count(click.*)" ,"issue.members"]

 ,"order"  : ["issue.dt"] 

}


{

  "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"count(click.*)" ,"issue.members"]

 ,"filter" : [{ "a" : "issue.group.gid", "op" : "==" , "v" : "gdfhdfh" }]

 ,"order"  : ["issue.dt"] 

}


{

  "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"count(click.*)" ,"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" ,"count(click.*)" ,"issue.members"]

 ,"filter" : [{"a" : "issue.id", "op" : "==", "v" : 15 }]

 ,"order"  : ["issue.dt"] 

}


{

  "select" : ["issue.name" ,"issue.group.name" ,"issue.dt" ,"count(click.*)" ,"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", "v" : "2011-05", "op" : ">=" }
             , { "a" : "click.dt:YM", "op" : "<=", "v" : "2011-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" ,"count(read.*)" ,"issue.members"]

}


{

  "select" : ["issue.name", "issue.group.name" ,"issue.dt" ,"count(read.*)" ,"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" ,"count(deliv.*)" ,"issue.members"]

 ,"filter" : [ { "a" : "deliv.status", "op" : ">", "v" : "0" } ]

}


{

  "select" : ["issue.name","issue.group.name","issue.dt","count(deliv.*)","issue.members"]

 ,"filter" : [ { "a" : "deliv.status", "op" : ">", "v" : "0" }
             , { "a" : "issue.group.gid", "op" : "==", "v" : "masssending" } ] 

}


{

  "select" : ["issue.name","issue.group.name","issue.dt","count(deliv.*)","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(deliv.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(deliv.issue.members)","count(deliv)","count(click)","count(read)"]

 ,"filter" : [ {"a" : "*.issue.dt:YM", "op" : ">=", "v" : "2011-06" }
             , {"a" : "deliv.status", "op" : ">", "v" : "0" }] 

 ,"order"  : ["*.issue.dt:YM"]

}

Статистика активности по выпускам


{

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

}

вверх

История изменений

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      Форматирование

вверх