Программирование циклов. Циклы с заданным числом повторений. Вложенные и итерационные циклы
Внимание! Все тесты в этом разделе разработаны пользователями сайта для собственного использования. Администрация сайта не проверяет возможные ошибки, которые могут встретиться в тестах.
Тест для 10 класса. На работу с тестом 15 минут. Результаты теста отправлять не нужно.
Система оценки: 5 балльная
Список вопросов теста
Вопрос 1
Какой оператор в языке Паскаль предназначен для реализации цикла с заданным числом повторений?
Выберите один из 4 вариантов ответа:
Варианты ответов
Вопрос 2
Какие операторы не могут быть выполнены в теле цикла с указанным заголовком?
for i :=1 to n do
Выберите несколько из 4 вариантов ответа:
Варианты ответов
- i:=i-1
- t:=i+2
- n:=n-1
- t:=n-i
Вопрос 3
Какие из приведённых циклов предназначены для возведения числа k в степень n ?
Выберите несколько из 4 вариантов ответа:
Варианты ответов
- for i:=1 to n do k:=k*k;
- r:=1; for i:=1 to n do r:=r*k;
- for i:=n downto do k:=k*k;
- r:=1; for i:=n downto 1 do r:=r*k;
Вопрос 4
Чему будет равно значение переменной t после выполнения данной последовательности команд?
for i:=1 to 20 do
for j:=1 to 30 do
Вопрос 5
Какая из приведённых блок-схем описывает цикл с заданным числом повторений?
Выберите один из 4 вариантов ответа:
Варианты ответов
Вопрос 6
Частным случаем какого цикла является цикл с заданным числом повторений?
Выберите один из 4 вариантов ответа:
Варианты ответов
- Цикла с параметром
- Никакого из перечисленных
- Цикла с постусловием
- Цикла с предусловием
Вопрос 7
Сколько раз будет выполнен заданный цикл?
for i:=20 downto 1 do
Выберите один из 4 вариантов ответа:
Варианты ответов
Вопрос 8
Сколько раз будет выполнен заданный цикл?
for i:=1 to 15 do
Выберите один из 4 вариантов ответа:
Варианты ответов
Вопрос 9
Как называется цикл, число повторений которого неизвестно до начала его работы?
Выберите один из 4 вариантов ответа:
Варианты ответов
- Итерационный цикл
- Цикл с предусловием
- Цикл с постусловием
- Безитерационный цикл
Вопрос 10
Сколько раз будет выполнен описанный цикл?
Выберите один из 4 вариантов ответа:
Вложенные и итерационные циклы
Будьте внимательны! У Вас есть 10 минут на прохождение теста. Система оценивания — 5 балльная. Разбалловка теста — 3,4,5 баллов, в зависимости от сложности вопроса. Порядок заданий и вариантов ответов в тесте случайный. С допущенными ошибками и верными ответами можно будет ознакомиться после прохождения теста. Удачи!
Система оценки: 5 балльная
Список вопросов теста
Вопрос 1
Какие операторы не могут быть выполнены в теле цикла с указанным заголовком?
for i:=1 to n do
Варианты ответов
- i:=i-1;
- t:=i+2;
- n:=n-1;
- t:=n-i;
Вопрос 2
Какой оператор в языке Паскаль предназначен для реализации цикла с заданным числом повторений?
Варианты ответов
Вопрос 3
Какие из приведённых циклов предназначены для возведения числа k в степень n?
Варианты ответов
- for i:=1 to n do k:=k*k;
- r:=1; for i:=1 to n do r:=r*k;
- for i:=n downto 1 do k:=k*k;
- r:=1; for i:=n downto 1 do r:=r*k;
Вопрос 4
Чему будет равно значение переменной t после выполнения данной последовательности команд?
t:=0;
for i:=1 to 20 do
for j:=1 to 30 do
t:=t+1;
Вопрос 5
Какая из приведённых блок-схем описывает цикл с заданным числом повторений?
Варианты ответов
Вопрос 6
Частным случаем какого цикла является цикл с заданным числом повторений?
Варианты ответов
- Цикла с параметром
- Цикла с постусловием
- Цикла с предусловием
- Никакого из перечисленных
Вопрос 7
Сколько раз будет выполнен заданный цикл?
for i:=20 downto 1 do
t:=random (100);
Варианты ответов
Вопрос 8
Сколько раз будет выполнен заданный цикл?
for i:=1 to 15 do
t:=random (100);
Варианты ответов
Вопрос 9
Как называется цикл, число повторений которого неизвестно до начала его работы?
Варианты ответов
- Итерационный цикл
- Цикл с предусловием
- Цикл с постусловием
- Безитерационный цикл
Вопрос 10
Сколько раз будет выполнен описанный цикл?
for i:=2 to 1 do
t:=random (100);
Предисловие
Многолетний опыт работы в школе и анализ контрольных работ слушателей курса повышения квалификации “Методика преподавания программирования на уроках информатики” Педагогического университета “Первое сентября” показывают, что учителя на уроках сталкиваются не только с проблемой подбора задач, но и со сложностями их проверки. Даже опытный учитель не в состоянии во время урока качественно оценить программы всех своих учеников, анализируя тексты этих программ. Зачастую проверка заключается в запуске программы ученика и проверке результатов ее работы на одном-двух, часто очевидных, тестах.
В последнее время в нашей стране появилось несколько систем автоматической проверки программ, хотя они еще и не стали общедоступными. Тем не менее наличие такой системы не снимает проблемы методики тестирования. Человеку, который не является специалистом в этой области (а таковыми невольно стали педагоги, активно занимающиеся подготовкой своих учеников к олимпиадам по программированию или проведением подобных олимпиад), сложно продумать и подготовить исчерпывающую систему тестов даже для стандартных задач.
Вашему вниманию предлагается практический курс для обучения программированию, основную часть которого составляет подборка задач, решение практически каждой из которых полезно при изучении той или иной темы. Именно это отличает данную публикацию от других задачников по программированию, где приводится много однотипных задач. Фактически делается попытка показать, как обучить программированию в школе за 16 часов :). Конечно, на самом деле это невозможно. Однако количество различных тем для изучения действительно не превышает 16. А наличие автоматизированной системы проверки позволяет вынести почти всю практическую часть курса на дом (ученики с удовольствием самостоятельно решают задачи, если могут сразу видеть результат их проверки).
Большинство представленных задач предполагают проверку их решений на системе тестов. Тесты к задачам, а также одну из систем для автоматической проверки решений можно будет скачать с сайта inf.1september.ru (раздел “Download”). Во втором из двух номеров будут разобраны решения принципиальных задач, а также обсуждена методика тестирования некоторых из них.
Специфика задач, решение которых проверяется автоматически, такова, что их условия должны быть полностью формализованы. А именно, подробно описывается диапазон всех вводимых значений, а также формат ввода и вывода. Для лучшего понимания и исключения неверного толкования приводятся примеры входных и выходных данных. Именно так и оформлены большинство предлагаемых задач.
Для удобства читателей каждая тема снабжена описанием соответствующих конструкций языка программирования Pascal (программы на языке Basic тяжело проверять с помощью автоматических систем, а язык С гораздо меньше распространен в российских школах).
Введение
Словарь языка Pascal
Словарь любой программы на языке Pascal состоит из букв, цифр и специальных символов, комбинации которых являются знаками пунктуации в языке программирования.
Цифры: 1, 2, 3, 4, 5, 6, 7, 8, 9, 0.
Буквы: _, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z.
Знаки операций: +, –, *, /, , = (больше или равно), =, <> (не равно).
Обратите внимание, что символ подчеркивания ‘_’ в языке Pascal, как и во многих других языках программирования, является буквой.
Переменные
Любой алгоритм или программа для компьютера состоит из двух разделов: описания данных и описания действий, которые над этими данными необходимо выполнить. В языках программирования действия представляются так называемыми операторами. Данные есть общее понятие для всего того, с чем оперирует компьютер. Память компьютера с точки зрения языка Pascal разделена на секции, называемые переменными. Переменные бывают разных типов. Тип определяет допустимое конечное множество значений, которое может принимать та или иная переменная. Каждая переменная имеет жестко закрепленное за ней имя. Значения переменных могут меняться в ходе выполнения программы.
Имена (или идентификаторы) используются не только для обозначения переменных, но и для констант, типов, процедур и функций. Имя может иметь и программа.
Имя (идентификатор) — это любое количество букв и цифр, начинающееся с буквы, кроме служебных слов. Хотя имена и могут быть очень длинными, в конкретных реализациях в них анализируется лишь несколько первых символов (например, 63, то есть имена, у которых первые 63 символа совпадают). Прописные и строчные буквы в именах не различимы. Так, имена My_Name , my_name и MY_NAME совпадают.
Для описания термина имя очень удобно использовать синтаксическую диаграмму (см. вверху справа). Синтаксическая диаграмма — это графическое представление синтаксиса языка программирования. С ее помощью можно определить корректность тех или иных конструкций (предложений) с точки зрения конкретного языка программирования. В отличие от блок-схем у синтаксической диаграммы могут существовать безусловные разветвления, что означает при проверке синтаксиса возможность пойти по любой из ветвей. Также могут присутствовать и бесконечные циклы. Так, из приведенной диаграммы следует, что букв и цифр в одном имени может быть как угодно много, а после первой буквы может находиться буква, цифра или ничего больше не стоять (конец диаграммы). В дальнейшем буквы и цифры могут также чередоваться произвольным образом.
Общий вид программы
Из диаграммы, представленной, видно, что программа может иметь, а может не иметь своего имени (заголовка программы). Любой из разделов описаний также может отсутствовать. Перед блоком (собственно программой) идут все необходимые описания. Располагаться они могут в различном порядке (убедитесь, что диаграмма позволяет возвращаться к разделам описаний, размещенных выше текущего раздела). Точка с запятой служит разделителем между операторами, а не является окончанием каждого оператора. Поэтому перед end точку с запятой ставить не нужно.
Урок 1
Простейшая программа на языке Pascal
Собственно программа на языке Pascal (как еще говорят, тело программы) должна начинаться со слова begin, а заканчиваться cловом end и знаком точки (см. синтаксическую диаграмму). То есть ее можно сравнить с законченным предложением. Программа, состоящая только из этих слов, разделенных пробелом или переводом строки, верна, но ничего не делает. Добавим в нее вызов процедуры печати каких-либо сообщений, например:
Текст, заключенный в апострофы, компьютер не анализирует, а просто выводит на экран, поэтому он может быть произвольным, то есть содержать любые символы, набираемые на клавиатуре, в том числе русские и латинские большие и маленькие буквы. Программа может быть записана и в одну строку, тогда различные слова нужно разделять хотя бы одним пробелом:
begin write(‘Hello’) end.
Набейте текст этой программы и запустите ее на выполнение. Научитесь просматривать результат работы программы.
Теперь познакомимся с правилами вывода в языке Pascal подробнее.
Вывод данных
Стандартные процедуры write и writeln служат для вывода информации. Правило их использования одно и то же: после слова write или writeln в скобках через запятую перечисляются параметры, которые мы хотим напечатать. Число этих параметров не ограничено. Запятая служит разделителем между параметрами:
Существует три вида параметров: константы, переменные и выражения (например, арифметические выражения). Константы бывают числовые (это просто различные числа — целые и вещественные), логические и строковые. Любой текст, набранный с клавиатуры и заключенный в апострофы (одиночные кавычки), называется строковой константой. Если в текст нам нужно поместить апостроф, например, в слове O’Key, на этом месте нужно набить два апострофа подряд вместо одного: write(‘O»Key’).
При выполнении данных операторов все параметры будут напечатаны в одной строке в заданном порядке. Любая константа числовая или строковая будет напечатана так, как вы ее набили в вызове write или writeln (только в строковой константе начальный и конечный апострофы напечатаны не будут, а вместо двух апострофов, расположенных в строковой константе подряд, на экране появится в этом месте один); вместо переменной на экране появится ее значение, а вместо арифметического выражения — результат его вычисления. Все параметры в write или writeln независимы друг от друга, поэтому в одном и том же операторе могут встречаться параметры разных типов, в произвольном порядке.
Между write или writeln существует единственное различие: после (. ) выполнения writeln курсор переходит на новую строку, а после выполнения write курсор остается в той же строке, и новая печать данных с помощью write или writeln или набивка данных для read или readln (процедур чтения данных) будет проходить в той же строке.
При печати параметров между ними пробелы автоматически не вставляются, например, при печати чисел 1, 2, 3 с помощью writeln(1,2,3) все они сольются в одно число — 123. Чтобы улучшить выдачу, можно поместить между числами символ пробел, например writeln(1,’ ‘,2,’ ‘,3) , или отформатировать выдачу, поставив после каждого элемента списка вывода двоеточие и целое число, которое указывает, сколько позиций на экране должна занимать выводимая величина, например, writeln(1:3,2:3,3:3) . Отметим, что элемент дополняется начальными пробелами слева с тем, чтобы соответствовать указанной после двоеточия величине. Результаты выполнения двух последних операторов будут выглядеть так:
Если указанное в формате выдачи число меньше, чем необходимо, то Pascal при выводе увеличит это значение до минимального необходимого размера. При выдаче на экран значений вещественных переменных или выражений в формате выдачи следует указывать еще один параметр после второго двоеточия. Он будет обозначать количество символов после десятичной точки, которые мы хотим напечатать. Например, при печати результата стандартной функции pi , которая с машинной точностью выдает значение числа p, то оператор write(pi:0:0,pi:6:2,pi/2:2:0) выдаст на экран:
Заметим, что при выдаче фиксированного числа цифр вещественного числа оно предварительно округляется по правилам математики.
Примеры операторов вывода:
write(‘Нажмите любую клавишу’);
Задания
1. Определите, что будет на экране после выполнения трех последних операторов, а потом напишите соответствующую программу и сверьте результат ее выполнения со своим предположением.
2. Напишите программу, которая семью различными способами будет выдавать на экран фразу “2 + 2 = 4” (без кавычек), воспользуйтесь для этого операторами writeln, которые следует разделять друг от друга знаком “точка с запятой” (;) — разделителем между операторами в языке Pascal.
Первый способ должен содержать всего один параметр в операторе writeln, второй — два, и т.д., пятый, шестой и седьмой — пять. При этом шестой оператор не должен содержать числа 4, а седьмой — числа 2.
В операторах печати должны использоваться все три вида параметров.
Урок 2
Целые и вещественные числовые типы данных
Каждая переменная в программе должна быть описана, то есть упомянута в разделе описаний переменных var c указанием своего типа.
Основным типом для работы с целочисленными данными является тип integer. Значениями переменных этого типа являются целые числа от –32 768 до 32 767 в Borland Pascal и от –2 147 483 648 до 2 147 483 647 в Delphi (в Borland Pascal значения из этого диапазона принимают переменные типа longint). К переменным целочисленных типов применимы следующие арифметические операции:
+, –, * — сложение, вычитание и умножение;
div — целая часть от деления (значение не округляется, а дробная часть просто отбрасывается, в том числе и для отрицательных чисел);
mod — остаток от деления нацело:
a mod b = a – ((a div b) * b).
Приведем примеры выполнения двух последних операций для всех возможных знаков аргументов:
5 div 3 = 1; 5 mod 3 = 2;
-5 div 3 = -1; -5 mod 3 = -2;
5 div -3 = -1; 5 mod -3 = 2;
-5 div -3 = 1; -5 mod -3 = -2;
Основным типом для работы с вещественными (действительными) числами является тип real . Вещественных чисел, точно представимых в компьютере, конечное число. Остальные числа либо приближаются представимыми, либо оказываются непредставимыми. Последнее относится к слишком большим и к слишком маленьким вещественным числам 1 .
К числовым типам данных применимы стандартные функции, приведенные в таблице выше.
В программировании существует негласное правило, что имена целочисленных переменных начинаются с букв i, j, k, l, m, n, a вещественных — с остальных букв. Это правило не выполняется, если переменные имеют мнемоничные имена, то есть их названия отражают условие задачи.
Cчитывание значений переменных с клавиатуры
Процедуры read и readln предназначены для задания значений переменным путем ввода их с клавиатуры или из файла. Правило их использования одно и то же: после слова read или readln в скобках через запятую перечисляются имена переменных (идентификаторы), значения которых мы хотим ввести. Число этих имен не ограничено. Запятая служит разделителем между идентификаторами:
При вызове процедуры read или readln выполнение программы будет приостановлено до тех пор, пока пользователь не введет соответствующее количество значений, они должны быть того же типа, что и переменные. Если в read или readln переменных несколько, то они могут быть набиты в одной строке, но одно число от другого должно отделяться пробелом или переводом строки. Чтобы ввести набитые значения и выполнить оператор read или readln, нужно нажать клавишу . В результате переменные приобретут заданные вами значения. Между read и readln существует единственное различие: после выполнения readln курсор переходит на новую строку, а после выполнения read курсор остается в той же строке, и новая набивка данных для read или readln будет проходить в той же строке. Но, так как после нажатия клавиши курсор в любом случае переходит на новую строчку, для однократного ввода значений переменных разницу между операторами read и readln заметить невозможно. Тем не менее в данном случае лучше использовать readln. Оператор readln можно использовать и без параметров вообще. Тогда программа просто будет ждать, пока пользователь не нажмет клавишу . Такой оператор, например, удобно ставить в качестве самого последнего оператора в программе. Тогда можно сразу посмотреть результат работы программы, а потом нажать и только тогда работа программы завершится.
Замечание. Перед вводом данных с клавиатуры рекомендуется выдавать на экран приглашение, например:
write(‘Введите число a => ‘);
Но в программах для автоматической проверки лишние печати недопустимы.
Задания
20 div 6 20 mod 4
20 mod 6 2 div 5
20 div 4 2 mod 5
trunc(6.9) round(-1.8)
round(6.9) round(0.5)
trunc(-1.8) round(-0.5)
2. Определите тип выражения (integer или real):
3. Напишите программу, в которой описана одна переменная — a. Программа выдает запрос:
Введите значение b =>
Далее вводится некоторое значение и программа выдает
Вместо многоточия должно стоять введенное значение.
4. Запишите по правилам языка Pascal следующие арифметические выражения:
5. Напишите программу, которая будет вычислять значения 2 в степени 16, 18 и 27 за минимально возможное число умножений.
Урок 3
Оператор присваивания
Синтаксическая диаграмма оператора присваивания:
Данный оператор указывает, что нужно вычислить значение выражения и присвоить полученное значение переменной (поместить его в соответствующую секцию памяти). Типы переменной и выражения должны совпадать. Исключение: переменной любого вещественного типа, например real, можно присвоить выражение любого целого типа.
Пример программы, использующей переменные различных типов:
Рассмотрим также фрагмент программы, который демонстрирует способ выделения цифр из произвольного трехзначного числа с использованием целочисленного деления с остатком.
Пусть требуется выделить цифры трехзначного числа, находящегося в целочисленной переменной a:
a1 := a div 100;
a2 := a div 10 mod 10;
a3 := a mod 10;
Задачи
1. Напишите программу, которая по введенному не более чем четырехзначному числу k будет выдавать сумму его цифр.
На вход программе подается целое число k (0 k 9999). Выдайте сумму его цифр.
Пример входных данных | Пример выходных данных |
2008 | 10 |
2. Идет k-я секунда суток. Определите, сколько целых часов h и целых минут m прошло с начала суток. Например, если k = 13 · 257 = 3 · 3600 + 40 · 60 + 57, то
h = 3 и m = 40.
На вход программе подается целое число k (0 k 86 399 2 ). Выведите на экран фразу: It is . hours . minutes.
Вместо многоточия программа должна выводить значения h и m, отделяя их от слов ровно одним пробелом.
Пример входных данных | Пример выходных данных |
13257 | It is 3 hours 40 minutes |
3. Часовая стрелка повернулась с начала суток на d градусов. Определите, сколько сейчас целых часов h и целых минут m.
Вместо многоточия программа должна выводить значения h и m, отделяя их от слов ровно одним пробелом.
Пример входных данных | Пример выходных данных |
90 | It is 3 hours 0 minutes |
4. Определите, является ли не более чем четырехзначное число k симметричным (например, 1331 или 0550).
На вход программе подается целое число k (0 k 9999). Выдайте 1 при положительном ответе на вопрос задачи и любое другое целое число — в противном случае.
Пример входных данных | Пример выходных данных |
2008 | 7 |
2002 | 1 |
5. Пусть в школе пять дней в неделю ежедневно проходят шесть уроков. Тогда в неделе всего 30 уроков. По введенному номеру дня d и номеру урока l найдите порядковый номер этого урока в неделе.
На вход программе подаются номер дня d (от 1 до 5) и номер урока l (от 1 до 6). Выведите номер этого урока (от 1 до 30) в неделе.
Пример входных данных | Пример выходных данных |
2 1 | 7 |
6. В книге на одной странице помещаются k строк. Таким образом, на 1-й странице печатаются строки с 1-й по k-ю, на второй — с (k+1)-й по (2•k)-ю и т.д. Напишите программу, которая по номеру строки в тексте определяет номер страницы, на которой будет напечатана эта строка, и порядковый номер этой строки на странице.
На вход программе подаются число k — количество строк, которое печатается на странице, и число n — номер строки (1 k 200, 1 n 20 000). Выведите два числа — номер страницы, на которой будет напечатана эта строка, и номер строки на странице.
Пример входных данных | Пример выходных данных |
50 1 | 1 1 |
20 25 | 2 5 |
15 43 | 3 13 |
7. Обозначим дни недели числами от 1 — понедельник до 7 — воскресенье соответственно. По известному m — дню недели первого числа текущего месяца — определите день недели числа n.
На вход программе подаются 2 целых числа: 1 n 31, 1 m 7. Выведите день недели числа n.
Пример входных данных | Пример выходных данных |
8 1 | 1 |
7 7 | 6 |
8. Единица товара стоит a рублей b копеек. Было куплено n штук этого товара. Сколько рублей и копеек пришлось заплатить за всю покупку?
На вход программе подаются три целых числа:
0 a 30 000, 0 b < 100 и 0 n 30 000. Выведите два искомых числа.
Пример входных данных | Пример выходных данных |
10 15 2 | 20 30 |
2 50 4 | 10 0 |
9. Цена товара обозначена в рублях с точностью до копеек, то есть вещественным числом с двумя цифрами после десятичной точки, например, 10.35. В целочисленных переменных получите и выдайте значения целого числа рублей и целого числа копеек в цене товара.
Пример входных данных | Пример выходных данных |
10.35 | 10 35 |
10. Даны значения двух моментов времени: часы, потом минуты и секунды. Известно, что второй момент времени наступил не раньше первого и разница между ними менее суток. Определите, сколько секунд прошло между двумя моментами времени.
В первой строке входных данных находятся три целых числа — часы, минуты и секунды первого момента времени. Во второй строке три числа, характеризующие второй момент времени. Число часов лежит в диапазоне от 0 до 23, число минут и секунд — от 0
до 59. Выведите число секунд между двумя моментами времени.
Пример входных данных | Пример выходных данных |
1 1 1 |
Задачи повышенной сложности 3
1. На вход программе подаются два целых числа: m и n, по модулю не превосходящих 10 6 . Если m делится на n или n делится на m, то требуется вывести 1, в противном случае — любое другое число.
Пример входных данных | Пример выходных данных |
2 8 | 1 |
0 0 | 100 |
5 0 | 1 |
2. На вход программе подаются два целых числа: m, n. Если m n, то требуется вывести 1, в противном случае — любое другое число.
Пример входных данных | Пример выходных данных |
2 8 | 0 |
2 1 | 1 |
3. Определите, верно ли, что в не более чем четырехзначном числе ровно две одинаковые цифры.
На вход программе подается целое число k (0 k 9999). Выдайте 1 при положительном ответе на вопрос задачи и любое другое целое число — в противном случае.
Пример входных данных | Пример выходных данных |
2008 | 1 |
2002 | 2 |
4. На вход программе подаются 4 целых числа, по модулю не превосходящих 10 6 , m, n, k, l. Если остаток от деления m на n равен k или l, то выведите 1, в противном случае — любое другое число.
Пример входных данных | Пример выходных данных |
12 8 3 4 | 1 |
0 5 1 2 | 0 |
5. На вход программе подаются два целых числа:
0 m < 60, 0 < n 12, указывающие момент времени
“n часов m минут”. Определите наименьшее число полных минут, которое должно пройти до того момента, когда часовая и минутная стрелки на циферблате совпадут, не обязательно на каком-то делении. Вещественную арифметику не использовать.
Пример входных данных | Пример выходных данных |
50 2 | 26 |
0 3 | 16 |
6. На вход программе подаются два целых числа:
0 m < 60, 0 < n 12, указывающие момент времени
“n часов m минут”. Определите наименьшее число полных минут, через которое часовая и минутная стрелки на циферблате расположатся перпендикулярно друг другу. Вещественную арифметику не использовать.
Пример входных данных | Пример выходных данных |
50 2 | 10 |
0 12 | 16 |
7. На вход программе подаются два числа (не обязательно целые, но не более чем с двумя знаками после десятичной точки). Распечатайте их в порядке возрастания. Используйте только арифметические операции и, при необходимости, стандартные функции.
Пример входных данных | Пример выходных данных |
10 35 | 10.00 35.00 |
3.14 2.71 | 2.71 3.14 |
8. На вход программе подается вещественное число x. Получите и выведите целое значение функции sign(x) — знак числа x.
Пример входных данных | Пример выходных данных |
3.14 | 1 |
0 | 0 |
-0.5 | -1 |
9. Квадратная таблица заполнена по спирали по часовой стрелке, начиная с левой верхней угловой клетки (1,1). По числу, записанному в некоторой клетке, определите значения строки и столбца этой клетки (они нумеруются, начиная с 1, сверху и слева соответственно).
На вход программе сначала подается значение N (1 N 30 000), а затем значение, стоящее в искомой клетке (от 1 до N 2 ). Выведите значения строки и столбца этой клетки.
Пример входных данных | Пример выходных данных |
5 1 | 1 1 |
100 2138 | 95 36 |
10. Квадратная таблица заполнена по спирали по часовой стрелке, начиная с левой верхней угловой клетки (1,1). По номерам строки и столбца некоторой клетки (они нумеруются, начиная с 1, сверху и слева соответственно) определите, какое число в ней записано.
На вход программе сначала подается значение N (1 N 30 000), а затем значения строки и столбца (от 1 до N). Выведите число, записанное в этой клетке.
Пример входных данных | Пример выходных данных |
5 1 1 | 1 |
100 95 36 | 2138 |
Урок 4
Логический тип данных
Множество значений логического типа boolean содержит всего два элемента — false (ложь) и true (истина). Эти константы предопределены так, что false < true . Логические значения получаются также в результате выполнения операций сравнения числовых, символьных, строковых или логических переменных: =, <>, , =. Такие сравнения представляют собой частный случай логических выражений — выражений со значениями типа boolean . Подобные выражения можно присваивать переменным типа boolean , а также печатать (на экран будет выведено слово false или true соответственно). Кроме операций сравнения, для построения логических выражений используются операции not, and, or, xor . Последняя операция при применении ее к логическим операндам совпадает с операцией “не равно”, то есть
(x xor y) = (x <> y) . Приведем таблицы результатов этой и других логических операций для всех возможных значений операндов (в алгебре логики такие таблицы называются таблицами истинности):
Логический результат дает также стандартная функция odd(x) , которая применяется к целочисленному аргументу х :
odd(x) = true, если х нечетно;
odd(x) = false, если х четно.
Логические выражения
В логических выражениях могут встречаться как арифметические операции, так и логические. Порядок выполнения операций определяется их приоритетом (в других языках программирования приоритеты операций могут быть другими):
2. *, /, div, mod, and;
Операции с одинаковым приоритетом выполняются по порядку слева направо. Для изменения порядка выполнения операций применяют круглые скобки.
Для булевских выражений характерно то, что их значение может стать известным еще до конца вычисления всего выражения. Например:
Уже после вычисления первого операнда операции and ясно, что результат всего выражения — false , поэтому второй операнд вычисляться не будет.
Нередко при составлении программ со сложными логическими выражениями нужно строить их отрицания. Для этого полезно воспользоваться следующей таблицей и тождествами, известными из алгебры логики:
not (a and b) = not a or not b;
not (a or b) = not a and not b.
Условный оператор
Синтаксическая диаграмма условного оператора:
На месте оператора может стоять любой из операторов, в том числе и условный, но оператор должен быть только один. Приведем синтаксическую диаграмму понятия оператор:
Последний из приведенных в диаграмме операторов называется составным. Слова begin и end называются операторными скобками.
Полный условный оператор выполняется так: сначала проверяется условие (вычисляется значение логического выражения), если оно истинно (равно true), то компьютер выполняет оператор, стоящий после then, если же ложно (равно false), то есть справедливо противоположное условие, то компьютер выполняет оператор, стоящий после else. Семантику данного оператора можно проиллюстрировать следующей блок-схемой:
Здесь B — выражение булевского типа, которое стоит в условном операторе после слова if , а S1 и S2 — операторы, которые стоят после слов then и else соответственно.
Пример условного оператора:
if k mod 2 = 0 then writeln(k, ‘ четное’)
else writeln(k, ‘ нечетное’)
Условный оператор может быть и укороченным, то есть не содержать слова else и следующего за ним оператора. Тогда, если условие, стоящее после if , ложно, то ничего делаться не будет.
Приведем блок-схему, соответствующую семантике укороченного условного оператора:
Пример использования укороченного условного оператора:
if x > 0 then writeln(‘x = ‘, x);
В этом случае ничего напечатано не будет.
Согласно синтаксису условного оператора (см. синтаксическую диаграмму), как после then, так и после else может стоять только один оператор, поэтому если необходимо использовать не один оператор, а несколько, то используется составной оператор. Например:
Если после then в качестве оператора стоит условный оператор, то возможна такая конструкция:
if условие1 then
if условие2 then оператор1
Здесь непонятно, к какому if относится else , то есть какой из условных операторов полный, а какой укороченный. Для таких случаев введено правило, по которому
if всегда относится к ближайшему else |
Значит, в данной конструкции первый оператор укороченный (без else ), а второй полный. Если же требуется, чтобы первый оператор был полным, а второй — укороченным, то следует использовать операторные скобки:
if ycловие1 then
if ycловие2 then оператор1
Благодаря операторным скобкам else стало относиться к первому if , а не ко второму. Другой способ решения данной проблемы — всегда использовать только полные условные операторы:
if условие1 then
if условие2 then оператор1
Такая конструкция всегда будет однозначной.
Примеры вложенных условных операторов:
if j = 1 then writeln(‘i = j’)
else writeln(‘i = 1, j <> 1′)
if j = 1 then writeln(‘i = j’)
else writeln(‘i = 1, j <> 1′)
else writeln(‘i <> 1′)
В обоих примерах будет напечатано то условие, при котором мы попадаем на данный оператор печати. При любых значениях i и j для каждой из программ выполнится только один из writeln .
Приведем еще несколько полезных правил применения условного оператора:
Перед else знак ; не ставится никогда. |
2. Рассмотрим следующий фрагмент программы:
if b then ; begin s1; s2; s3 end
В данном случае составной оператор будет выполняться всегда, так как после then стоит пустой оператор.
3. Пусть n условий исчерпывают все возможные случаи, например, x < 2, x = 2, x >2. Тогда вызов операторов, соответствующих каждому из случаев, можно запрограммировать двумя способами:
if x = 2 then s2; ¦ else if x = 2 then s2
if x > 2 then s3 ¦ else s3
Первый способ нагляднее, но во втором не делаются лишние проверки. Постарайтесь понять, почему во втором случае вообще не проверяется условие x > 2.
4. Рассмотрим следующий условный оператор
if a = c then b := true else b := false
Такая запись является избыточной. Вместо нее нужно применять выражение
if b = true then оператор
if b then оператор
Задачи
1. На выданном вам рисунке на координатной плоскости изображены окружности, прямые, параболы, ромбы, прямоугольники (некоторые из упомянутых линий могут отсутствовать). Несколько областей, ограниченных этими линиями, заштрихованы. Данные линии можно описать уравнениями в декартовой прямоугольной системе координат (x,y) на плоскости:
у = f(x), или x = f(y), или f(x, y) = 0.
На рисунке изображены также оси координат и координатная сетка, линии которой проведены через единицу масштаба. Восстановите по рисунку уравнения всех линий, изображенных на нем.
Напишите программу, которая позволит определять, принадлежит ли точка с вещественными координатами (x0,y0) фигуре, состоящей из всех заштрихованных на рисунке областей, или нет. Точки на границах областей не рассматривать, то есть ваша программа может считать их как принадлежащими фигуре, так и не принадлежащими ей. Значения x0,y0 вводятся с клавиатуры. В качестве ответа программа выдает на экран true , если точка с введенными координатами (x0,y0) принадлежит заштрихованной фигуре, и false , если точка (x0,y0) не принадлежит ей. Условный оператор не использовать.
Пример входных данных | Пример выходных данных |
1 1 | true |
1 -1.5 | false |
2. Напишите программу, которая будет считывать значение вещественной переменной x и будет печатать значение следующей функции от x:
Пример входных данных | Пример выходных данных |
0.1 | 1 |
-1000000000.5 | -1 |
3. Напишите программу, которая будет считывать значения целых переменных a, b и с и распечатывать их в порядке возрастания. Значения a, b и с по модулю не превосходят 30 000.
Решите задачу двумя способами:
1) не используя операторы присваивания и логическую операцию and ;
2) используя операторы присваивания.
В первом случае нужно в зависимости от значений переменных печатать их в соответствующем порядке, а во втором — значения нужно переместить так, чтобы в переменной a оказалось минимальное значение, в с — максимальное, а в b — среднее. Оператор печати в этом случае должен быть только один: writeln(a,b,c).
Пример входных данных | Пример выходных данных |
1 2 3 | 1 2 3 |
-1 -2 -3 | -3 -2 -1 |
4. Напишите программу для решения уравнения ax = b относительно х в целых числах. Учтите, что a может принимать любые значения, в том числе и 0.
На вход программе подаются целые числа a, b, по модулю не превосходящие 30 000. Требуется вывести целый корень уравнения, если он существует и единственный. Если уравнение не имеет корней, то вывести nosolution . Если уравнение имеет больше одного целого корня, то вывести many solutions.
Пример входных данных | Пример выходных данных |
1 -2 | 4 |
2 1 | 1 |
5. Даны координаты двух точек на плоскости. Требуется определить, в какой координатной четверти они лежат. Вводятся 2 целых, не равных нулю числа, по модулю не превосходящие 30 000: координаты точки плоскости (x, y). Выведите номер координатной четверти, в которой лежит эта точка (1, 2, 3 или 4).
6. Поле шахматной доски определяется парой натуральных чисел, каждое из которых не превосходит 8. По введенным координатам двух полей (k,?l) и (m, n) выясните, угрожает ли ферзь, находящийся на поле (k,?l), полю (m, n)?
На вход программе подаются 4 целых числа: k, l, m и n. Выведите YES или NO в зависимости от ответа на вопрос задачи.
Пример входных данных | Пример выходных данных |
1 1 2 2 | YES |
1 1 2 3 | NO |
7. Поле шахматной доски определяется парой натуральных чисел, каждое из которых не превосходит 8. По введенным координатам двух полей (k,?l) и (m, n) выясните, являются ли эти поля полями одного цвета?
На вход программе подаются 4 целых числа: k, l, m и n. Выведите YES или NO в зависимости от ответа на вопрос задачи.
Пример входных данных | Пример выходных данных |
1 1 2 2 | YES |
1 1 2 3 | NO |
8. По введенному номеру года — положительному целому числу, не превосходящему 10 000, требуется определить, является ли данный год високосным. Напомним, что високосными являются года, номера которых кратны 4, но не кратны 100, а также года, номера которых кратны 400. Выведите YES или NO в зависимости от ответа на вопрос задачи.
Пример входных данных | Пример выходных данных |
2007 | NO |
2000 | YES |
9. Узник замка Иф.
За многие годы заточения узник замка Иф проделал вилкой в стене прямоугольное отверстие размером D x E. Замок Иф сложен из кирпичей размером A x B x C. Узник хочет узнать, сможет ли он выкидывать кирпичи в море из этого отверстия, для того чтобы сделать подкоп. Помогите ему, считая, что стороны кирпича будут параллельны сторонам отверстия.
На вход программе подаются 5 чисел: A, B, C,
D, E. Все числа натуральные, не превосходящие 10 000. Выведите YES или NO в зависимости от ответа на вопрос задачи.
Пример входных данных | Пример выходных данных |
1 1 1 1 1 | YES |
2 2 2 1 1 | NO |
10. Даны три натуральных числа — длины сторон треугольника. Определите, существует ли треугольник с такими сторонами, и если “да”, то определите его тип (остроугольный, тупоугольный, прямоугольный).
На вход программе подаются 3 натуральных числа, не превосходящих 10 000. Необходимо вывести одно из слов: rectangular — для прямоугольного треугольника, acute — для остроугольного треугольника, obtuse — для тупоугольного треугольника или impossible , если входные числа не образуют треугольника.
Пример входных данных | Пример выходных данных |
3 4 5 | rectangular |
1 2 3 | impossible |
11. Решить в действительных числах уравнение ax 2 + bx + c = 0.
На вход программе подаются a, b, c (a, b, c целые, по модулю не превосходят 100). Выдать код ситуации и значения корней:
- –1 — бесконечное множество решений;
- 0 — нет действительных корней;
- 1 — уравнение вырождается в линейное, выдать x;
- 2 — уравнение квадратное, два различных корня, выдать x1 и x2;
- 3 — уравнение квадратное, кратный корень, выдать x.
Значения корней выводить с двумя знаками после десятичной точки.
Пример входных данных | Пример выходных данных |
0 0 0 | -1 |
1 -2 1 | 3 1.00 |
Задачи повышенной сложности
1. На столе лежат коробка размера A1 x B1 x C1 и коробка размера A2 x B2 x C2. Выясните, можно ли одну из этих коробок положить в другую, если разрешены повороты коробок вокруг любого ребра на угол 90?.
Первая строка входных данных содержит три целых числа: A1, B1 и C1. Вторая строка входных данных содержит три целых числа: A2, B2 и C2. Все числа положительны и не превосходят 1000.
Если коробки одинаковы, выведите
Boxes are equal
Если первая коробка может быть положена во вторую, выведите
The first box is smaller than the second one
Если вторая коробка может быть положена в первую, выведите
The first box is larger than the second one
В остальных случаях выведите
Boxes are incomparable
Пример входных данных | Пример выходных данных |
1 2 3 |
2. Яша плавал в бассейне размером N x M метров и устал. В этот момент он обнаружил, что находится на расстоянии x метров от одного из длинных бортиков (не обязательно от ближайшего) и y метров от одного из коротких бортиков. Какое минимальное расстояние должен проплыть Яша, чтобы выбраться из бассейна на бортик?
На вход программе подаются 4 натуральных числа: N, M, x, y (N M), разделенные пробелами. Все числа не превосходят 100. Требуется вывести одно число — минимальное расстояние, которое должен проплыть Яша, чтобы выбраться на бортик.
Пример входных данных | Пример выходных данных |
10 25 7 8 | 3 |
3. Узник замка Иф-2.
За многие годы заточения узник замка Иф проделал вилкой в стене прямоугольное отверстие размером D x E. Замок Иф сложен из кирпичей размером
A x B x C. Узник хочет узнать, сможет ли он выкидывать кирпичи в море из этого отверстия, для того чтобы сделать подкоп. Помогите ему, считая, что стороны кирпича могут произвольно располагаться относительно сторон отверстия.
На вход программе подаются 5 чисел: A, B, C, D, E. Все числа натуральные, не превосходящие 10 000. Выведите YES или NO в зависимости от ответа на вопрос задачи.
Пример входных данных | Пример выходных данных |
1 1 1 1 1 | YES |
2 2 2 1 1 | NO |
4. По координатам трех точек на плоскости требуется определить их взаимное расположение.
На ввод программе подаются 6 чисел: x1, y1, x2, y2, x3, y3. Все числа целые, по модулю не превосходят 100. Они задают 3 точки плоскости: a(x1, y1), b(x2, y2), c(x3, y3). Следует определить взаимное расположение точек и выдать на экран код ситуации:
0 — 3 точки совпадают;
1 — ровно 2 точки из трех совпадают;
2 — точки не совпадают, лежат на одной прямой;
3 — точки образуют остроугольный треугольник;
4 — точки образуют прямоугольный треугольник;
5 — точки образуют тупоугольный треугольник.
Постарайтесь использовать как можно меньше логических операций (операций сравнения и логических связок).
Пример входных данных | Пример выходных данных |
1 1 2 2 3 3 | 2 |
1 2 1 2 1 2 | 0 |
5. Задана система двух линейных уравнений относительно x и y:
Требуется решить данную систему. На вход программе подаются 6 чисел: a, b, c, d, e, f (все числа целые, по модулю не превосходят 100; обратите внимание, что сначала вводятся значения a, b, c, d, а потом e и f). Выдать на экран описание решения в следующем виде:
- 0 — решений нет.
- 1 — решение имеет вид y = kx + b, k 0.
- 1X c — решение представляет собой пары вида
(x, c), c фиксированно, x любое. Вывести с с точностью до двух знаков после десятичной точки. - 1Y с — решение представляет собой пары вида
(c, y), c фиксированно, y любое. Вывести с с точностью до двух знаков после десятичной точки. - 2 x y — решение системы единственно, вывести x и y с точностью до двух знаков после десятичной точки.
- 2XY — любая пара (x, y) является решением данной системы.
1X 0.50
Урок 5
Цикл с предусловием
Многократно повторяемые действия могут быть заданы с помощью оператора цикла. Рассмотрим синтаксическую диаграмму одного из таких операторов — оператора цикла с предусловием:
Выполнение оператора цикла сводится к повторному выполнению оператора S (тела цикла), пока значение логического выражения B истинно (до тех пор, пока оно не станет ложным). Фактически подобные операторы цикла реализуют повторное выполнение условных операторов if B then S, пока истинно условие B. Если выполняемый оператор не изменяет значения переменных, входящих в условие, то условие будет истинным всегда и цикл будет выполняться вечно, при этом говорят, что программа зацикливается. Если же при первой проверке условия оно сразу оказывается ложным, то оператор цикла не выполняется вообще.
Если в цикле нам необходимо выполнять больше чем один оператор, то, как и в случае с условным оператором, применяется составной оператор, то есть несколько операторов заключаются в операторные скобки begin … end .
Пример оператора цикла с предусловием:
Если до оператора цикла значение х положительно, то цикл не будет выполняться вообще. Если х было равно 0, то оператор цикла будет выполняться ровно один раз, а если х было меньше 0, то оператор цикла выполнится несколько раз и закончится, когда х станет равным 1.
Пример 1. По заданному целому неотрицательному значению n, не применяя формулы, вычислить
s = 1 + 2 + 3 + 4 + . + n:
Пример 2. С клавиатуры вводятся натуральные числа. Последовательность этих чисел заканчивается нулем (в данном случае 0 — признак окончания ввода). Найти их сумму:
while a <> 0 do
Для того чтобы эта программа работала, числа надо набирать или в одной строке, разделяя их пробелами, или — каждое в новой строке. Если не набрать в качестве одного из чисел 0, то программа не закончится. Обратите внимание, что если первое же число будет нулем, то цикл выполняться не будет.
Цикл с постусловием
В языке Pascal существует еще один оператор цикла с условием, которое проверяется уже после выполнения оператора. Приведем его синтаксическую диаграмму:
В данном операторе слова repeat и until служат операторными скобками и begin end использовать не требуется. На первом шаге цикла операторы, заключенные между repeat и until , выполняются в любом случае, дальше же цикл будет повторяться, пока значение булевского выражения ложно. То есть цикл закончится, когда оно станет истинным. В отличие от цикла с предусловием здесь В — это условие окончания цикла.
Пример 3. Решить задачу из примера 2 с помощью цикла с постусловием:
until a = 0;
Здесь на последнем шаге к значению суммы прибавляется нулевое значение, что ее не меняет.
Задачи
1. По заданным вещественному значению x и целому значению n вычислите x n (операция возведения в степень в языке Pascal отсутствует). Для решения задачи используйте последовательное домножение результата на x.
На вход программе подаются вещественное x, по модулю не превосходящее 10, и целое n, по модулю не превосходящее 20. Выведите значение x n с точностью до трех цифр после десятичной точки.
Пример входных данных | Пример выходных данных |
2 10 | 1024.000 |
2 -3 | 0.125 |
2. Найдите сумму цифр введенного целого числа. (На каждом шаге выделяется последняя цифра числа, а затем число делится на 10. Процесс повторяется, пока число не станет равным 0.)
На вход программе подается целое неотрицательное число n 10 9 . Выведите сумму его цифр.
Пример входных данных | Пример выходных данных |
1234 | 10 |
5 | 5 |
3. На вход программе подается натуральное число n 10 9 . Проверьте, является ли оно простым. Выведите YES или NO в зависимости от ответа на вопрос задачи. Максимальное время работы программы на одном тесте — 0,1 секунды.
Пример входных данных | Пример выходных данных |
13 | YES |
10 | NO |
4. На вход программе подается натуральное число n 30 000. Выведите количество делителей числа n, включая 1 и само число n.
Пример входных данных | Пример выходных данных |
13 | 2 |
10 | 4 |
5. Найдите все целочисленные решения уравнения ax 3 + bx 2 + cx + d = 0 и выведите их в произвольном порядке. На вход программе подаются 4 целых числа:
a, b, c и d, по модулю не превосходящие 10 9 , a 0. Максимальное время работы программы на одном тесте — 1 секунда.
Указание. При d 0 все корни уравнения, отличные от 0, являются делителями числа d. Для вычислений используйте схему Горнера 4 .
Пример входных данных | Пример выходных данных |
1 1 1 -1 | 1 |
6. На вход программе подается натуральное число n 10 9 . Проверьте, можно ли представить его в виде суммы двух квадратов натуральных чисел. Выведите YES или NO в зависимости от ответа на вопрос задачи. В случае положительного ответа во второй строке выведите два числа, сумма квадратов которых равна n. Числа следует выводить в порядке неубывания. Максимальное время работы программы на одном тесте — 0,1 секунды.
Пример входных данных | Пример выходных данных |
100 | YES |
7. Вкладчик положил на банковский счет n рублей. Каждый год на сумму вклада начисляется k процентов годовых (будем считать, что процент всегда округляется до целого числа рублей по формуле [xk/100], где x — сумма вклада на начало года). Начисленные проценты добавляются к сумме вклада. Через сколько лет сумма вклада станет не менее m рублей?
На вход программе подаются три натуральных числа: n 10 6 , k 100, m 1000 n. Выведите одно число — искомое количество лет.
Пример входных данных | Пример выходных данных |
100 10 111 | 2 |
100 1 100 | 0 |
8. Вкладчик положил на банковский счет некоторую сумму. Каждый год на сумму вклада начисляется k процентов годовых (будем считать, что процент всегда округляется до целого числа рублей по формуле [xk/100], где x — сумма вклада на начало года). Начисленные проценты добавляются к сумме вклада. Через сколько лет сумма вклада как минимум удвоится?
На вход программе подается натуральное число k 100. Выведите одно число — искомое количество лет.
Пример входных данных | Пример выходных данных |
100 10 | 8 |
9. На вход программе подаются два натуральных числа: n, m 10 9 . Выведите их наибольший общий делитель. Для решения задачи используйте алгоритм Евклида, основанный на следующем тождестве: НОД(n, m) = НОД(m, r), где r — остаток от деления n на m. Если r = 0, то m = НОД(n, m).
Пример входных данных | Пример выходных данных |
24 16 | 8 |
11 13 | 1 |
10. На вход программе подается последовательность целых чисел, заканчивающаяся 0. Выведите минимальное и максимальное значения среди чисел этой последовательности, 0 при этом не учитывается.
При решении задачи массив использовать нельзя.
Пример входных данных | Пример выходных данных |
1 -1 0 | -1 1 |
1 2 3 4 5 0 | 1 5 |
11. На вход программе подается последовательность целых чисел, заканчивающаяся 0. Выведите их среднее арифметическое с точностью до двух знаков после десятичной точки, 0 при этом членом последовательности не считается.
При решении задачи массив использовать нельзя.
Пример входных данных | Пример выходных данных |
1 -1 0 | 0.00 |
1 2 3 4 0 | 2.50 |
12. Программа получает на вход последовательность целых чисел, по модулю не превосходящих 10 9 . Признак окончания последовательности — число –2×10 9 . Программа должна определить вид последовательности — возрастающая, убывающая, случайная или постоянная.
Ответ следует выдать в следующем формате — в 1-й строке напечатать количество элементов последовательности (без учета –2×10 9 ), во 2-й строке — тип последовательности:
- SCENDING (строго возрастающая);
- WEAKLY ASCENDING (нестрого возрастающая, т.е. неубывающая);
- DESCENDING (строго убывающая);
- WEAKLY DESCENDING (нестрого убывающая, т.е. невозрастающая);
- CONSTANT (постоянная);
- RANDOM (случайная).
При решении задачи массивы использовать нельзя.
Пример входных данных | Пример выходных данных |
1 -1 -2000000000 | DESCENDING |
1 2 2 4 -2000000000 | WEAKLY ASCENDING |
1 2 -2 4 -2000000000 | RANDOM |
Урок 6
Оператор цикла с параметром
Синтаксическую диаграмму для данного оператора необходимо дополнить следующими правилами.
1. Идентификатор и оба выражения должны быть одного и того же порядкового типа. (Из изученных ранее порядковыми являются все целые типы, а также тип boolean , далее будут рассмотрены символьный и перечислимый порядковые типы.)
2. Оба выражения вычисляются до выполнения оператора цикла и впоследствии не перевычисляются.
3. Идентификатор является параметром цикла и по стандарту не должен изменяться внутри оператора цикла (данное требование стандарта поддерживается в языке Delphi). Однако изменение параметра цикла внутри цикла не противоречит синтаксису Borland Pascal, но может приводить к непредсказуемым последствиям, например, зацикливанию.
4. После окончания цикла значение параметра цикла не определено, то есть нельзя считать, что значение параметра равно значению второго выражения.
Оператор цикла выполняется так: сначала вычисляются значения выражений, обозначим их A и B. Они являются начальным и конечным значениями параметра цикла соответственно. Если для цикла с to A B, то параметр цикла последовательно будет принимать значения, равные A, A + 1, A + 2, . B. То есть цикл будет выполняться ровно B – A + 1 раз. Если A > B, то цикл не будет выполняться совсем. Если при входе в цикл с downto выполняется неравенство A B, то параметр цикла последовательно будет принимать значения, равные A, A – 1, A – 2, . B. То есть цикл будет выполняться ровно A – B + 1 раз. Если A < B, то цикл не будет выполняться совсем.
Оператор цикла с параметром следует применять, если заранее известно, сколько раз нужно выполнить некоторый оператор. Параметр цикла может являться просто счетчиком, контролирующим количество повторений оператора, а может и использоваться в самом операторе (с учетом того факта, что на каждом шаге цикла параметр цикла на 1 отличается от предыдущего своего значения).
Пример 1. По заданному целому неотрицательному значению n и вещественному значению x вычислить x n :
for i := 1 to n do p := p * x;
Пример 2. По заданному целому неотрицательному значению n вычислить n!:
for i := 2 to n do f := f * i;
Если в качестве оператора цикла необходимо использовать несколько операторов, то применяется составной оператор.
Пример 3. По заданному натуральному значению n вычислить 1 – 1/2 + 1/3 – 1/4 + . 1/n:
for i := 2 to n do
Пример 4. По заданному натуральному значению n и вещественному значению x вычислить
x + x 2 + x 3 + … + x n :
for i := 1 to n do
Задачи
1. По заданному натуральному значению n вычислить 1 – 1/3 + 1/5 – 1/7 + . 1/(2n + 1). На вход программе подается натуральное число n 10 000. Выведите значение указанного выражения с точностью 6 значащих цифр после десятичной точки.
Пример входных данных | Пример выходных данных |
1 | 0.666667 |
2 | 0.866667 |
2. В последовательности a1, a2, . an найти номер самого большого числа. На вход программе сначала подается натуральное число n 10 6 . Далее следуют n целых чисел, по модулю не превосходящих 30 000, — сами члены последовательности. Выведите номер максимального числа. Если таких чисел несколько, то выведите номер последнего из них. Нумерация чисел начинается с единицы.
Массив в программе не использовать.
Пример входных данных | Пример выходных данных |
3 3 1 2 | 1 |
3 1 1 1 | 3 |
3. Дана последовательность, состоящая из n чисел. Выяснить, сколько раз в ней встречается минимальное число. На вход программе сначала подается натуральное число n 10 6 . Далее следуют n целых чисел, по модулю не превосходящих 30 000, — сами члены последовательности. Выведите число, которое является ответом на вопрос задачи.
Массив в программе не использовать.
Пример входных данных | Пример выходных данных |
3 3 1 2 | 1 |
4 1 1 2 1 | 3 |
4. В некоторых видах спорта выступление каждого спортсмена оценивается несколькими судьями, затем из всех оценок удаляются минимальная и максимальная, а из оставшихся берется среднее арифметическое. Если максимальную или минимальную оценку поставили несколько судей, то удаляется только одна из них.
На вход программе сначала подается натуральное число 3 n 100 — количество судей. Далее следуют n натуральных чисел, не превосходящих 100, — оценки, выставленные судьями одному из спортсменов. Выведите оценку, которая пойдет в зачет данному спортсмену, с точностью до двух значащих цифр после десятичной точки.
Массив в программе не использовать.
Пример входных данных | Пример выходных данных |
3 3 1 2 | 1.00 |
4 1 1 2 1 | 1.00 |
5. По заданному натуральному числу n и вещественному x вычислить
На вход программе подаются натуральное n 100 и вещественное x, по модулю не превосходящее 10. Выведите значение указанного выражения с точностью 6 значащих цифр после десятичной точки.
Пример входных данных | Пример выходных данных |
10 0 | 1.000000 |
100 1 | 2.718282 |
6. По заданному натуральному числу n и вещественному x вычислить
На вход программе подаются натуральное n 100 и вещественное x, по модулю не превосходящее 10. Выведите значение указанного выражения с точностью
6 значащих цифр после десятичной точки.
Пример входных данных | Пример выходных данных |
10 0 | 1.000000 |
50 3.1416 | -1.000000 |
7. По заданным натуральным числам n и m вычислить
На вход программе подаются натуральные n 100 и m 100. Выведите значение указанного выражения с точностью 6 значащих цифр после десятичной точки.
Пример входных данных | Пример выходных данных |
100 2 | 2.158477 |
8. Числа Фибоначчи определяются следующими формулами: f0 = f1 = 1; fn = fn–1 + fn–2, при n 2.
На вход программе подается целое неотрицательное n 40. Выведите n-е число Фибоначчи. Массив в программе не использовать.
Пример входных данных | Пример выходных данных |
4 | 5 |
9. Дана последовательность, состоящая из n чисел. Найти в ней два самых маленьких числа. На вход программе сначала подается натуральное число n 10 6 . Далее следуют n целых чисел, по модулю не превосходящих 30000, — сами члены последовательности. Выведите минимальное число и второе по величине число (оно может совпадать с минимальным).
Массив в программе не использовать.
Пример входных данных | Пример выходных данных |
3 3 1 2 | 1 2 |
4 1 1 2 1 | 1 1 |
10. Вычислите по схеме Горнера значение полинома anx n + an–1x n–1 + … + a1x + a0 в точке x0.
На вход программе сначала подается целое неотрицательное число n 20. Затем вещественное число x0, по модулю не превосходящее 10. Далее следуют n + 1 вещественных чисел, по модулю не превосходящих 10. Выведите значение полинома с точностью до трех значащих цифр после десятичной точки.
При решении задачи массив использовать нельзя.
Пример входных данных | Пример выходных данных |
1 0 1 1 | 0.000 |
2 0.5 1 1 1 | 1.750 |
Урок 7
Вложенные циклы
Пример 1. Для заданного натурального числа n найти все тройки натуральных чисел a, b, c таких, что a + b + c = n:
for a := 1 to n — 2 do
for b := 1 to n — 2 do
Данный пример показывает, как можно сокращать количество вложенных циклов. Подумайте, почему параметры обоих циклов изменяются именно до n – 2?
Пример 2. Распечатать все трехзначные числа, в которых есть две одинаковые цифры:
for j := 1 to 9 do
for i := 0 to 9 do
for k := 0 to 9 do
if (j = i) or (j = k) or (i = k) then writeln(j, i, k);
Если порядок выводимых чисел не важен, то эту задачу можно решить и более эффективно:
for j := 1 to 9 do
writeln(j,0,0,’ ‘,j,j,0,’ ‘,j,0,j);
for i := 1 to 9 do writeln(i,i,j,’ ‘,j,i,i,’ ‘,i,j,i)
Пример 3. Распечатать все трехзначные числа, в которых вторая цифра больше первой, а третья больше второй.
for i := 1 to 7 do
for j := i + 1 to 8 do
for k := j + 1 to 9 do writeln(i,j,k);
В данном решении удалось избежать использования условного оператора.
Два последних примера показывают, что в задачах по информатике, для того чтобы получить ответ, не всегда нужно оперировать именно теми объектами, о которых идет речь в условии задачи. В этих задачах совершенно излишним было бы перебирать все трехзначные числа, выделять из них цифры и сравнивать их между собой. Более того, формировать из подходящих цифр число, только для того чтобы его распечатать, тоже не нужно: печать нескольких цифр подряд без разделителей приведет к тому, что зрительно эти цифры как раз и образуют нужное число.
Задачи
1. (Модифицированная задача из примера 1.) Для заданного натурального числа n найти все тройки натуральных чисел a, b, c таких, что a + b + c = n и a b c. Минимизируйте количество условий, которые используются в программе.
На вход программе подается натуральное число n 30 000. Выведите количество искомых троек 5 .
Пример входных данных | Пример выходных данных |
3 | 1 |
2 | 0 |
2. a) Автобусный билет считается счастливым, если в его шестизначном номере сумма первых трех цифр равна сумме трех последних цифр. Подсчитайте и выведите число счастливых билетов с различными номерами (от 000001 до 999?999).
б) Билет считается счастливым, если в его n-значном номере сумма первых [n/2] цифр равна сумме [n/2] последних цифр (при нечетном n центральная цифра в “проверке на счастье” не участвует и может быть любой). Подсчитайте число счастливых билетов с различными n-значными номерами (ведущие нули в номерах возможны, но номера, состоящего из одних нулей, не существует).
На вход программе подается натуральное n 15. Выведите количество n-значных счастливых билетов.
Пример входных данных | Пример выходных данных |
1 | 9 |
2 | 9 |
3. Определите количество различных способов выплаты сдачи в размере n рублей купюрами 10 рублей и монетами 5, 2 и 1 рубль. Так, 5 рублей можно выплатить четырьмя различными способами: 5 = 2 + 2 + 1 = 2 + 1 + 1 + 1 = 1 + 1 + 1 + 1 + 1.
Пример входных данных | Пример выходных данных |
2 | 2 |
5 | 4 |
4. Напишите программу, которая будет разлагать натуральное число n > 1 на простые множители.
На вход программе подается натуральное n 30 000. Выведите его разложение на простые множители, располагая их в порядке неубывания так, как показано в примерах.
Пример входных данных | Пример выходных данных |
5 | 5=5 |
12 | 12=2*2*3 |
5. Дано число n. Найдите число из диапазона от 1 до n с максимальной суммой своих делителей (включая непростые делители, 1 и само число). Если таких чисел несколько, выведите минимальное из них.
На вход программе подается натуральное n 10 000. Выведите искомое число.
Пример входных данных | Пример выходных данных |
5 | 4 |
12 | 12 |
6. Цифровой корень натурального числа получается следующим образом. Складываются все цифры данного числа. Процесс повторяется, пока в результате не будет получено однозначное число, которое и называется цифровым корнем числа.
На вход программе подается натуральное число n 10 9 . Выведите его цифровой корень.
Пример входных данных | Пример выходных данных |
10 | 1 |
888 | 6 |
7. Напишите программу для подсчета числа точек c целочисленными координатами, находящихся внутри и на границе круга c центром в начале координат и заданным радиусом r.
На вход программе подается целое неотрицательное число r 1 000 000. Выведите количество искомых точек в этом круге.
Пример входных данных | Пример выходных данных |
2 | 13 |
8. Экспериментальным путем определите, факториал каких чисел может быть точно вычислен в 32-битном целом типе ( integer в Delphi и longint в Borland Pascal), 64-битном целом типе ( int64 в Delphi и comp в Borland Pascal) и типе extended . Затем напишите программу, которая будет работать следующим образом.
Сначала запрашивается число K — количество факториалов, которые надо вычислить (K 100). Затем K раз считывается значение N (N 100), для очередного N сразу вычисляется значение N!, если это можно точно сделать хотя бы в одном из указанных типов данных, и выводятся в строке через пробел найденное значение факториала и число 1, 2 или 3 соответственно в зависимости от типа данных, в котором можно это значение посчитать точно (выводится минимально возможное значение). Если точно факториал в стандартной компьютерной арифметике вычислить невозможно, то выводится только 0.
Пример диалога программы:
Пример входных данных | Пример выходных данных |
3 |
9. По заданным вещественному значению x и целому неотрицательному значению n вычислите x n (операция возведения в степень в языке Pascal отсутствует). Для решения задачи используйте алгоритм эффективного возведения в степень.
Алгоритм основан на тождестве x 2n = x n x n . Тогда, если n = 2 k , то значение x n можно получить из x, домножая результат сам на себя (таким образом мы будем последовательно получать значения 2-, 4-, 8-й и т.д.
2 k -й степеней числа x). В свою очередь, произвольное n можно представить как сумму степеней двойки (фактически перевести в двоичную систему счисления):
n = 2 k1 + 2 k2 + … Соответственно, Фактически алгоритм быстрого возведения в степень сводится к последовательному получению 2-, 4-, 8-й и т.д. степеней числа x и перемножению необходимых степеней.
На вход программе подаются вещественное x, по модулю не превосходящее 10, и целое неотрицательное n, не превосходящее 100. Выведите значение x n с точностью до трех цифр после десятичной точки. Для вычислений используйте тип extended .
Пример входных данных | Пример выходных данных |
2 10 | 1024.000 |
0.5 3 | 0.125 |
10. По заданным натуральным числам n и m вычислите .
На вход программе подается натуральное m 100. Выведите значение указанного выражения с точностью 6 значащих цифр после десятичной точки (известно, что это выражение, состоящее из бесконечного числа вложенных корней, для всех указанных значений m конечно).
Пример входных данных | Пример выходных данных |
2 | 2.158477 |
Урок 8
Символьный тип данных
Помимо стандартных типов для работы с числовыми и логическими переменными, в языке Pascal существует тип для обработки переменных символьного типа. Данный тип называется char — от английского слова character — символ. Интересно, что транскрипция этого слова начинается со звука к, а не ч, так что устоявшееся в русском языке произношение названия символьного типа — “чар”, по-видимому, является некорректным и может быть непонято программистами из англоязычных стран.
Значениями символьного типа char являются элементы конечного и упорядоченного множества символов, зависящего от текущей кодовой таблицы.
В языке Pascal это множество состоит из 256 символов, пронумерованных от 0 до 255. В число этих символов входят все символы, которые вы можете получить на экране с помощью нажатия какой-либо клавиши или комбинации клавиш, а также некоторые другие символы, в том числе и невидимые. Какие именно символы являются константами данного типа, зависит от того, какая кодовая таблица используется в момент выполнения (а не написания) программы. То есть одна и та же программа, например печатающая изображение всех символов кодовой таблицы, на компьютерах с различными текущими кодировками будет иметь различные результаты работы. Обычно первые 128 символов с кодами от 0 до 127 всегда соответствуют так называемым “ASCII-символам”, а остальные 128 в различных таблицах используются для кодирования букв того или иного национального алфавита, символов псевдографики и т.п. Кроме того, первые 32 символа считаются управляющими, а остальные — изображаемыми, т.е. имеющими графическое изображение (пробел, имеющий код 32, относится уже к изображаемым символам). Управляющие символы должны восприниматься устройствами вывода и ввода текста как команды, например:
Компилятор с языка программирования может обрабатывать управляющие символы определенным в нем нестандартным образом. Например, в языке Delphi все первые 33 символа, включая пробел, считаются разделителями при вводе информации, т.е. практически любым из них можно отделять, например, числа при вводе из файла или с клавиатуры.
В тексте программы константы символьного типа записываются двумя способами. Наиболее наглядный из них — это заключение любого изображаемого символа в апострофы. Например: ‘*’, ‘F’, ‘1’. Для того чтобы таким способом представить сам символ апостроф, его записывают внутри апострофов же дважды: »» (на клавиатуре для этого надо четыре раза подряд нажать клавишу, соответствующую апострофу). Второй способ позволяет задавать любые символьные константы, в том числе и соответствующие управляющим символам, по их кодам. В этом случае обозначение константы начинается с символа ?“#”, за которым следует десятичный код (т.е. номер от 0 до 255) соответствующего символа. Например, #13 , #65 . Если же мы считываем значение символьной переменной с клавиатуры или из файла, то соответствующий символ должен быть набит уже без апострофов. А если считывается последовательность символов (текст), то они набиваются все подряд, без разделителей, так как и пробел, и другие разделители числовых констант также являются значимыми символами.
Множество символьных констант является упорядоченным так, что символ “ c1 ” считается меньше символа “ c2 ”, если код первого символа соответственно меньше кода второго. Строчные и прописные буквы являются различными символами, то есть ‘a’ <> ‘A’ , объясняется это тем, что в любой кодовой таблице каждой из них соответствует свой символ. Все строчные и прописные английские буквы, а также символы для десятичных цифр упорядочены между собой, то есть
Русские буквы одного регистра упорядочены между собой не во всех кодовых таблицах, но чаще всего это так, за исключением буквы Ё.
Символ ‘0’ в таблице ASCII имеет код 48, символ ‘A ‘ (английская) — 64.
Рассмотрим операции, применимые к переменным и константам символьного типа. Во-первых, как уже следует из сказанного выше, значения символьных переменных можно считывать, а значения символьных выражений — печатать. Во-вторых, в силу наличия отношения порядка, над символьными выражениями определены все операции отношения: , =, <>, = . Арифметические действия над данным типом не определены.
С символьным типом связаны следующие функции:
1) функция chr(i) выдает по порядковому номеру символа в кодовой таблице соответствующий символ, следовательно, на месте i может стоять целочисленное выражение, значение которого находится в диапазоне от 0 до 255; если номер является константой, можно использовать также символ «#»:#65 означает то же самое, что и chr(65) ;
2) функция ord(с) , наоборот, выдает номер символа с в кодовой таблице, здесь с — или переменная символьного типа, или символьная константа, или функция, результатом выполнения которой является символ (например, chr );
3) функция succ(с) выдает символ, следующий в кодовой таблице за символом “ с ”. Для последнего символа кодовой таблицы эта функция не определена. То есть с точки зрения данной функции символы не считаются расположенными по кругу, они имеют только линейный порядок; эта функция позволяет обрабатывать символы в циклах;
4) функция pred(с) выдает символ, предшествующий в кодовой таблице символу “ с ”. Для символа с кодом 0 значение этой функции также не определено;
5) функция upcase(с) переводит символы, обозначающие строчные английские буквы, в прописные, остальные символы (в том числе и соответствующие русским буквам) она оставляет неизменными. Например, upcase(‘f’) есть ‘ F ‘, а upcase(‘*’) есть ‘ * ‘. Обратной функции, т.е. функции, переводящей прописные буквы в строчные, в стандартной библиотеке не существует.
Забегая вперед, отметим, что при анализе констант символьного типа часто удобно использовать так называемые “множественные константы”, то есть проверку на принадлежность значения символьной переменной некоему множеству символов. Приведем примеры таких проверок, не вдаваясь в детали синтаксиса:
1) if c in [‘a’..’z’,’A’..’Z’] then writeln(‘letter’);
2) if c in [‘1′,’3′,’5′,’7′,’9’] then writeln(‘odd digit’)
Аналогичные конструкции используются и для целочисленных типов.
Перечислимый тип данных
Еще одним скалярным типом данных в языке Pascal является перечислимый тип. Данный тип задается программистом путем явного перечисления всех имен, обозначающих значения этого типа. С помощью синтаксической диаграммы порядок описания такого типа можно определить следующим образом:
В тексте программы все константы данного типа употребляются непосредственно, без апострофов. Все константы пронумерованы, согласно описанию, начиная с 0, следовательно, определены все операции отношения над переменными и константами данного типа и можно использовать функцию ord. Ввод и вывод для данного типа не допускается.
Уже знакомый вам тип boolean фактически является стандартным предопределенным перечислимым типом:
type boolean = (false, true);
Однако над выражениями данного типа определен расширенный набор операций, а также допустимо их использование в процедурах печати (однако считывание не определено).
Перечислимый тип с точки зрения идеологии программирования относится к так называемым “флаговым”, то есть различные константы одного и того же перечислимого типа используются для обозначения различных ситуаций, каждая из которых должна быть обработана в программе отдельно. Использование таких переменных вместо, например, числовых делает программу более наглядной и легко отлаживаемой.
Примеры описания порядковых типов:
type week = (mon, tues, wed, thur, fri, sat, sun);
operators = (plus, minus, times, divide);
Для того чтобы по номеру константы порядкового типа получить в программе ее значение, можно использовать имя типа:
boolean(0) означает false;
week(1) означает tues;
operators(2) означает times.
Ограниченный тип (диапазон)
Новый тип можно определить, накладывая ограничения на уже определенный ранее порядковый тип — в этом случае его называют базовым типом. Ограничение определяется заданием диапазона значений: минимального и максимального значений констант базового типа:
Допустимость операций над значениями ограниченного типа определяется базовым типом. А директива компилятора позволяет контролировать выход за границу диапазона описанных значений во время выполнения программы.
Напомним, что именно такие типы данных используются чаще всего для описания индексов у массивов. Помимо этого, они позволяют описывать данные программы более наглядным образом и контролировать грубые ошибки. Приведем примеры описания ограниченных типов:
type age = 0..120;
Порядковые типы данных
Рассмотрев ранее целые, логические, символьные, перечислимые и ограниченные типы данных, мы приходим к их обобщенному понятию — порядковые типы данных. Как уже упоминалось ранее, значения любого из таких типов могут быть упорядочены так, что компьютерное представление каждого следующего значения есть двоичное число, на единицу большее предыдущего. Перечислим все стандартные и определяемые пользователем типы, относящиеся к этой группе.
1. Все целые типы: integer, byte, shortint, smallint, word, longint (64-битный целый тип int64 в Delphi в полном смысле слова порядковым не является).
2. Логический тип boolean .
3. Символьный тип char .
4. Определяемые программистом перечислимые типы.
5. Ограниченный тип.
Над всеми порядковыми типами определены следующие функции:
1) ord(a) — выдает “порядковый номер” a среди констант соответствующего типа. Для целых типов, в том числе и знаковых, это будет само число, для остальных — номер в нумерации значений типа, начиная с нуля. Данная функция, по сути, позволяет производить преобразование любого порядкового типа в числовой, что иногда очень удобно при решении задач;
2) succ(a) — выдает следующее по порядку значение за значением а (не определена для максимального значения типа);
3) pred(a) — выдает предшествующее значению а значение (не определена для минимального значения типа);
4) получение по номеру элемента типа: (i) , по-другому это называют приведением к типу.
Переменные любого порядкового типа можно употреблять в качестве параметров цикла for . То есть в цикле можно перебирать значения не только числовых, но и символьных, логических и других параметров порядкового типа. Кроме того, для обработки различных значений порядковых типов в языке Pascal определен так называемый “оператор варианта” — case . Рассмотрим его подробнее.
Оператор варианта case
Данный оператор представляет собой естественное расширение условного оператора. Оператор варианта состоит из выражения порядкового типа и нескольких операторов, каждому из которых предшествует список констант того же типа, что и выражение. Оператор всегда начинается словом case и заканчивается словом end :
else оператор4
Приведенная схема не есть точное описание оператора, а лишь демонстрация нескольких случаев комбинации констант (полная синтаксическая диаграмма данного оператора слишком громоздка). Порядок употребления констант произвольный, но они не должны повторяться. Выполняется оператор так. Сначала вычисляется значение выражения, затем среди констант ищется равная значению выражения, и выполняется соответствующий оператор. Если соответствующая константа не найдена, то выполнится оператор, стоящий после слова else , а если это слово также отсутствует, то не будет делаться ничего, и программа перейдет к выполнению следующего оператора.
Приведем примеры нескольких различных операторов варианта:
1) case n mod 7 of
2) case c of
Формат протокола¶
Где ACCOUNT — код вашего аккаунта (совпадает с основным логином).
Для вызовов, не требующих аккаунта (например, ping), используйте знак минус ‘-‘.
Транспорт — https — HTTP 1.0/1.1 с GOST2012/GOST8912 — используйте хост apigost.sendsay.ru
Возможно ГОСТ-шифрование всего канала cвязи — свяжитесь со Службой поддержки.
Рекомендуемые расширения — SNI
Имя api.sendsay.ru имеет несколько ip-адресов. При невозможности соединения с каким-то из этих адресов необходимо повторять запрос с использованием других.
Метод вызова¶
Метод вызова — POST — RFC 2616 section 5 https://tools.ietf.org/html/rfc2616#section-9.5
Максимальный размер запроса — в настоящий момент 400 Мбайт. Если вам этого недостаточно, свяжитесь со Службой поддержки.
Content-Type: запроса — application/json
Содержимое запроса — JSON-строка в кодировке UTF-8.
Описание url-кодирования, применяемого в некоторых случаях, доступно в RFC 3986 https://www.rfc-editor.org/rfc/rfc3986#section-2.1
Описание формата JSON доступно в RFC 7159 http://tools.ietf.org/html/rfc7159
Не забывайте кодировать символы, которые не могут быть непосредственно записаны в JSON.
«Красивое» форматирование пробелами совершенно не обязательно и его отсутствие может заметно уменьшить размер вашего запроса, что увеличит скорость его обработки.
Настоятельно рекомендуется пользоваться готовыми функциями вашего языка программирования для перевода структуры данных в json-строку.
Обширная практика Службы поддержки показывает, что самостоятельная реализация json-кодирования может привести к значительной переоценке своих навыков программирования в строну уменьшения и последующей депрессии на этой почве.
Дополнительные параметры запроса¶
- request.id — дополнительный параметр для идентификации запроса со стороны клиента и облегчения изучения случаев, требующих обращение в Службу поддержки.
Он никак не анализируется (за исключением описанного ниже) и просто возвращается обратно в параметре ответа request.id.
Параметр request-id можно передать одним из трёх способов:
— в содержимом запроса
— в HTTP заголовке X-Request-ID
X-Request-ID: url-кодированный-идентификатор-запроса
Базовые лимиты_вызовов¶
5 одновременно длящихся запросов на изменение данных или расчёт статистики.
10 одновременно длящихся запросов всего.
80 запросов в секунду.
Вы можете получить api-ошибку rate_limit, HTTP код ответа 503. Тайм-аут запроса — в зависимости от отношения системы к текущему превышению лимита.
Ошибки оформления вызова¶
- double_request.id — request.id указан несколькими способами одновременно
- account_missmatch — аккаунт в url и после авторизации не совпали
Готовые библиотеки для работы¶
В данный момент доступны готовые библиотеки для языков:
Проверка request.id¶
Несмотря на то, что параметр request.id не обязателен и служит, в целом, только для облегчения отладки, есть одно его применение, которое позволяет избежать нежелательных последствий.
Если request.id не пустой и action входит в число контролируемых, то повторный вызов с таким же request.id в пределах 15 минут заканчивается сразу ошибкой repeated_request.id
issue.send issue.send.multi member.import member.import.probe member.sendconfirm
Для не транзакционного issue.send и для member.import дополнительно в obj будет повторён ответ на первоначальный запрос (например, там будет полезный параметр track.id).
Можно управлять этим временем в сторону увеличения через параметр запроса
Последовательность обработки¶
Последовательность обработки вызовов не гарантирована, так как они выполняются параллельно.
Если вам требуется твёрдая уверенность в том, что вызов Б нормально воспользуется результатами более раннего вызова А, то вы должны дождаться явного окончания вызова А и только потом посылать вызов Б.
Конкурентные вызовы изменяющие один и тот же объект настоятельно рекомендуется выполнять последовательно по одному.
Например, два вызова anketa.quest.add в случае, когда они сделаны для одной и той же анкеты и второй вызов послан до окончания первого, могут дать три разных результата:
— добавятся оба вопроса
— только первый
— только второй
Также следует помнить о порядке обработки при удалении сложных объектов. Например, если удаляемый объект ссылается на другие необходимые ему объекты и они тоже при этом должны быть удалены, то сначала следует удалить основной объект и явно дождаться результата и только после этого удалять объекты, на которые он ссылался. Иначе, при параллельной обработке может сложиться ситуация, когда вспомогательный объект не будет удалён, так как ещё будет существовать основной (вызов удаления вспомогательного объекта дошёл до обработки ранее завершения удаления основного).
Не заданные параметры api-вызова¶
Если явно не указано иное, то необязательный параметр, который служит для указания логики работы, будет трактоваться как имеющий значение 0 или логическое значение «нет», если он отсутствует или задан, но пустой.
Если явно не указано иное, то необязательный параметр, который служит для указания текстовых строк, будет трактоваться как имеющий пустое значение, если он отсутствует.
Представление чисел¶
Как при вызове, так и при ответе, параметр, имеющий численное значение, может быть представлен в любом из двух видов:
— число как json-число — 123
— число как json-cтрока — «123»
Представление дат¶
Временная зона всех дат — MSK (MSD, если летнее время опять вернут).
Даты принимаются и возвращаются в виде строки в формате с точностью до секунд.
YYYYY-MM-DD hh:mm:ss
YYYY — год
MM — месяц
DD — день
hh — час
mm — минута
ss — секунда
Лидирующие нули не обязательны («2019-5-31 17:7:4»)
Параметры с типом «дата» имеют пометку их точности, составленную из первых букв старшего и младшего полей, например:
Ys — от года до секунды, формат «YYYYY-MM-DD hh:mm:ss»
Yh — от года до часа, формат «YYYYY-MM-DD hh»
YD — от года до месяца, формат «YYYYY-MM-DD»
Ответ¶
Ответ выдаётся в формате JSON и кодировке UTF-8
http-статусы¶
При нормальном развитии событий ответ 200.
Необходимо уметь обрабатывать ответы 3xx, которые возможны при работе по HTTP.
Все прочие статусы должны трактоваться как неизвестная ошибка исполнения запроса.
Синхронность¶
Если иного не описано, то вызов является синхронным — запрошенное действие будет выполнено (или не выполнено при ошибке) к моменту ответа на вызов.
Если вызов помечен как асинхронный, то успешный ответ обозначает, что запрошенное действие принято и будет выполнено позже в порядке обработки очереди запросов на такое же действие.
Асинхронный вызов возвращает track.id — номер трекера для отслеживания с помощью track.get
Общие поля ответа¶
Нормальный ответ¶
Формат ответа при ошибке¶
При наличии ошибки (ошибок), препятствующих полному или частичному выполнению запроса в ответе, появится массив errors со списком описаний каждой ошибки.
Обратите внимание, что в зависимости от вызова и самой ошибки, поле explain может быть не только строкой, но и массивом, и объектом.
Часть вызовов может возвращать массив warnings аналогичный структуры для того, чтобы сообщить о событиях, помешавших выполнить вызов в какой-либо его части, но не позволяющих считать, что вызов ошибочен.
< ."errors" : [ < "id" : "код ошибки-1" ,"explain" : "возможное более развёрнутое описание-1" ,> , < "id" : "код ошибки-2" ,"explain" : "возможное более развёрнутое описание-2" ,> . ] >
Специальный ответ «Смена пароля»¶
Получение ответа с ошибкой «error/auth/failed» и уточнением «force_change_password» означает, что для продолжения работы требуется сменить пароль с помощью данной комбинации login/sublogin.
Это может быть вызвано как автоматическими событиями (например истёк срок действия пароля), так и прямой установкой такого требования через вызов user.set или sys.password.set
Для продолжения работы необходимо:
- Сменить пароль, используя вызов user.set с разовой авторизацией
- Повторить вызов, в ответ на который получено «force_change_password», заново, так как он не был выполнен. Возможно при этом потребуется получить новую сессию.
< ,"errors" : [ < "id: : "error/auth/failed" ,"explain" : "force_change_password" >] >
Кэширование¶
Часть вызовов поддерживает кэширование ответов, что позволяет быстрее получать ответ, если вы уверены, что данные не изменились, и не придумывать свою собственную систему кэширования. В данный момент это вызовы stat.uni и member.list.count.
Кэширование применяется только для вызовов, которые завершились без ошибок.
Для использования кэширования в вызове передаётся параметр cache с как минимум значениями mode и key.
В ответ вызова, использующего кэширование с режимами «use», «fetch» и «refresh», будет добавляться параметр cache с информацией о результате использования кэша.
- всегда в режиме «use» — так как реальную работу проделывает и общается с кэшем фоновый процесс
- в режиме «fetch» — при наличии данных в кэше, так как тоже будет вызван фоновый процесс
Если вызов асинхронный, то при режиме «fetch» и при отсутствии данных, основной вызов сразу завершится с hit == 0, а асинхронная часть даже не начнётся и её действия не будут выполнены. Проверяйте на наличие hit и его равенство 0 для установления факта не вызова асинхронной части.
В ответ на «refresh»:
При отсутствии данных в кэше в ответе на «use» и «fetch» будет:
При использовании данных из кэша в ответе на «use» и «fetch» будет:
Несколько запросов за один вызов¶
Параметры аутентификации session и one_time_auth работают только в основном запросе и игнорируются во вложенных.
Вызовы login и logout во вложенных запросах приводят в ошибке.
Запросы выполняются последовательно.
Запросы изолированы друг от друга и ничего не знают о результатах работы своих соседей. Т.е. схема «в одном запросе создать объект, а в следующем его изменить» в общем случае работать не будет.
Вы можете получить ошибку о слишком большом расходе памяти, если рассчитываете несколько статистических запросов в одном batch — выделяемая память переиспользуется между запросами, но не освобождается — суммарный её расход в какой момент может превысить предел.
< ,"result" : [ < один ответ >, < другой ответ >. ] >
Проверка доступности и авторизации¶
Эти вызовы позволяют проверить, правильно ли вы работаете с API и авторизацией.
Пинг без авторизации¶
< ,"pong" : "что-то, более-менее каждый раз разное" >
Пинг с авторизацией¶
< ,"ping" : "что-то, более-менее каждый раз разное" >
Возвращаемое значение¶
Часть вызовов имеет возможность указать, что результат их работы можно сохранить как отчёт или загрузить на клиентский сервер.
Такие вызовы поддерживают необязательный параметр result, содержащий один или несколько способов использования результата.
,"result" : [ < "type" : . способ-сохранения-результата-1 >, < "type" : . способ-сохранения-результата-2 >. ]
Если параметр отсутствует, задан как пустой скаляр или задан как пустой массив, то по умолчанию выбирается значение «response».
Если запрошенное действие «response» или «none», то работа вызова происходит синхронно, и его результат возвращается сразу в ответе.
Иначе вызов возвращает track.id — номер запроса для отслеживания с помощью track.get, а само действие производится асинхронно.
Возможные действия с результатом приведены ниже.
Во всех случаях использования http(s)/ftp(s) ссылок в них работает кастомизация текущим временем или случайным числом как описано в разделе «Кастомизированные ссылки». Такая же кастомизация работает для параметра filename. Таким образом, при использовании вызовов в «Действиях по расписанию» имеется возможность получать каждый раз разные ссылки и имена файлов.
Везде, где можно указать format, можно указать для него необязательные параметры:
— compress — zip, bzip2, gzip или пусто (не сжимать). По умолчанию не сжимать для xlsx и сжимать zip для csv, html и json.
— separator — разделитель полей для формата csv. По умолчанию — запятая, игнорируется для других форматов.
— always_quote — 0 или 1 — всегда обрамлять значение каждой ячейки для формата csv. По умолчанию — 0 — нет, игнорируется для других форматов.
— utf8 — 0 или 1 — использовать ли utf-8 как кодировку данных для формата csv. Игнорируется для других форматов.
Форматы csv и xlsx исторически созданы с расчётом на одно значение (число, строка, пусто) в ячейке. Если же значением ячейки является массив или хэш, то они будут закодированы в json-строку.
Для csv по умолчанию, для аккаунтов открытых до 28 февраля 2018 года используется windows-1251 (и включить utf-8 можно указав «utf8»:1). Для аккаунтов, открытых с 28 февраля 2018 года по умолчанию используется кодировка utf-8 (вернуть windows-1251 можно, указав «utf8»:0). Рекомендуется всегда использовать utf-8, так как, как минимум, в интернациональных email могут быть символы, не представленные в windows-1251, не говоря уже о данных подписчика.
Кодировка всех остальных форматов отчётов — utf-8.
Отправить результат на электронную почту¶
После вычисления результата на адреса, указанные в массиве to, высылается письмо с прикреплённым файлом.
Название файла задаётся в необязательном параметре filename, а при его отсутствии генерируется автоматически.
Формат файла задаётся в необязательном параметре format, а при его отсутствии используется csv.
Можно использовать черновик выпуска для настройки содержимого письма и указать его номер в необязательном параметре draft.
< "type": "email_file", "to" : [ , . ], "draft": , "filename": , "format":>,
Сохранить в Отчёты¶
После вычисления результата он сохраняется в хранилище отчётов.
Срок хранения файла — 90 дней, после чего он автоматически удаляется.
Название файла задаётся в необязательном параметре filename, а при его отсутствии генерируется автоматически. Название файла в дальнейшем доступно в результатах отслеживания запроса через track.get
Формат файла задаётся в необязательном параметре format, а при его отсутствии используется csv.
< "type": "save", "to": , "format":>,
Загрузить на внешний ресурс пo http(s)¶
После вычисления результата он передаётся по ссылке указанной в to.
Если to не указан, то используется адрес владельца аккаунта.
Для загрузки по http(s) используется метод POST с типом multipart/form c именем переменной, указанным в name (необязательно, по умолчанию «file») и именем файла указанным в filename (необязательно, по умолчанию генерируется автоматически).
Формат файла задаётся в необязательном параметре format, а при его отсутствии используется csv.
< "type": "url_file", "to" : , "name" : "", "filename": , "format":>,
Загрузить на внешний ресурс пo ftp(s)¶
После вычисление результата он загружается по ссылке, указанной в to.
Для загрузки по ftp(s) указывается сервер и каталог на сервере (параметр to), в который загружается файл с именем, указанным в filename (не обязательно, по умолчанию генерируется автоматически).
Формат файла задаётся в необязательном параметре format, а при его отсутствии используется csv
< "type": "url_file", "to" : , "filename": , "format":>
Отправить уведомление на электронную почту¶
После вычисления результата на адреса, указанные в массиве to высылается письмо с уведомлением об окончании расчёта.
Если to не указан, то используется адрес владельца аккаунта.
Обратите внимание, что сам результат в письме не содержится и его получение должно быть предусмотрено отдельно (email_file,save,url_file).
Можно использовать черновик выпуска для настройки содержимого письма, указав его номер в необязательном параметре draft.
< "type": "email_notify", "to" : [ , . ], "draft": >,
Отправить уведомление по sms¶
После вычисления результата на номера телефонов, указанные в массиве to, высылается сообщение с уведомлением об окончании расчёта.
Обратите внимание, что сам результат в письме не содержится и его получение должно быть предусмотрено отдельно (email_file,save,url_file).
Уведомить по внешней ссылке¶
После вычисления результата вызывается ссылка, указанная в to (методом GET).
Обратите внимание, что сам результат в вызове не содержится и его получение должно быть предусмотрено отдельно (email_file,save,url_file).
Вернуть в ответе¶
Результат вычисляется синхронно и возвращается в ответе.
Это действие по умолчанию. Для его использования просто ничего не указывайте.
Это действие предназначено для работы интерфейсов взаимодействия с человеком.
Хотя его и получится использовать при интеграции работы с API автоматических систем, но запросы могут быть автоматически прекращены системой по разным критериям (например, длительность выполнения).
Рекомендуется в случаях автоматизированного взаимодействия использовать схему работы с асинхронным получением ответа через запрос с сохранением результата в отчёты и последующим забором отчёта по готовности (можно определить по трекеру или получив callback) или с отправкой результата по готовности на ваш url.
Не возвращать¶
Это действие имеет смысл только для вызова Универсальной статистики при задании пересчёта кэша и позволяет сократить размер ответа.
Защищённые экземпляры сущностей¶
Большинство сущностей поддерживают защиту от изменения и удаления.
Такие сущности имеют свойство protected .
Оно принимает значения: 0 — не защищено, по умолчанию, 1 — защищено пользователем, -1 — защищено системой
При protected = 1 для изменения или удаления экземпляра необходимо в вызове передать дополнительный необязательный параметр «ignore_protection».
Значением ignore_protection должно быть значение id объекта.
Список сущностей которые поддерживают защиту:
Группы group.(
Черновики issue.draft.*
Форматы format.*
Анкета anketa.*
Формы form.*
Логины sys.user.*
Роли sys.role.*
Действия по расписанию cron.*
Триггеры sequence.*
DKIM-ключи issue.dkim.*
Адреса еmail-отправителей issue.emailsender.*
Названия sms-отправителей issue.emailsender.*
Авторизация¶
Настоятельно рекомендуется для вашей же безопасности при реализации автоматической работы по API создавать для этих целей отдельный саблогин с максимально ограниченными правами и использовать для его работы ключ API или JWT-токены, а саблогину отключить возможность работы с интерфейсом, исключив право на вызов login !
Авторизация по логину и паролю¶
Полученный в ответ идентификатор сессии должен передаваться во всех последующих запросах (кроме запросов «ping» и «login», в которых он игнорируется) как описано ниже.
Время жизни сессии несколько часов. Рекомендуется завершать явным вызовом «logout».
В случае окончания времени действия сессии вы получите ответ об ошибке авторизации, а запрошенное действие не будет выполнено.
Для продолжения работы будет необходимо:
- Получить новую сессию (автоматически или заново, запросив логины и пароль у пользователя),
- Повторить заново вызов, на котором произошла ошибка авторизации, так как он не был выполнен.
< ,"session" : "номер сессии" ,"login" : "общий логин для которого выдана авторизация" ,"sublogin" : "личный логин для которого выдана авторизация" >
Полученный в ответ идентификатор сессии должен передаваться во всех последующих запросах (кроме запросов «ping» и «login», в которых он игнорируется) или в самом запросе:
или в HTTP заголовке Authorization:
Authorization: sendsay session=идентификатор-сессии-url-кодированный
Авторизация по ключу api¶
Создайте заранее ключ api для саблогина вызовом sys.user.apikey.create.
Авторизация заканчивается c окончанием вызова и завершения вызовом «logout» не требует.
Процессы, порождённые асинхронными вызовами, продолжат работать до их естественного завершения.
Для использования ключа api укажите его:
— или в самом запросе:
— или в HTTP заголовке Authorization:
Authorization: sendsay apikey=ключ-api-url-кодированный
Авторизация c JWT¶
Требования к токену:
— поддерживаются алгоритмы RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512
— содержимое полезной нагрузки учитываемое при аутентификации
— после генерации пары приватный-публичный ключ сообщите Службе поддержки публичный в формате PEM для внесения в настройки
— пример генерации пары RSA-ключей:
> openssl genrsa -out key.pem 1024 > openssl rsa -in key.pem -outform PEM -pubout -out public.pem
— для работы с api генерируйте jwt с использованием своего приватного ключа и предпочитаемого exp
Для использования jwt-токены укажите его:
— или в самом запросе:
Передаётся в параметре apikey с приставкой «jwt:’
— или в HTTP заголовке Authorization:
Authorization: sendsay apikey=jwt:токен-url-кодированный
Авторизация AGSES-карт. Запрос¶
Авторизация биометрических карт AGSES происходит в два этапа:
1. На этапе запроса вы получаете flicker-код.
2. На этапе ответа сообщаете код, полученный клиентом от своей карты и, в случае успеха, в ответ получаете номер сессии.
< ,"flicker" : код фликера ,"hedgeid" : номер запроса >
Авторизация AGSES-карт. Ответ¶
Сессия, полученная в этом вызове точно такая же по своим свойствам, как и сессия от обычного вызова login. Храните её в надёжном, cухом, светлом месте вдали от детей.
< ,"session" : "номер сессии" ,"login" : "общий логин для которого выдана авторизация" ,"sublogin" : "личный логин для которого выдана авторизация" >
Окончание работы¶
Текущая сессия становится не действительной:
Логины и пароли в ссылках¶
Многие вызовы api могут получать данные, осуществляя доступ по http(s)/ftp(s) к сторонним серверам.
Хорошей практикой будет требовать логин-пароль при доступе к таким данным.
Однако использование стандартной для такого случая схемы записи ссылки с указанием логина-пароля прямо в ней
http://login:password@host.tld/bla/bla
хоть и, разумеется, поддерживается, но не является полностью безопасным. Например, при работе нескольких сотрудников с аккаунтом, все они смогут увидеть логин-пароль, если он указан в действиях по расписанию или в отложенных выпусках.
Создайте один раз объект «Внешняя авторизация» (вызов authext.create, type = 0, login = «метка для памяти», «token» = «логин:пароль») и используйте его номер в ссылках в виде:
http://authext:777@host.tld/bla/bla
Отслеживание асинхронных запросов¶
Список асинхронных запросов¶
Список всех или отобранных по фильтру запросов.
Информация о запросах старше двух месяцев регулярно автоматически удаляется из системы.
Информация о запросах issue.send/personal хранится ещё меньше — два дня.
По умолчанию, не выдаются запросы issue.send/personal. Для их получения явно указывайте action = «issue.send/personal».
< "list" : [ < объект как track.get для issue.send отсутствует letter->message по сравнению с track.get > . ] >
Состояние асинхронного запроса¶
< obj : < "id" : номер трекера ,"dt" : дата-время создания (YYYY-MM-DD hh:mm:ss) ,"action" : -- тип запроса "issue.send" "issue.send/personal" "stat.uni" "member.list" "member.list.count" "member.import" "member.sendconfirm" "member.update" "member.delete" "member/activate" "issue.split.create" "stoplist.add" "stoplist.delete" "stoplist.erase" "sequence.member.start" "sequence.member.pause" "sequence.member.resume" "sequence.member.stop" "email.test" "email.cleanerror" "cron/run" "sys.message" ,"status" : состояние запроса -- -7 - действие приостановлено -- -6 - действие не прошло модерацию -- -5 - действие на премодерации -- -4 - отложенное действие (например, отложенный выпуск рассылки) -- -3 - отменён -- -2 - закончился ошибкой -- -1 - закончился успешно -- 0 - принят -- 1 - запущен -- 2 - начата обработка -- 3 - сортировка -- 4 - форматирование -- 5 - генерация отчёта -- 6 - антиспам проверка -- остальное - зависит от типа запроса ,"status.dt" : дата-время установки текущего состояния (YYYY-MM-DD hh:mm:ss) ,"cron.id" : номер действия по расписанию, при выполнении действия которого появился этот трекер (null) ,"error" : код ошибки -- не обязательно -- смысл зависит от типа запроса ,"track.info" : "строка" -- дополнительная информация, переданная в вызове, создавшем трекер через параметр track.info. 1024 байта (null) ,reltype" : . ,relref" : . -- дополнительные параметры в зависимости от запроса и его состояния ,"param" : < -- === issue.send === -- === issue.send/personal === ,"group.id" : "код группы" ,"group.name" : "название группы" ,"api.request" : < . >-- оригинальный запрос на рассылку. для personal - не запоминается. для всех - без attaches. для masssending и без users.list. ,"api.request.id" : ". " -- оригинальный номер запроса на рассылку. для personal - не запоминается. -- характеристики выпуска, если они уже известны ,"issue.id" : номер выпуска ,"issue.dt" : время начала выпуска ,"issue.size" : количество sms для sms или примерный размер сообщения в байтах для других ,"issue.members" : количество получателей, для которых уже сформированы письма ,"issue.format" : "email" , "sms" , "viber", "push", "vk", "tg" ,"vknotify" ,"issue.name" : "название выпуска" ,"issue.split.id" : "номер сплит-тестирования, если это его выпуск" ,"issue.split.variant" : "номер варианта сплит тестирования" ,"issue.split.winner" : "выпуск - победитель в сплит тестировании" -- в состоянии "начата обработка" примерная информация о достигнутом прогрессе ,"eta" : < "rest" : примерное количество секунд до окончания ,"perc" : примерный процент обработки ,"dt.finished" : примерное дата-время окончания ,"dt.updated : дата-время последнего обновления информации eta >-- информация о номере письма для Транзакционных писем после завершения работы ,"letter" : номер письма -- пусто, если адресу не было отправлено письмо (например, подписчик отписался или какие-то ошибки выпуска) ,"email" : адрес получателя ,"error" : ошибка обработки если была ,"error.info" : дополнительная информация произвольной структуры об ошибке обработки -- отчёт и статистика после завершения работы для Экспресс-выпуска ,"report_file" : "название файла" -- название файла с отчётом для использования в вызове rfs.file.get -- отчёт формируется, если в выпуске были адреса с ошибкой обработки -- название предсказуемо masssending/.zip, в котором содержится файл НОМЕРВЫПУСКА.csv ,"statistic" : < "total" : всего строк ,"taked" : верных строк ,"erroneous" : строк с ошибками ,"repeated" : повторов адресов ,"only_unique" : 0|1 -- был ли выпуск запущен с запретом повторной -- рассылки по дублирующимся адресам >-- === stat.uni === "report_file" : "название файла" -- пусто до окончания запроса -- после окончания - название файла с отчётом для вызова rfs.file.get -- или пусто, если заказывалась высылка на почту ,"api.request" : < . >-- запрос, для которого появился трекер ,"api.request.id" : ". " -- номер запроса, для которого появился трекер -- === member.list === "group.id" : "код группы" -- пусто, если считалось без указания группы, -- иначе код группы, указанной для расчёта ,"group.name" : "название группы" ,"filter" : [ фильтр использованной группы или параметр group.filter ] -- если считалось по группе или по явно указанному фильтру ,"report_file" : "название файла" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >-- === member.list.count === "group.id" : "код группы" -- пусто, если считалось без указания группы, -- иначе код группы, указанной для расчёта ,"group.name" : "название группы" ,"filter" : [ фильтр использованной группы ] -- если считалось по группе ,"statistic" : < копия результата расчёта как в ответе вызова >,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >-- === member.import === "group.id" : "код группы" -- пусто, если при импорте не указывалось автосоздание новой -- или заполнение существующей группы, иначе код автосозданной -- существующей группы ,"group.name" : "название группы" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >-- отчёты и статистика после завершения работы ,"report_file" : "название файла" -- файл в формате xlsx с отчётом в хранилище отчётов, если были ошибки -- первые 1000 ошибок для просмотра человеком ,"report_file.json" : "название файла" -- файл в формате json запакованный zip с отчётом в хранилище отчётов если были ошибки -- все ошибки в машиноразбираемом виде ,"report_file.csv" : "название файла" -- файл в формате csv запакованный zip с отчётом в хранилище отчётов если были ошибки -- все ошибки в машиноразбираемом виде ,"statistic" : < "inserted" : добавлено новых адресов ,"updated" : обновлено адресов ,"economed" : без изменений (вносимые данные совпали с имеющимися) ,"erroneous" : строк с ошибками ,"unconfirmed" : новых адресов внесённых без необходимости подтверждения ,"needconfirm" : новых адресов внесённых с необходимостью подтверждения ,"repeated" : повторов адресов ,"listadd" : адреса, добавленные в группу импорта ,"datarows" : строк с данными (т.е. строк которые было было попробовано импортировать) ,"upserted" : inserted + updated ,"uniqs" : количество уникальных идентификаторов в импорте >,"api.request" : < . >-- запрос, для которого появился трекер ,"api.request.id" : ". " -- номер запроса, для которого появился трекер -- === member/activate === "group.id" : "код группы" -- код активируемой группы ,"group.name" : "название группы" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >-- статистика после завершения работы ,"statistic" : < "done : активировано адресов ,"notneed" : для какого количества адресов не требовалась активация ,"overlimit" : не активировано адресов из-за исчерпания лимита >-- === email.test === "group.id" : "код группы" -- пусто, если считалось без указания группы, -- иначе код группы, указанной для расчёта ,"group.name" : "название группы" ,"report_file" : "название файла" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >,"records" : число -- количество обработанных записей ,"method": "group | list | filter | url |stat.uni" -- для filter ,"filter" : [ filter из запроса ] -- для url ,"url" : "url из запроса" -- для stat.uni ,"query" : [ query из запроса ] -- === group.snapshot === "group.id" : "код исходной группы" -- пусто, если считается без указания группы, -- иначе код группы, указанной для расчёта ,"group.name" : "название исходной группы" "togroup.id" : "код получающей группы" ,"togroup.name" : "название получающей группы" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >,"records" : число -- количество обработанных записей ,"method": "group | list | filter | url |stat.uni" -- для filter ,"filter" : [ filter из запроса ] -- для url ,"url" : "url из запроса" -- для stat.uni ,"query" : [ query из запроса ] -- === member.sendconfirm === -- === member.update === -- === member.delete === -- === stoplist.add === -- === stoplist.delete === -- === stoplist.erase === -- === group.clean === -- === sequence.member.start === -- === sequence.member.pause === -- === sequence.member.resume === -- === sequence.member.stop === -- === email.cleanerror === "group.id" : "код группы" -- пусто, если считается без указания группы, -- иначе код группы, указанной для расчёта ,"group.name" : "название группы" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >,"records" : число -- количество обработанных записей ,"method": "group | list | filter | url |stat.uni" -- для filter ,"filter" : [ filter из запроса ] -- для url ,"url" : "url из запроса" -- для stat.uni ,"query" : [ query из запроса ] -- === issue.split.create === -- отслеживается не "создание" (как формально следует из названия), -- а процесс формирования списка получателей и назначения им того или иного варианта, -- соответственно, трекер отслеживает тестирование в состояние "подготавливается к запуску" "split.id" : "номер сплит-тестирования" ,"eta" : < в состоянии "начата обработка" примерная информация о достигнутом прогрессе >-- === cron/run === "cron.id" : "номер крона" "cron.name" : "название крона" "errors" : "количество ошибочных запусков подряд" "result" : < -- последний ответ api c ошибкой, полученной при исполнении крона, в нём интересен errors . >-- === sys.message === "text" : "сообщение от системы или Службы поддержки" > >
Интеграция¶
Для получения данных снаружи и внесения их в систему Sendsay можно использовать импорт данных (вызов member.import) или callback (настройка через sys.settings.get)
Для выгрузки данных из системы Sendsay можно использовать выгрузку данных подписчиков (вызов member.list), массовую выгрузку статистических данных (вызов stat.uni) и информирование внешней системы о событиях в реальном времени через Callback/Webhook (смотрите соответствующий раздел)
Традиционные источники¶
Используйте обычные ссылки (http, https, ftp, ftps, soap, soaps) на внешние данные для вызова member.import для импорта данных и при выпуске рассылки для формирования списка получателей.
Siebel¶
Используйте вызов member.import со схемой soap:// для импорта данных.
Google Big Query¶
Используйте вызов member.import со схемой gbd:// для импорта данных и при выпуске рассылки для формирования списка получателей.
Используйте Callback/Webhook со схемой gbd:// для передачи данных о событиях в Google Big Query.
Flocktory¶
Получите ссылку через параметр integration.flocktory вызова sys.settings.get и указывайте её в настройках Flocktory, чтобы данные передавались в Sendsay в реальном времени.
Tilda¶
Получите ссылку ссылку через параметр integration.tilda вызова sys.settings.get и указывайте её в настройках форм Tilda, чтобы данные передавались в Sendsay в реальном времени.
Можно настроить как все формы Tilda на одну и ту же ссылку, так и индивидуально каждую форму на свою ссылку.
Индивидуальный вариант лучше, так как регистрируемые адреса можно собирать в разные группы-списки и высылать им разные приветственные письма.
Дополнительные данные, получаемые от формы, запоминаются в подписчике в ключе данных tilda.названиеформы , где «название формы» это её название в Tilda.
Настоятельно рекомендуется, что бы название состояло только из символов a-zA-Z0-9, «-» и «_» — это позволит без дополнительных действий напрямую использовать такие ключи в персонализации писем.
Названия содержащие прочие символы будут нормализованы — все не буквы (любого языка) и не символы 0-9, «-» и «_» будут заменены на символ «_».
Например, данные формы с названием «Данные от клиенты» будут сохранены в ключе данных «tilda.Данные_от_клиента». Их без проблем можно будет проматривать и использовать в фильтрах, но вместо просто подстановки персонализации [% tilda.Данные_от_клиента %] придётся конструировать имя ключа данных в промежуточной переменной языка персонализации ProScipt и работать далее с ним.
Формы без названия записываются в tilda.default.
Новое заполнение формы полностью заменяет в данных подписчика старое.
amoCRM¶
Используйте вызов member.import со схемой amocrom:// для импорта данных.
Или получите ссылку ссылку через параметр integration.amocrm вызова sys.settings.get и указывайте её в настройках amoCRM, чтобы данные передавались в Sendsay в реальном времени.
Bitrix24¶
Используйте вызов member.import со схемой bitrix24:// для импорта данных.
Или получите ссылку ссылку через параметр integration.bitrix24 вызова sys.settings.get и указывайте её в настройках Bitrix24, чтобы данные передавались в Sendsay в реальном времени.
Яндекс.Маркет¶
Для использования данных о товарах из Яндекс.Маркет (формат YML) для персонализации писем воспользуйтесь интерфейсом. Или обратитесь в Службу поддержки (ask@sendsay.ru) для разовой настройки регулярного автоматического получения данных от вас.
Для тестирования разбора вашего файла или его импорта вне расписания используйте вызов cron.runonce.
Примеры использования описаны ниже в разделе подключения внешних данных.
Mail.Ru Смарт-карточки¶
Для подстановки в письмо кода смарт-карточки Mail.Ru ( https://help.mail.ru/developers/jsonld/smartcards/ ) используйте команду шаблонизатора [% mailru_smartcard(. ) %]
Обратите внимание, что в данный момент код валюты подставляется автоматически как RUB.
Значения параметров должны соответствовать требованиям Mail.Ru.
Возможны два способа передачи параметров:
[% mailru_smartcard("type", "Order", "name", "Симулякр", "offer_name", "Заказ", "order", "123-4567890-1234567", "price", "539.00") %]
[% data = < "type" =>"Order", "name" => "Симулякр", "offer_name" => "Заказ", "order" => "123-4567890-1234567", "price" => "539.00" > %] [% mailru_smartcard(data) %]
Далее описаны возможные для генерации смарт-карточки в формате «Название параметра в шаблонизаторе» => Описание параметра [ Генерируемый путь в шаблоне mail.ru ]
Счёт (Invoice)¶
Параметр «type» должен иметь значение «Invoice».
"type" => "Invoice" -- обязательная константа
"name" => Ваше краткое название для карточек ['provider', 'name']
"id" => Идентификатор вашего клиента ['accountId']
"payment" => Сумма счёта ['totalPaymentDue', 'price']
"payment_due" => Крайний срок оплаты ["paymentDue"]
"description" => Назначение платежа ["description"]
"legal_name" => Официально название компании ["provider", "legalName"]
"payment_min" => Минимальная сумма к оплате ["minimumPaymentDue", "price"]
"logo" => Ссылка на логотип компании ["provider", "logo"]
"billing_period" => Период оплаты ["billingPeriod"]
"customer_name" => Имя заказчика ["customer", "name"]
"customer_address" => Адрес заказчика ["customer", "address"]
"customer_phone" => Телефон заказчика ["customer", "telephone"]
"url" => Ссылка на заказ, продукт, файл со счётом ["url"]
"image" => Ссылка на превью ["image"]
Заказ (Order)¶
Параметр «type» должен иметь значение «Order».
"type" => "Order" -- обязательная константа
"name" => Ваше краткое название для карточек ["merchant", "name"]
"order" => Номер заказа ["orderNumber"]
"price" => Общая сумма заказа ["price"]
"offer_name" => Наименование заказа ["acceptedOffer", "itemOffered", "name"]
"legal_name" => Официальное название компании ["merchant", "legalName"]
"url" => Ссылка на корзину ["url"]
"offer_url" => Ссылка на корзину ["acceptedOffer", "itemOffered", "url"]
"offer_image" => Ссылка на превью-картинку заказа ["acceptedOffer", "itemOffered", "image"]
EmailOnAcid¶
Сервис EmailOnAcid https://www.emailonacid.com/ позволяет посмотреть, как будет выглядеть ваше письмо в разных почтовых клиентах и сервисах.
Вам необходимо создать свою учётную запись в этом сервисе.
Потом разово создать у нас внешнюю авторизацию с типом 15 — вызовы authext.*
После чего можно использовать вызов предпросмотра issue.draft.preview для получения результатов от EmailOnAcid.
Календарное событие¶
Добавление в письмо события календаря позволяет настроить письмо так, что получатель сможет легко добавить запись о событии в свой календарь.
Для подстановки в письмо события календаря используйте команду шаблонизатора [% calendar_event(. ) %]
Данная команда «визуально» ничего не меняет в письме, но добавляет в него необходимые элементы для того, чтобы совместимые почтовые системы распознали событие.
Возможна также подстановка ссылки на Google Calendar с помощью команды [% calendar_event_gc_url(. ) %]
Есть два способа передачи параметров:
[% calendar_event("name", "Важное событие", "start_date", "2020-01-01 00:00:00", . ) %]
[% ce = < "name" =>"Важное событие", "start_date", "2020-01-01 00:00:00", . > %] [% calendar_event(ce) %]
name - Название события
description - Описание события
start_date - Дата начала - YM или Ys
end_date - Дата окончания (если есть) - YM или Ys
location - Адрес места проведения события
organizer - Название организатора события
organizer_email - Email адрес организатора события
url - Ссылка на что-то связанное с событием (описание на сайте, индивидуальная страница настройки события)
Gmail Promotional Annotations¶
Для подстановки в письмо блока промо-акций Gmail используйте команду шаблонизатора [% gpa(. ) %]
Как обычно, параметры можно передать как списком, так и готовой структурой.
name - Имя отправителя
logo - https-url логотипа отправителя, не анимационное изображение 48x48
subject - Тема
discount_description - Описание предложения
discount_code - Код предложения
start_date - Дата начала действия кода YD или Ys
end_date - Дата окончания действия кода YD или Ys
promocard - промо-изображение, https-url, не анимационное изображения 538x138
Другое¶
Сообщите нам, если вам не хватает какого-либо источника. Мы изучим, как интегрировать это в систему.
Подписчики¶
Идентификация подписчика¶
Каждый подписчик имеет свой набор связанных с ним данных и идентифицируется в системе своими адресом электронной почты — email, и/или номером мобильного телефона — msisdn, и/или номером Viber — viber, и/или клиентским идентификатором — csid, и/или идентификатором регистрации — push, и/или номером регистрации ВКонтакте — vk, и/или номером регистрации в Телеграм — tg, и/или номером мобильного телефона для VK Notify — vknotify.
Именно их вы указываете в параметре, традиционно называемом «email», и в данных импортирования.
При сохранении, каждому идентификатору система назначает свой внутренний целочисленный номер. Он постоянен (даже если подписчика удалить и потом создать заново) и доступен вам как member.id.
Так как указание адреса или телефона в открытом виде не всегда допустимо, то система предоставляет клиенту две возможности по их сокрытию — «Клиентский идентификатор» и «Заменитель адреса», которые описаны ниже.
Большинство вызовов также понимают тип идентификатора «id» — системный номер уже существующего подписчика.
Набор данных, связанный с идентификатором, тоже имеет свой номер — member.dataset. Но этот номер не постоянен. Если вы создали, удалили и опять создали подписчика с одним и тем же идентификатором, то его системный номер member.id будет в обоих случаях один и тот же, а номер набора данных будет другой.
- можно было сравнить эти номера у двух разных подписчиков и таким образом определить, не объединены ли они в одного (подраздел «Мультиканальность» нижe)
- использовать его в вызове member.get для чтения разом всех подписчиков, связанных с данным набором данных (например, для отображения «Карточки подписчика)
Использование адреса электронной почты¶
Система полностью поддерживает национальные доменные имена (IDN) и национальные имена получателей. Вы можете без проблем использовать адреса не только из домена .рф (например проверка@тест.рф), но и из любых других национальных доменов (например, 企业@企业.企业), и записывать из без всяких ухищрений (типа xn--кодирования) просто как есть.
Система нормализует email, приводя их к написанию маленькими буквами (да, формально это не по стандарту, но такова практика всех почтовых систем).
Также производится проверка email-адреса на соответствие правилам RFC и правильности указания его домена верхнего уровня.
Национальные почтовые адреса по умолчанию включены для всех аккаунтов, созданных с 2016-07-26. Для ранее созданных аккаунтов возможность включается через параметр email.utf8 вызова sys.settings.set. Если к моменту включения вы уже имели в базе адреса с xn--кодированием, то обратитесь в Службу поддержки для их преобразования.
Использование номера мобильного телефона¶
Система нормализует номера телефонов к виду +7XXXYYYYYYY.
Также производится проверка номера телефона на наличие в реестре «Российской системы и плана нумерации» Федерального агентства связи.
Использование клиентского идентификатора¶
Клиентский идентификатор регистрозависим и нормализуется только удалением начальных и конечных пробельных символов. Остальное в нём — ваше дело. Для системы это просто набор символов.
Скорее всего у вас есть свой уникальный идентификатор подписчика. Если вы будете вносить его вместе с прочими данными подписчика, то сможете включать его в отчёты наряду или вместо email.
Но кроме такого простого использования вам доступен более продвинутый способ — система может следить за уникальностью вашего клиентского идентификатора при внесении и изменении данных, и вы можете указывать его в «Экспресс-выпуске» и «Транзакционных письмах» вместо реального адреса.
Возможность системы использовать клиентский идентификатор в выпуске рассылки место настоящего адреса позволяет реализовать сложные сценарии работы с рассылками без раскрытия адресов третьим лицам.
Например, по вашему поручению подрядчик собирает какие-то данные о посетителях вашего сайта и должен периодически делать по ним рассылки. Он не знает адресов ваших посетителей, а знает только их идентификаторы, что в обычной ситуации не позволит ему произвести рассылку.
Если же вы подключите в Службе поддержки возможность делать выпуски и импорты по клиентскому идентификатору, то подрядчик сможет производить «Экспресс-Выпуск» и «Транзакционные Письма» с использованием известного ему идентификатора, который система сама превратит в адрес получателя.
Также это даёт возможность импортировать данные с указанием не настоящего адреса, а вашего клиентского идентификатора.
Хранение заменителя адреса¶
Вы можете хранить в системе не настоящие email-адреса, а их заменители. Главное, чтобы по заменителю адреса вы могли однозначно понять о каком вашем подписчике идёт речь.
Во всех отчётах и данных системы будет использоваться именно заменитель.
Реальный адрес необходимо будет указывать только при выпуске рассылки (к сожалению, при использовании заменителя адреса вам будет доступен только «Экспресс-Выпуск» и «Транзакционные Письма»).
Данная возможность настраивается по обращению в Службу поддержки.
Мультиканальность¶
Одному подписчику могут соответствовать несколько идентификаторов (member.email), по которым вы получите доступ к одному и тому же набору данных (member.dataset).
Думайте об этом как о Змее-Горыныче: несколько голов (идентификаторов) с одним телом (набором данных).
В данный момент доступны идентификаторы видов: email-адрес, номер мобильного телефона, клиентский идентификатор, номер push-подписки, номер регистрации ВКонтакте, номер регистрации в Телеграм.
По какой бы голове-идентификатору вы не вели работу, с подписчиков вы получаете доступ к одному и тому же телу-набору данных.
У набора данных должен быть хотя бы один идентификатор подписчика связанный с ним (тело без головы не живёт).
Участие подписчика в группах-списках учитывается по идентификаторам подписчика. Разные идентификаторы могут быть внесены в разные группы-списки (впрочем, в одну и туже — тоже).
Совершаемые подписчиком действия (доставка письма, сообщения; чтение письма и его длительность; переход по ссылке; отписка; подтверждение внесения в базу; ошибки доставки и прочие) запоминаются за тем его идентификатором, от которого произведены эти действия.
Например, если у тела есть почтовая голова с фатальными ошибками доставки, то из email-рассылки такое тело будет исключаться, но на рассылку sms это не повлияет.
Благодаря поддержке нескольких идентификаторов у одного подписчика вам доступны разнообразные сценарии мультиканального взаимодействия с ним. Например, «Выслать письмо, а тем кто за 10 дней так и не прочёл и не сделал ни одного перехода выслать смс».
Форматы хранения¶
В данный момент имеется два формата хранения — текущий с моделью «Анкета-Вопрос-Ответ» (АВО) и новый с моделью хранения «Ключи Данных» (КД).
Формат АВО проверен временем, но имеет несколько недостатков, которые делают его непригодным для реализации сложных проектов.
Формат КД разработан как замена АВО и может быть использован в любых проектах.
Формат «Анкета-Вопрос-Ответ»¶
Формат АВО хранит данные в жестко структурированной форме «Анкет» которые состоят из «Вопросов» разных типов.
Данные о подписчике могут быть представлены только как «Ответы» на «Вопросы Анкет».
Формат АВО имеет только одно преимущество — при доступе к данным и изменении данных система следит за тем, что указаны существующие «Анкета» и «Вопрос», и проверяет соответствие данных типу «Вопроса».
Недостатки формата АВО более многочисленны и печальны:
— ограничен набор символов, которые можно хранить
— невозможно хранить несколько ответов на один «Вопрос» (массив)
— невозможно хранить структуры данных произвольной сложности — иерархия данных только двухуровневая «Анкета-Вопрос»
— в перспективе формат будет полностью заменён на КД и объявлен устаревшим
Формат «Ключи Данных»¶
(Изучите отдельную главу, описывающую ключи данных)
Новый формат КД разработан для замены форматы АВО и поддержки хранения сложных структур данных
— Данные формата АВО полностью доступны через КД
— Нет ограничения на набор хранимых данных
— Нет ограничений на сложность иерархии хранения данных и их сочетание (например, «адреса подписчика» могут представлять собой массив из объектов, хранящих структуру одного адреса по компонентам (страна, город, улица, дом, квартира, координаты), а компоненты адреса в свою очередь там же быть объектами — «координаты» это «широта» и «долгота»).
— Нет ограничений на формат данных
— У разных подписчиков по одному и тому же ключу данных можно хранить разные структуры и типы данных
— Доступ к данным в выпуске рассылки осуществляется как и прежде путём прямой записи [% anketa.ключ.данных %] или через функцию datakey()
Cистемная анкета member¶
Через системную анкету member вы можете получить дополнительную служебную информацию о подписчике.
В формате «Ключи Данных» она имеет вид:
< "member" : < -- информация от наборе данных (теле) подписчика, общая для всех его идентификаторов (голов) "create" : < "time" : "2015-09-12 18:53:39" -- дата создания (Ys) набора данных ,"host" : "1.1.1.1" -- источник создания набора данных >,"update" : < "time" : "2015-09-12 18:53:39" -- дата последнего изменения (Ys) набора данных ,"host" : "1.1.1.1" -- источник последнего изменения набора данных >,"import" : < "time" : "2015-09-12 18:53:39" -- дата последнего изменения (Ys) набора данных при импорте >-- информация о том идентификаторе (голове), через который прочитаны данные, своя для каждого идентификатора ,"addr_type" : "email" -- тип идентификатора (email, msisdn, viber, csid, push, vk, tg, vknotify) ,"email" : "test@test.ru" -- идентификатор ,"domain" : "test.ru" -- домен почтового адреса, если идентификатор email ,"id" : 1380900 -- внутренний номер идентификатора в системе ,"dataset" : 1231273891 -- внутренний номер набора данных (тело), с которым связан данный идентификатор (голова) ,"last" : < "tz" : число -- временная зона последнего клика или чтения. Если устройство подписчика определено как "Робот", то не учитывается -- хранится смещение от UTC в часах и минутах (HHMM или -HHMM), так как это число, но лидирующих нулей нет -- подходит автоматически ведомый системой источник данных для выпусков с учётом временной зоны получателя -- (вызов issue.send, параметр tz_observance) >-- информация о блокировках идентификатора (головы), через который прочитаны данные, своя для каждого идентификатора ,"haslock" : 0, -- все блокировки идентификатора в одном параметре. Может ли получать сообщения -- 0 - нет - может -- 1 - отписался - не может -- 2 - не подтверждён - не может -- 4 - имеет фатальные ошибки доставки - не может получать письма -- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указанных блокировок ,"confirm" : < -- состояние подтверждения внесения в базу "lock" : 0, -- 0 - подтверждено, 1 - нет ,"time" : "2015-09-12 18:53:39" -- дата подтверждения (Ys) ,"host" : "1.1.1.1" -- источник подтверждения >,"error" : < -- состояние ошибок доставки "lock" : 1 -- заблокирован из-за ошибок доставки (1) или нет (0) ,"date" : "2015-09-12 18:53:39" -- дата последней ошибки доставки (Ys) (удаляется при первой же успешной доставке) ,"str" : "name=test.ru type=A: Host not found" -- описание последней ошибки доставки (удаляется при первой же успешной доставке) ,"error" : 1 -- общее число ошибок доставки, произошедших подряд (устанавливается в 0 при первой же успешной доставке) ,"issue" : 123 -- выпуск последней ошибки доставки ,"letter" : 123 -- письмо последней ошибки доставки ,"lock_issue" : 456 -- выпуск приведший к блокировке ,"lock_letter" : 456 -- письмо приведшее к блокировке >,"lockremove" : 0 -- адрес отписан или в стоп-листе (1) или нет (0) -- информация об участии в сообществах ВКонктаке для подписчиков с типом vk "vk" : < "номер сообщества" : < "sub" =>"дата Ys подписки" -- подписан ,"member" => "дата Ys вступления" -- участник ,"unsub" => "дата Ys отписки" -- отписался ,"left' => "дата Ys покидания" -- покинул ,"err" => "дата Ys последней ошибки" -- ошибки доставки > > -- информация о подписчиках Телеграм для подписчиков с типом tg "tg" : < "номер бота" : < "sub" =>"дата Ys подписки" -- подписан ,"unsub" => "дата Ys отписки" -- отписался ,"err" => "дата Ys последней ошибки" -- ошибки доставки > > > >
В формате АВО анкета member содержит те же поля, но с названиями адаптированными к формату «анкета.вопрос». Например member.confirm.time
Полей member.dataset, member.last.tz member.vk.*, member.tg.* в ABO нет.
Псевдо-ключ -group»¶
Псевдо-ключ «-group» описывает участие и дату внесения идентификатора в группах списка.
Перечисляются коды только тех групп-списков, в которых состоит именно этот идентификатор.
Дата внесения — дата и время с точностью Ys внесения в группу-список.
Фактическая точность — YD, но для совместимости с возможными будущими изменениями она увеличена до Ys добавкой «00:00:00».
В фильтрах сегментов для отбора «Участвует/Не участвует в группе-списке» используйте операции «in_group» и «!in_group».
Для фильтрации по дате внесения — обычные операции сравнение и ключ данных «-group.кодгруппы».
Проверить существование подписчика¶
< "list" : < "адрес электронной почты или номер телефона" : 0|1|null -- подписчик существует (1) или нет (0) в базе, null - ошибка в адресе -- в случае невалидного адреса запись в warnigns >, ,"warnings" : [ cписок предупреждений про невалидные адреса ] >
Все подписчики с данным идентификатором¶
Одна и та же строка символов может быть использована как идентификатор подписчика для разных типов идентификаторов. Также усложняет жизнь то, что идентификаторы типа email и msisdn хранятся в нормализованном виде.
Это означает, что по строке нельзя однозначно сказать какого типа идентификатор она представляет. Например, «test@test.RU» может быть и email-адресом «test@test.ru» и идентификатором типа csid «test@test.RU».
Данный вызов позволяет получить для заданной строки все типы идентификаторов, соответствующих ей (с учётом нормализации), для подписчиков в системе.
< "list" : [ < "id" : номер подписчика-1 ,"addr_type : "тип идентификатора-1" ,"email" : "идентификатор-1" -- нормализованный >, < "id" : номер подписчика-2 ,"addr_type : "тип идентификатора-2" ,"email" : "идентификатор-2" -- нормализованный >. ] >
Cоздать подписчика / Обновить данные подписчика (КД)¶
При отсутствии адреса в базе он создаётся автоматически.
Изменяются только указанные данные.
< "action" : "member.set" ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn ,"source" : "ip-адрес оригинального запроса" -- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос ,"if_exists" : "error|must" -- не обязательно, по умолчанию существующий подписчик обновляется, а отсутствующий - создаётся -- error - ошибка при наличии подписчика в базе -- must - ошибка при отсутствии адреса в базе ,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)" -- используется только при внесении email-адресов -- действует лимит внесения без подтверждения -- подробнее описанный в вызове member.import ,"newbie.letter.confirm" : "номер шаблона информационного письма" -- высылается, если новый адрес до этого отсутствовал в базе, и внесён с необходимостью подтверждения -- если параметр пуст или отсутствует, то ничего выслано не будет -- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm -- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт -- продолжит вносить уже с подтверждением и этот параметр будет использоваться -- при внесении номеров телефонов никакие уведомления не высылаются -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации ,"newbie.letter.no-confirm" : "номер шаблона информационного письма" -- высылается? если новый адрес до этого отсутствовал в базе, и внесён с без необходимости подтверждения -- если параметр пуст или отсутствует, то ничего выслано не будет -- при внесении номеров телефонов никакие уведомления не высылаются -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации -- записываемые/изменяемые данные ,"datakey" : [ [ "ключ-данных-1", "режим-1", "новое-значение-1", "тип-1" ] ,[ "ключ-данных-2", "режим-2", "новое-значение-2", "тип-2" ] ,[ "ключ-данных-3", "режим-3", "ключ-данных-из-3", "тип-3" ] . ] -- "режим" имеет следующие значения -- режимы работы со значениями указанными непосредственно в вызове -- "set" - полностью и безусловно заменить имеющиеся данные новыми -- если значение присваивается элементу массива, и элемент ещё не существовал и не первый, то в массиве появится необходимое количество -- элементов (со значением null), предшествующих присваемому -- -- "update" - заменить имеющиеся данные новыми, только указанный ключ уже есть -- ("есть" это именно есть - null, пустая строка, пустой массив, пустой объект, находящиеся по указанному ключу - это "ключ есть"), -- иначе изменение игнорируется. Поведение при присвоении не первому элементу массива аналогично set (при условии, что замена реально была произведена) -- -- "insert" - добавить данные, только если указанного ключа ещё нет -- ("нет" это именно нет - null, пустая строка, пустой массив, пустой объект, находящиеся по указанному ключу - это "ключ есть"), -- иначе изменение игнорируется. Поведение при присвоении не первому элементу массива аналогично set (при условии, что данные реально были добавлены) -- -- "merge" - "set" по каждому ключу нового значения в существующее, а именно: -- * если имеющиеся данные - это объект и новое значение тоже объект, то каждый ключ и его величина из нового значения добавляются при отсутствии -- или его величина заменяют собой величину существующего такого же ключа в имеющихся данных, если ключ в них уже есть -- * если данных по указанному ключу нет и новое значение - объект, то новое значение создаст объект по указанному ключу -- * в других случаях вызов завершится ошибкой -- -- "merge_update" - "update" по каждому ключу нового значения в существующее, а именно: -- * если имеющиеся данные - это объект и новое значение тоже объект, то величина каждого ключа из нового значения заменяют собой величину -- существующего такого же ключа в имеющихся данных. Ключи нового значения, отсутствующие в имеющихся данных игнорируются. -- * если данных по указанному ключу нет и новое значение - объект, то новое значение будет проигнорировано -- в других случаях вызов завершится ошибкой -- -- "merge_insert" - "insert" по каждому ключу нового значения в существующее, а именно: -- * если имеющиеся данные - это объект и новое значение тоже объект, то каждый ключ и его величина из нового значения добавляются при отсутствии такого ключа в имеющихся данных. Ключи нового значения, уже существующие в имеющихся данных, игнорируются. -- * если данных по указанному ключу нет и новое значение - объект, то новое значение создаст объект по указанному ключу -- * в других случаях вызов завершится ошибкой -- -- "push" - если имеющиеся данные это массив и новое значение тоже массив, то новый данные добавляются в конец имеющегося массива -- если данных по указанному ключу нет и новое значение - массив, то новое значение создаст массив по указанному ключу -- * в других случаях вызов завершится ошибкой -- -- "unshift" - если имеющиеся данные это массив и новое значение тоже массив, то новый данные добавляются в начало имеющегося массива -- если данных по указанному ключу нет и новое значение массив, то новое значение создаст массив по указанному ключу -- * в других случаях вызов завершится ошибкой -- -- "delete" - данные будут удалены, "значение" и "тип" игнорируются и должны или отсутствовать или быть пустыми -- - если удалялся элемент массива и он был последним, то размер массива уменьшится на 1 -- - если удалялся элемент массива и он не был последним, то размер массива не уменьшится, а удаляемый элемент получит значение null -- режимы, копирующие значения из другого ключа данных -- "set.copy", "update.copy", "insert.copy", "merger_copy", "merge_update.copy", "merger_insert.copy", "push.copy", "unshift.copy" - работают аналогично -- режимам без .copy, но значением является то, что хранится в указанном в третьем элементе "ключе-данных-из". -- -- если копируемое значение не скаляр, а структура данных, то создаётся независимая копия структуры данных -- "тип" не обязателен и предназначен для контроля соответствия "нового-значения" формату данных. -- В данный момент поддерживается только тип данных "дата-время", так как неверно заданные данные этого типа могут вызвать ложные срабатывания/не срабатывания -- в фильтре групп операции сравнения дат. -- -- возможные значения "тип": -- -- отсутствует - проверки не производятся -- -- "" - проверки не производятся -- -- null - проверки не производятся -- -- "dt" - сокращение для dt:Ys -- -- "dt:LR" - производится проверка и нормализация "значения" как даты для указанного диапазона точности от L до R, -- - где L и R - символы Y M D h m s, задающие диапазон компонентов даты -- - например, "dt:Ys" - дата от года до секунды, "dt:Mh" - дата от месяца до часа -- - год должен всегда задаваться четырьмя цифрами -- - остальные компоненты - одной или двумя и они будут автоматически нормализованы до двух цифр -- - например, дата "1971-5-4 3:2:1" при типе "dt:Ys" станет "1971-05-04 03:02:01" -- -- другие значения - вызов завершится с ошибкой -- -- при указании типа данных "дата-время" кроме непосредственно даты, можно указывать время относительно текущего момента -- используется тот же синтаксис, что и в универсально статистике stat.uni -- -- current -- current - 1 month -- current:YD + 25 days -- -- в ключ данных будет записан результат вычисления времени с указанной точностью -- -- если точность указана разная одновременно и в типе (dt:YD), и в выражении (сurrent:Yh), то используется точность из выражения current -- -- если несколько ключей изменяются с использованием выражения current, то они все вычисляются от какого-то одного и того же времени, запомненного в начале вызова -- -- при импортировании все вычисления current для всех строк импорта также используют какое-то одно и то же время, запомненное в начале импорта -- -- внимательно изучите примеры в разделе "Общие замечания" -- для управления участием указанного идентификатора в группах-списках с помощью псевдо-ключа данных "-group" используйте точное указание группы "-group.КОДГРУППЫ" и: -- * режим "delete" для удаления из группы -- * режим "set" и новое значение "1" для добавления в группу -- * в других случаях вызов завершится ошибкой -- для удаления ошибок доставки используйте ключ данных "member.error.error" и режим "delete", в других случаях вызов завершится ошибкой -- для перевода подписчика в состояние "Требуется подтверждение внесения в базу" используйте ключ данных "member.lockconfirm", режим "set" и значение точно "1", в других случаях вызов завершится ошибкой -- все прочие изменения по ключам данных "member.*" и "-group.*" в данный момент игнорируются, но могут стать ошибками в будущем, лучше не делайте их -- если изменяемый ключ данных не существует, то он будет создан с учётом влияния "режима" -- если не существует часть или весь путь изменяемого ключа данных, то все отсутствующие части пути также будут созданы. -- в контексте создания не существующих частей пути, "не существует" - это действительно не существует, или существует, но равен null. -- попытки использовать объект или скалярную величину как массив приведут к завершению вызова с ошибкой -- попытки использовать массив или скалярную величину как объект приведут к завершению вызова с ошибкой -- данные или изменяются/удаляются для всех указанных ключей (если не было ошибок) или не изменяются/удаляются вообще (при любой ошибке) -- одновременное с созданием подписчика / внесением данных подписчика -- добавление к нему дополнительных идентификаторов -- аналогично последовательному вызову member.set и потом нужное число раз member.head.attach -- но при данном использовании атомарно - или все действия по созданию/внесению и присоединению -- завершаться успешно или же любая ошибка отменяет все изменения -- -- режимы head_rule -- -- error - отмена запроса с сообщением, что данный идентификатор непригоден -- none - голова остается где была, запрос возвращает предупреждение -- transplant - перенос головы от источника к приёмнику -- decapitate - удалить голову head у источника -- replace - перенести голову head от источника к приёмнику, а потом удалить голову email у приёмника -- replace_same_type - перенести голову head от источника к приёмнику, заменив ею голову приёмника того же типа, что и head (если она есть и единственная по типу). Если у приёмника нет головы того же типа, что и head, выполняется режим transplant. -- -- режим по умолчанию -- -- для multi и single: error -- для newbie: attach -- -- обработка данных при слиянии срабатывает только для head_rule (multi или single в зависимости от присоединяемого идентификатора) = replace|replace_same_type|decapitate "head_attach" : [ -- не обязательно < -- параметры аналогичны одноимённым из вызова member.head.attach "head" : "дополнительный присоединяемый идентификатор" ,"head_addr_type" : "тип дополнительного присоединяемого идентификатора ,"newbie.confirm" : "режим подтверждения" ,"head_rule": < -- параметры, определяющие обработку голов при слиянии "multi": error|none|transplant|replace|replace_same_type|decapitate -- для многоголовых пользователей "single": error|none|transplant|replace|replace_same_type|decapitate -- для одноголовых "newbie": attach|none|replace|replace_same_type - для новых, несуществующих идентификаторов (без голов) >, ,"data_rule": "обработка данных при слиянии" -- как в member.merge > . ] -- необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" -- при "1" данные возвращаются как при запросе member.get c "datakey" : "*" >
< ,"newbie" : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу ,"member" : < "id" : номер в базе, "email" : "нормализованный идентификатор", "addr_type" : "тип идентификатора" >-- если "return_fresh_obj" : "1" -- данные от запроса "member.get" соответствующего адреса >
Получить данные подписчика (ДК)¶
Обратите внимание, что в зависимости от того, что вы выбираете и имеются ли в ключе шаблоны, «данные для ключа» могут быть и скаляром, и массивом, и объектом, и null.
Обратите внимание, что значением для того, что было создано в модели АВО и называется там «вопрос с выбором» будет объект, а не массив. Ключами массива будут кода ответов, значениями — null.
Обратите внимание, что количество ошибок доставки имеет ключ member.error.error (совместимо со stat.uni), а не member.error как в АВО.
Системный ключ «member» и псевдо-ключ «-group», описывающий участие и дату внесения адреса в группах списка, описаны выше во вводной части раздела.
< -- при запросе со списком ключей ,"datakey" : < "ключ данных-1" : данные для ключа-1 ,"ключ данных-2" : данные для ключа-2 . >-- при запросе с одним ключом или с "*" ,"datakey" : данные для ключа -- при запросе "*" ,"datakey" : < данные для имеющихся ключей >-- если missing_too = 1 ,"missing" : 0|1 - нет или есть всё адрес как подписчик >
Получить набор данных (ДК)¶
Это специализированный вариант вызова member.get для чтения всех данных подписчиков, связанных с конкретным набором данных
< "dataset" => "номер набора данных" -- member.dataset ,"data" => < -- общие данные. все или только указанные в datakey >,"heads" => [ -- список номеров всех идентификаторов (member.id) связанных с этим набором данных 123 ,4567 . ], ,"head" => < -- информация о каждом идентификаторе -- данные аналогичны таким же полям системной анкеты member и описаны выше "номер идентификатора-1" => < "id" =>номер идентификатора ,"dataset" => номер набора данных ,"addr_type" => "тип идентификатора", ,"email" => "идентификатор", ,"domain" => "домен идентификатора для email" ,"haslock" => "все блокировки идентификатора" ,"lockremove" => "cостояние удаления" ,"create" => < -- информация о создании 'time' =>"дата (Ys)" 'host' => "источник" > ,"update" => < -- информация об изменении по АПИ 'time' =>"дата (Ys)" 'host' => "источник" > ,"import" => < -- информация об изменении при импорте 'time' =>"дата (Ys)" > ,"-group" => < -- участие в группах-списках >,"confirm' => < -- информация о подтверждении регистрации данного идентификатора >, ,"error" => < -- информация об ошибках доставки для данного идентификатора >,"stoplist" => [ -- нахождение данного идентификатора в стоп-листах -- cтруктура как у вызова email.get ] > ,"номер идентификатора-2' => < . >> >
Cоздать подписчика / Установить ответы подписчика (АВО)¶
При отсутствии адреса в базе он создаётся автоматически.
Изменяются только указанные данные.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error точно в «0» удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки, если таковая была.
Установка member.lockconfirm точно в «1» переводит подписчика в состояние «Требуется подтверждение внесения в базу».
< "action" : "member.set" ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn ,"source" : "ip-адрес оригинального запроса" -- если оригинальный инициатор запроса вы сами - ваш ip, иначе ip-адрес откуда вам пришёл запрос ,"if_exists" : "error|must|update|overwrite" -- не обязательно, по умолчанию существующий подписчик обновляется в режиме overwrite, а отсутствующий - создаётся. -- правила учёта есть или нет подписчик -- error - ошибка при наличии подписчика в базе -- must - ошибка при отсутствии адреса в базе -- -- правила изменения ответов анкетных данных. не действует на псевдоанкету "-group" -- update - если ответ на изменяемый вопрос уже есть, то он остаётся неизменным -- overwrite - ответ заменяется/создаётся в любом случае ,"newbie.confirm": "подписчик должен подтвердить внесение в базу (1|0)" -- используется только при внесении email-адресов -- действует лимит внесения без подтверждения -- подробнее описанный в вызове member.import ,"newbie.letter.confirm" : "номер шаблона информационного письма" -- высылается, если новый адрес до этого отсутствовал в базе и внесён с необходимостью подтверждения -- если параметр пуст или отсутствует, то ничего выслано не будет, -- но необходимость подтвердить регистрацию никуда не денется и выслать письма вы сможете позже через member.sendconfirm -- этот параметр НЕ зависит от newbie.confirm - если у вас кончился лимит внесения без подтверждения, то импорт -- продолжит вносить уже с подтверждением, и этот параметр будет использоваться -- при внесении номеров телефонов никакие уведомления не высылаются -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации ,"newbie.letter.no-confirm" : "номер шаблона информационного письма" -- высылается, если новый адрес до этого отсутствовал в базе и внесён с без необходимости подтверждения -- если параметр пуст или отсутствует, то ничего выслано не будет -- при внесении номеров телефонов никакие уведомления не высылаются -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации ,"obj" : < -- управление анкетными данными подписчика -- ank - код анкеты -- quest - код ответа -- val - значение ответа или код ответа, если вопрос с выбором из списка -- значение не указанных вопросов не меняется "ank1" : < -- установка значения ответа обычного вопроса "quest" :"val" -- установка значения ответа для вопроса с типом "дата" в зависимости от заданной в анкете точности "quest" : "YYYY-MM-DD" "quest" : "YYYY-MM-DD hh" "quest" : "YYYY-MM-DD hh:mm" "quest" : "YYYY-MM-DD hh:mm:ss" -- установка значения ответа у вопроса с множественным выбором ,"quest" : [ "val", "val", "val". ] -- установка значения ответа у вопроса с выбором одного из нескольких - всё равно массив ,"quest" : [ "val" ] -- удаление ответа ,"quest" : null >,"ank2" : < . >-- управление участием указанного идентификатора в группах-списках с помощью псевдо-анкеты -- параметр "if_exists" не влияет на эту анкету ,"-group" : < -- 0 - удалить из группы-списка -- 1 - добавить в группу-список -- участие в не перечисленных группах не меняется "id1" : "(0|1)" ,"id2" : "(0|1)" . ,"idN" : "(0|1)" >> -- необязательный ,"return_fresh_obj" : "нужно вернуть данные объекта -- да, нет ( 1 | 0 )" >
< ,"newbie" : 0|1 -- новый подписчик - 0 - уже был в базе, 1 - внесён в базу -- если "return_fresh_obj" : "1" данные от запроса "member.get" соответствующего адреса >
Получить ответы подписчика (АВО)¶
< -- ответы на вопросы анкет ,"obj" : < -- ank - код анкеты -- quest - код ответа -- val - значение ответа или код ответа, если вопрос с выбором из списка "ank1" : < -- обычный вопрос "quest" : "val" -- вопрос с множественным выбором ,"quest" : [ "val", "val", "val". ] -- вопрос с выбором одного из нескольких - всё равно массив ,"quest" : [ "val" ] >,"ank2" : < . >-- псевдо-анкета, описывающая участие в группах-списках ,"-group": < -- участие в группах-списках >> -- если missing_too = 1 ,"missing" : 0|1 - нет или есть всё адрес как подписчик >
Удалить подписчика¶
Адреса и данные реально удаляются из базы !
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием того, как и какие адреса были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
В зависимости от параметра wipe вызов работает по-разному в случае наличия у подписчика нескольких идентификаторов.
При wipe = 0 (по умолчанию)
- Если у подписчика несколько идентификаторов, то этот вызов удаляет только указанный идентификатор, не трогая сам набор данных и другие идентификаторы.
- Подписчик по указанному идентификатору удаляется полностью — удаляются и все прочие его идентификаторы и связанный с ними набор данных.
- Если удаляемый идентификатор единственный (последний), то вместе с ним удаляется и набор данных (тело без головы не живёт).
В отличии от member.head.detach возможно удаление единственного (последнего) идентификатора.
В отличии от member.head.detach генерируется триггерное событие «Подписчик удалён».
Удаление идентификатора приведёт к прекращению его обработки в триггерных последовательностях. Однако не сразу, а при очередной обработке событий, связанных с удалённым идентификатором.
Одновременно может выполняться только один такой запрос.
< "action" : "member.delete" ,"wipe" : 0|1 -- способ удаления, по умолчанию 0 -- указание подписчиков одним из способов ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn или ,"list" : [ "идентификатор подписчика" ,"идентификатор подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса универсальной статистики -- подразумевается unique = 1 ,"filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ не обязательно. условие отбора поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно >
< -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : < "адрес-1" : 0|1 -- результат удаления - 1 - удалён, 0 - нет (например, адрес ошибочен или отсутствует) ,"адрес-2" : 0|1 . >>
Объединение данных двух подписчиков¶
< "action": "member.merge", ,"email": "идентификатор подписчика" -- подписчик, получающий данные ,"addr_type": email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. не обязательно ,"head": "идентификатор подписчика" -- подписчик-источник данных ,"head_addr_type": email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора-источника. не обязательно -- параметры, определяющие обработку голов при слиянии данных ,"head_rule": none|transplant|decapitate -- действие с головами -- -- Если у подписчика-источника единственная голова, то при выполнении transplant, decapitate или replace -- перестанет существовать подписчик - будет удалено его тело т.к. у тела должна быть хотя бы одна голова -- -- none - ничего не делать -- transplant - перенести голову head от источника к приёмнику -- decapitate - удалить голову head у источника -- replace - перенести голову head от источника к приёмнику, а потом удалить голову у приёмника, указанную в email -- параметры, определяющие обработку данных при слиянии. не обязательно. -- по умолчанию -- level = 2 -- hasmiss = set - скопировать из источника ключ, отсутствующий в приёмнике -- hashas = none - не трогать ключ, имеющийся у обоих -- misshas = none - не копировать ключ, имеющийся только у источника ,"data_rule": < "level" : 2 -- уровень иерархии (>=0), для которого выполняется слияние данных -- по умолчанию - 2 (это коды вопроса в модели АВО или второй уровень элемента ключа данных) -- режимы для разных ситуаций слияния ключей данных, для которых не описаны индивидуальные режимы в dk_rule -- для случая, когда ключ есть в источнике и отсутствует в приёмнике ,"hasmiss": set|none|move -- по умолчанию set -- set -- скопировать данные из источника в приёмник -- none -- ничего не делать -- move -- скопировать данные из источника в приёмник и потом удалить из источника -- для случая когда ключ есть и в источнике и в приёмнике ,"hashas": none|delete|set|move|merge -- по умолчанию none -- none -- ничего не делать -- delete-- удалить данные из приёмника -- set -- скопировать данные из источника в приёмник -- move -- скопировать данные из источника в приёмник и потом удалить из источника -- merge -- объединить данные источника с данными приёмника -- для случая, когда ключ отсутствует в источнике и есть в приёмнике ,"misshas" : none|delete -- по умолчанию none -- none -- ничего не делать -- delete-- удалить данные из приёмника -- значения, указанных здесь ключей данных, будут обработаны в соответствие с заданным именно для них режимом "dk_rule": < "ключ-данных-1" : "режим-1", . "ключ-данных-N" : "режим-N" >> ,"return_fresh_obj" : . >
Список идентификаторов¶
Выводится список всех идентификаторов и сопутствующая им информация для указанного пользователя
< ,"list" : [ < "email" : "идентификатор пользователя" -- email, номер телефона. ,"addr_type" : "email|msisdn|viber|csid|push|vk|tg|vknotify" -- тип идентификатора -- структуры состояния головы как описано в member.get ,"has_lock" : . ,"lockerror" : . ,"confirm" : < . >,"error" : < . >> . ] >
Присоединение идентификатора¶
К уже существующему пользователю, указанному в email, присоединяется идентификатор, указанный в head.
Присоединяемый идентификатор не должен быть связан с другим существующим пользователем.
Возможно присоединение идентификаторов во время импорта пользователей.
Удаление идентификатора¶
*Идентификатор, указанный в email, удаляется от пользователя и становится более ни с кем не связан.
*Также прекращается участие указанного идентификатора в группах-списках, в которых он состоял.
*Идентификатор, указанный в email, удаляется от пользователя и становится cамостоятельным пользователем.
*За ним остаётся участие в группах-списках, в которых он состоял.
Данные подписчика и другие идентификаторы остаются за пользователем, от которого удаляется идентификатор.
Статистика по действиям (участие в выпусках, доставки, переходы, чтения и их длительность и прочее) остаётся за удалённым идентификатором в части его действий
и за пользователем, от которого удаляется идентификатор в оставшейся части.
После удаления у пользователя, от которого удаляется идентификатор, должен остаться ещё хотя бы один другой идентификатор (для удаления всего пользователя есть member.delete).
В отличии от member.delete невозможно удаление единственного (последнего) идентификатора.
В отличии от member.delete не генерируется триггерное событие «Подписчик удалён».
Возможно удаление идентификаторов во время импорта пользователей.
Замена идентификатора¶
К уже существующему пользователю, указанному в email, присоединяется идентификатор, указанный в head.
После чего идентификатор, указанный в email, удаляется от пользователя и становится более ни с кем не связан.
Этот вызов — аналог последовательного исполнения member.head.attach и member.head.detach, но является атомарным — любая ошибка полностью отменяет все изменения.
Участие подписчика в группах-фильтрах¶
Списков групп-фильтров, в которых состоит подписчик. Участие в группах-списках и так известно через member.get.
Время работы вызова ограничено 300 секундами для учёта случая, когда есть много групп-фильтров со сложными условиями.
< ,"list" : < "адрес" : [ список кодов групп-фильтров в которые адрес входит ] -- или ,"адрес" : null -- адрес не существует или синтаксически не верен >>
Список подписчиков¶
НЕ СОВМЕСТИМОЕ ИЗМЕНЕНИЕ С 17 ИЮЛЯ 2017 ГОДА — при result=response размер выдачи не более 1000 строк.
Если формат фильтра у группы group или заданный непосредственно в group.filter использует формат ДК с оператором has c параметром save, то в результатах вызова будут также результаты всех срабатываний save.
< "action" : "member.list" -- источник адресов, одно из трёх или вообще ничего (тогда по всем адресам вообще) ,"group" : "идентификатор группы" -- или ,"group.filter" : [ фильтр отбора как у group.filter.set ] -- для всех источников ,"addr_type": "тип выбираемых адресов подписчиков (email|msisdn|viber|csid|push|vk|tg|vknotify|vknotify)" -- при отсутствии определяется по типу адресов в указанной группе -- если указан, то должен совпадать с типом адресов в группе, если и та указана -- если не указан и не указана группа, то выбираются еmail-адреса ,"member.haslock" : "код" -- учёт состояния блокировки подписчика -- пусто или отсутствует - не учитывать состояние блокировки. может ли получать сообщения -- -1 - есть хоть какая-то блокировка - не может -- 0 - нет блокировки - может -- 1 - заблокирован так как отписался - не может -- 2 - заблокирован так как не подтверждён - не может -- 4 - заблокирован так как имеет фатальные ошибки доставки - не может -- прочие значения ( 3,5,6,7 ) - одновременное наличие нескольких указанных блокировок -- -- формально этот параметр можно заменить дополнительными условиями в фильтре группы, -- но его использование позволяет -- * не меняя фильтры групп, узнавать сколько в ней всего участников и сколько из них могут получать письма -- * не создавая группы, узнавать это же для всех свои адресов вообще -- * выполнять запрос быстрее по сравнению с таким же условием в фильтре группы -- формат вывода, одно из трёх или вообще ничего -- если формат вывода не используется, то выводится только идентификатор подписчика ,"format" : "идентификатор формата вывода" -- использование существующего формата -- или ,"format" : [ -- указание формата в формате Анкета-Вопрос-Ответ прямо в запросе -- специальная пара aid=member с qid=head.list позволяют получить в ответе список всех голов как в результате member.head.list < "anketa" : "код анкеты", "quest" : "код вопроса" >. ] -- или ,"format" : [ -- указание объекта Формат прямо в запросе -- запрос просто по ключу данных -- специальный ключ данных "member.head.list" позволяет получить в ответе список всех голов как в результате member.head.list < "datakey" : "ключ данных" >-- запрос по ключу из результатов работы save в условии has используемого в вызове фильтра -- результат null, если save не срабатывал или массив из результатов получения данных по -- ключу данных относительно каждого значения из результата save с указанным кодом , < "save" : "код сохранения", datakey" : "относительный ключ данных" >-- запрос значение меток из условий фильтрации , < "label" : "имя метки" >. ] ,"sort" : "коданкеты.кодвопроса" -- сортировка по указанному полю (не важно будет оно в итоговых данных или нет) -- если параметр отсутствует или пуст, то выдача идёт в неком внутреннем порядке -- сортировка по произвольной анкете/полю может резко увеличить время выполнения запроса, -- так как для его выполнения надо отсортировать всю выборку, -- но сортировка по ниже перечисленным полям практически не влияет на скорость выполнения -- member.id -- member.email - при идентификатору подписчика -- member.domain - сортировка по домену и внутри него по адресу -- - при выборке телефонов эквивалентно просто member.email -- member.create.time - дата и время создания -- member.update.time - дата и время последнего изменения данных по API -- member.import.time - дата и время последнего изменения данных подписчика при импорте ,"sort.order" : "asc|desc" -- направление сортировки asc - по возрастанию (по умолчанию), desc - по убыванию ,"result" : [ способ возврата результата. Смотрите общее описание ] -- заголовок списка -- если параметр отсутствует или пуст, то такая строка не добавляется ,"caption" : "id" -- в первой строке выводить заголовок, содержащий для каждой колонки код анкеты и вопроса -- или ,"caption" : "name" -- в первой строке выводить заголовок, содержащий для каждой колонки названия анкеты и вопроса -- или ,"caption" : [ "имя 1", "имя 2" . ] -- в первой строке выводить заголовок, содержащий собственные указанные названия ,"answers" : "decode" -- для АВО вместо кодов ответов на вопросы в выбором возвращать значения. -- неизвестные кода возвращаются как есть ,"answers" : "unroll" -- для ДК для ключей совпадающих с вопросам анкет с типом 1m или nm вместо объекта соответствуюшего -- структуре хранения таких значений возвращается скаляр с кодом ответа для 1m, и массив с кодами ответов для nm ,"answers" : "decode" -- для ДК подразумевает unroll и, далее, значениея ответов как для ABO ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно ---- дополнительные параметры запроса зависящие от result -- *НЕ СОВМЕСТИМОЕ ИЗМЕНЕНИЕ С 17 ИЮЛЯ 2017 ГОДА* -- ДО 17 ИЮЛЯ 2017 ГОДА -- для response ,"page" : "номер страницы" -- при отсутствии выдаётся весь список. Должны быть указаны оба параметра или ни одного ,"pagesize": "размер страницы" -- ПОСЛЕ 17 ИЮЛЯ 2017 ГОДА -- для response ,"page" : "номер страницы" -- при отсутствии выдаётся 1000 строк -- должны быть указаны оба параметра или ни одного -- если размер страницы больше 1000, то ошибка ,"pagesize": "размер страницы" >
< -- для result != response ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для result = response ,"order" : [ -- описание порядка колонок выводимых результатов < anketa : код анкеты ,anketa.name : название анкеты ,quest : код вопроса ,quest.name : название вопроса >. ] ,"list" : [ -- по одной записи для каждого адреса [ значения запрошенных полей в порядке, указанном в параметре ответа order ] ,[ значения запрошенных полей в порядке, указанном в параметре ответа order ] ,[ значения запрошенных полей в порядке, указанном в параметре ответа order ] . ] ,"save" : < -- только при result=response "aдрес" : < результат (если таковой был) работы save в условии has фильтра В описании фильтра формата КД описано когда и чем это полезно >> ,"label" : < -- только при result=response "aдрес" : < список сработавших меток и их значений В описании фильтра формата КД описано когда и чем это полезно >> >
Количество подписчиков¶
Расчёт быстр, если ведётся по «всем», по группам-спискам, по группам-фильтрам, состоящим из групп-списков.
Расчёт по группе-фильтру может быть долог — в зависимости от сложности фильтра и общего числа подписчиков.
По умолчанию вызов синхронный. Используйте sync = 0, чтобы сделать его асинхронным.
Для групп-сообществ ВК ответ немного другой для получения дополнительной информации про сообщество.
Если ответ может быть получен из кэша и он там есть, то ответ будет сообщен сразу и асинхронный запрос не начнётся.
< "action" : "member.list.count" -- источник адресов, одно из двух или вообще ничего (тогда по всем адресам вообще) ,"group" : "идентификатор группы" -- или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"cache" : < параметры кэширования >,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. не обязательно ,"with_minmax" : 0|1 - дополнительно вернуть информацию о минимальных и максимальных номерах подписчиков >
< -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- также будет содержать копию ответа obj -- для синхронного запроса не по сообществу ВК ,"obj" : < "total" : всего подписчиков ,"active" : количество подписчиков, которые могут участвовать в рассылках писем или смс ,"locked" : уникальное количество заблокированных - не могут быть в рассылке -- подробности по причинам блокировок (у одного подписчика может быть больше одной блокировки) ,"locked.unsubscribed" : в том числе заблокированные, так как отписались ,"locked.confirm" : в том числе заблокированные, так как не подтвердили внесение в базу ,"locked.stoplist" : в том числе заблокированные, так как находятся в стоп-листе ,"locked.hardbounced" : в том числе заблокированные, так как имеют фатальные ошибки доставки -- минимальный и максимальный номер подписчика при with_minmax :1 -- позволяет организовать перебор подписчиков не малоэффективным способом постраничным first/skip, -- а эффективным - по диапазонам member.id ,"id_min" : число | null ,"id_max" : число | null -- при подсчёте по всем подписчикам, дополнительно появляются поля ,"total.email" : всего именно email ,"total.msisdn" : всего именно телефонов ,"total.viber" : всего именно Viber-номеров ,"total.csid" : всего именно клиентских идентификаторов ,"total.push" : всего именно push-подписок ,"total.vk" : всего именно vk-подписок ,"total.tg" : всего именно tg-подписок ,"total.vknotify" : всего именно vknotify-подписок ,"active.email" : способных получать именно адреса ,"active.msisdn" : способных получать именно телефоны ,"active.viber" : способных получать именно viber-номера ,"active.push" : способных получать именно push-подписки ,"active.vk" : способных получать именно vk-подписки ,"active.tg" : способных получать именно tg-подписки ,"active.vknotify" : способных получать именно vknotify-подписки -- при подсчёте по всем и with_minmax :1 ,"id_min.email" : число | null ,"id_min.msisdn" : число | null ,"id_min.csid" : число | null ,"id_min.push" : число | null ,"id_min.umid" : число | null ,"id_min.vk" : число | null ,"id_min.viber" : число | null ,"id_min.pushapp" : число | null ,"id_min.tg" : число | null ,"id_min.vknotify" : число | null ,"id_max.email" : число | null ,"id_max.msisdn" : число | null ,"id_max.csid" : число | null ,"id_max.push" : число | null ,"id_max.umid" : число | null ,"id_max.vk" : число | null ,"id_max.viber" : число | null ,"id_max.pushapp" : число | null ,"id_max.tg" : число | null ,"id_max.vknotify" : число | null >-- для синхронного запроса по сообществу ВК ,"obj" : < "member" : участников сообщества ,"total" : имеют в ВК разрешение на получение сообщений ,"active" : доступны для рассылки vk_DDDD ,"confirmed" : подтвердили желание получать сообщения ,"locked.hardbounced" : с ошибками доставки ,"locked.unsubscribed" : отписавшиеся от сообщений ,"left" : покинувшие сообщество >>
Внесение списка подписчиков¶
Вызов предназначен для массового внесения/изменения данных подписчиков на основе данных, указанных в самом вызове или получаемых по указанной ссылке из внешних источников.
Внешние источники могут быть как традиционные (http,https,ftp,ftps,sftp), так и специальные Google Big Query, Siebel, amoCRM, Bitrix24.
Вызов member.import.probe предназначается для проверки того, что думает система импорта о ваших входных данных.
В ответ будет сообщено, как произошло авто-определение кодировки (сharset), разделителя столбцов, определилась ли первая строка данных как строка конфигурации (firstline), и каким ответом каких анкет приписаны столбцы данных.
Если вы знаете заранее ответы на эти вопросы, то можете сразу указать эти данные при вызове: тогда они будут иметь приоритет над авто-определением системы.
Вызов member.import реально импортирует данные. Описанные выше параметры будет определены автоматически, если их не указать сразу при вызове.
Вызов member.import асинхронный — получение положительного ответа означает, что задание на импорт поставлено в очередь. Это не означает успешность импорта — он может не состоятся из ошибок, возникших позже. Следить за его исходом можно по возвращаемому номеру асинхронного запроса.
Обратите внимание: Все возможные проблемы (фатальные или нет — смотрите по cannot_import), связанные именно с импортом (настройки, данные) при вызове member.import.probe сообщаются только через параметр warnings. А параметр errors служит для сообщения о проблемах вызова только с точки зрения API. При вызове же самого импорта, не фатальные ошибки остаются по-прежнему в warnings, а фатальные переносятся в errors. Это может выглядеть не логично, но это так из-за назначения вызова member.import.probe — предупредить вас о возможных ошибках, а не выполнять само импортирование.
Вызов позволяет импортировать данные модели КД при использовании источника данных в формате JSON-объект.
Вызов member.import сохраняет отчёты о строчках, которые он не смог обработать. Имена файлов с отчётами можно получить из трекера.
Имеется два вида импорта:
Обычный
Данные вносятся в базу, создаются отсутствующие подписчики, внесённые данные доступны до момента удаления подписчика и могут использовать в условиях группах-фильтрах отбора сегментов.
Этот вид импорта используется по умолчанию и подходит, если данные должны храниться долговременно.
В зависимости от количества вносимых адресов и объёма данных этот импорт может быть относительно не быстр.
Импорт Телеграм
Это обычный импорт, но требуется:
- указать тип адресов addr_type : tg
- указать обязательный параметр basegroup.id — код базовой группы телеграм-бота
- в колонке member.tg указывать номера пользователей в Телеграм (номера, не имена)
- при желании использовать специальную колонку /status для указания как вносить подписчиков — колонка отсутствует или содержит 1 , active или пусто — подписчик добавляется как активный, всё прочее — как отписанный
Экспресс-Импорт
Этот вид импорта предназначен для очень быстрого (сотни тысяч в минуты) внесения реестров с адресами и данными персонализации, которые, в последствии, можно использовать в выпусках рассылок.
В отличии от обычного импорта эти данные хранятся и управляются отдельно, не становясь частью данных подписчика.
Если по каким-то причинам для выпуска рассылок по реестру не используется Экспресс-выпуск, а работа ведётся по сценарию «Импортировать данные, а потом сделать по ним выпуск», то использование Экспресс-импорта вместо обычного импорта как раз то, что лучше всего подходит для этого.
Внесённые в Экспресс-импорте подписчики и их данные сохраняются в отдельную новую группу-список, всегда создаваемую автоматически. Её название и, при желании, код можно указать в задании Экспресс-импорта.
В дальнейшем, именно по этой группе надо выпускать рассылки.
Группа, созданная при Экспресс-импорте ведёт себя в целом как обычная группа. С ней можно выполнять действия подсчёта количества адресов, получения списка, очистки списка, удаление группы, создания снимка.
Однако, такая группа не может участвовать в условиях отбора у групп-фильтров.
Отличить её можно по параметру expimp в group.list и group.get. Дополнительно, group.get, вызванный для одной группы, возвращает параметр caption для понимания структуры данных, а также count с количеством мемберов, например:
Внесённые данные хранятся 30 дней с момента последнего использования в выпуске, а если выпусков по группе не было, то 30 дней с момента внесения.
Для того, чтобы обычный импорт стал Экспресс-импортом достаточно указать в вызове member.import параметр «express»: 1.
Вызов импорта
< "action" : "member.import" или "action" : "member.import.probe" ** данные импортирования ,"addr_type": "тип вносимых адресов подписчиков (email|msisdn|viber|csid|tg|vknotify|vknotify)" и одни из источников данных: ,"users.list": адреса и данные для импортирования -- непосредственно в JSON, СSV или XSLX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-Выпуска" ,"encoding" : "base64" -- не обязательно. -- пусто или отсутствует - данные в users.list представлены непосредственно -- base64 - данные в users.list закодированы в base64 или ,"users.url": "URL, по которому находятся список адресов и данных для импортирования -- Данные забираются в момент вызова для member.import.probe и в момент начала импортирования для member.import -- При оформлении импорта как действия по расписанию не забудьте, что эту ссылку можно кастомизировать -- временем и указать количество и интервал попыток получения данных. Подробнее в разделе "Замечания" -- Внешние ссылки http / https / ftp / ftps / sftp или из хранилища загрузок rfs://upload/путь-до-файла -- === Siebel -- Для запросов по SOAP (например, к Siebel) схемы soap:// и soaps:// - обратитесь в Службу поддержки -- для получения дополнительной информации -- === Google Big Query -- Для запросов из Google Big Query настройте внешнюю авторизация для схемы gbd:// (описано в вызовах authext.*) -- Данные получаются полной выборкой из указанной в url вида gbd://authext:AUTHEXT_ID@DATASET_ID/TABLE_ID таблицы. -- При использовании схемы gbd:// обязательно должно быть указано описание получаемых столбцов через параметр caption (описан ниже) -- === amoCRM -- Для получения данных из amoCRM настройте внешнюю авторизацию для типа amocrm и укажите источником адресов ссылку вида -- -- amocrm://authext:AUTHEXT_ID@/ -- -- или с указанием дополнительных полей для внесения -- -- amocrm://authext:AUTHEXT_ID@/?fields=phone,name -- === Bitrix24 -- Для получения данных из Bitrix24 настройте внешнюю авторизацию для типа bitrix24 и укажите источником адресов ссылку вида -- -- bitrix24://authext:AUTHEXT_ID@/ -- -- или вот так пока у вас настроена работа только с одним bitrix24 -- -- bitrix24:/// -- -- или с ограничение списка разделов откуда выбирать адреса - company,lead,contact (по умолчанию изо всех) -- -- bitrix24://authext:AUTHEXT_ID@/?list=company,contact или ,"uid": "идентификатор уже загруженных данных" -- возвращается после первого вызова member.import.probe, используется далее вместо cамих данных ** прочие параметры ,"express" : 0|1 - признак Экспресс-Импорта ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )" -- указание кодировки символов не обязательно - работает автоопределение -- для XLSX и JSON смысла не имеет -- известная особенность - импорт CSV без явного указания кодировки -- если в первых нескольких килобайтах реестра нет ни одной русской буквы, то автопределение -- считает, что это cp-1251. Потом выясняется, что клиент всё же использовал utf-8. -- редко, но так бывает. Поэтому указывайте кодировку для CSV всё же явно. ,"separator": "разделитель символов ("," | ";" | "|" | "t")", -- где t - табуляция -- не обязательно - работает автоопределение -- для XLSX и JSON смысла не имеет ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )" ,"basegroup.id" -- обязательный код базовой группы телеграм-бота для импорта Телеграм, для остальных - игнорируется ** явное описание столбцов для модели АВО (не обязательны) ,"caption": [ -- по порядку следования столбцов в данных, приписывают каждый столбец одному вопросу одной анкеты -- приоритетнее, чем описание из первой строки данных для импортирования -- обязателен при получении данных из Google Big Query -- при addr_type = email колонка с адресом - это анкета "member" вопрос "email" -- при addr_type = msisdn колонка с номером телефона это анкета "member" вопрос "cellphone" -- при addr_type = viber колонка с номером viber - это анкета "member" вопрос "viber" -- при addr_type = csid колонка с клиентским идентификатором - это анкета "member" вопрос "csid" -- при addr_type = tg колонка с клиентским идентификатором - это анкета "member" вопрос "tg" -- при addr_type = vknotify колонка с клиентским идентификатором - это анкета "member" вопрос "vknotify" < "anketa": "id анкеты", "quest": "id вопроса в анкете", или "ignore": "1" -- игнорировать столбец -- вычислять при внесении. Содержимое колонки не заменит имеющиеся данные, а будет прибавлено к ним -- для задания через первую строку данных для импортирования добавьте знак "=" перед названием колонки "calc" : 1 или "/status" : "0|1|active|" -- только для Телеграмм. колонка отсутствует или содержит 1, active или пусто - подписчик добавляется как активный, всё прочее - как отписанный >, . ] ** явное описание столбцов для модели КД (не обязательны) ,"caption": [ -- по порядку следования столбцов в данных. Приписывают каждый столбец одному вопросу одной анкеты -- приоритетнее, чем описание из первой строки данных для импортирования -- при addr_type = email колонка с адресом - это member.email -- при addr_type = msisdn колонка с номером телефона - это member.cellphone -- при addr_type = viber колонка с номером viber - это member.viber -- при addr_type = csid колонка с клиентским идентификатором - это member.csid -- при addr_type = tg колонка с клиентским идентификатором - это анкета "member" вопрос "tg" -- при addr_type = vknotify колонка с клиентским идентификатором - это анкета "member" вопрос "vknotify" < "datakey": "ключ данных колонки", -- как в member.set "mode" : "режим внесения", -- как в member.set "type" : "тип данных", -- как в member.set "autodetect" : 0|1 -- не обязательно. пытаться автоматически преобразовывать вносимое значение-строку -- по умолчанию: 1 - для ключей base.*, 0- для прочих -- -- если включено и существуют анкета и в ней вопрос с id как в datakey -- и это вопрос с выбором, и вносимое значение не подходит ни под один -- код ответа, то попробовать найти код ответа. Нужно считать, что вносимое значение -- - это название ответа в вопросе, если значение не подойдёт и не под одно название, -- то строка не будет внесена с ошибкой "неизвестный ответ" -- -- например, для вопроса Пол с ответами "Мужской" - "m" и "Женский" - "w" будет -- при внесении будут пониматься значения m и w, но и Мужской (преобразуется в m) -- и Женский (преобразуется в w) -- -- также, при указании autodecet в строке можно указать несколько ответов (названий -- ответов) для вопроса с множественным выбором в том же формате, что и при АВО -- - через вертикальную черту. например "x1|x2|x4" или "ignore": "1" -- игнорировать столбец -- вычислять при внесении. Содержимое колонки не заменит имеющиеся данные, а будет прибавлено к ним. -- для задания через первую строку данных для импортирования добавьте знак "=" перед названием колонки "calc" : 1 или "/status" : "0|1|active|" -- только для Телеграм, колонка отсутствует или содержит @1@, @active@ или пусто - подписчик добавляется как активный, всё прочее - как отписанный >, . ] ** пробный импорт ,"action": "member.import.probe", ** импорт ,"action": "member.import", ,"if_exists" : "error|must|ignore" -- не обязательно, по умолчанию существующий подписчик обновляется, а отсутствующий - создаётся -- error - ошибка при наличии подписчика в базе -- must - ошибка при отсутствии адреса в базе -- ignore - игнорирование строки импорта при наличии подписчика в базе без сообщения об ошибке ,"newbie.confirm" : "подписчик должен подтвердить внесение в базу (1|0)", -- по умолчанию - внесение без необходимости подтверждения подписчиком (0) -- внесение email без подтверждения ограничено величиной member.noconfirm.rest -- (узнать можно через sys.settings.get) при её исчерпании остальные адреса -- вносятся с подтверждением. -- если количество адресов в базе превышает member.tarif.limit, то величина member.noconfirm.rest -- равна нулю, иначе она равна member.noconfirm.limit за вычетом количества уникальных email -- адресов, внесённых в текущем месяце -- на внесение номеров телефонов параметр newbie.confirm не влияет (они всегда вносятся без подтверждения) ,"auto_group" : < -- автоматически создать группу-список для импортируемых адресов -- или дополнить любую существующую группу-список импортируемыми адресами -- для обычного импорта отсутствие всего параметра auto_group означает не создавать новую и не пополнять -- существующую группу -- наличие auto_group, но без id и без name, означает создание группы со стандартным кодом -- и со стандартным названием -- для Экспресс-импорта группа-список создаётся всегда и отсутствие всего параметра auto_group означает -- только, что код и названия будут автоматические -- указание в id существующей группы будет ошибкой -- код созданной группы можно узнать, используя возвращаемый номер track.id и вызов track.get "id" : "идентификатор группы-списка для пополнения" -- при отсутствии такой группы она создаётся автоматически -- если параметр пуст или отсутствует, то используется стандартный -- код вида importYYYYYMMDDhhmmss или importexYYYYYMMDDhhmmss ,"name" : "название группы" -- название для создаваемой группы -- если параметр пуст или отсутствует, то используется стандартное "Внесены " >, ,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список, указанную в auto_group перед началом импортирования -- позволяет не дополнять группу, а полностью заменять её участников -- -- сначала проверяются все возможные причины, по которым импорт может не начаться. Если они есть, то импорт заканчивается ошибкой и очистка не происходит -- иначе импорт начинается с очистки списка участников, а внесение новых происходит только после этого -- -- не путайте удаление адреса из списка участников с удалением адреса из базы - это разные вещи -- -- при одновременном импортировании в одну группу несколькими вызовами, у которых хоть у одного clean_group=1, результат -- зависит от порядка выполнения и может быть неожиданным. Для однозначного результата всегда выполняйте импорт с cleangroup=1 -- только по завершении всех предыдущих импортов в ту же самую группу и не запускайте новый импорт в такую группу до завершения текущего -- Добавить/удалить импортируемые адреса в/из групп-списков -- Не применимо -- к Экспресс-Импорту - "express":1 -- если "no_member":1 -- -- Очерёдность -- сначала удаляется из групп "member.group.remove" -- потом, вне зависимости от результата remove, добавляются в "member.group.add" -- дубли autogroup в member.group.add игнорируются -- autogroup исполняется ПОСЛЕ remove/add ,"member.group.add" : [ код-группы-списка-1, код-группы-списка-2, . ] -- не обязательно -- группы-списки в которые добавить импортируемые адреса (не зависимо от того, поменял импорт данные или нет) ,"member.group.remove" : [ код-группы-списка-1, код-группы-списка-2, . ] -- не обязательно -- группы-списки из которых удалить импортируемые адреса (не зависимо от того, поменял импорт данные или нет) ,"head_attach" : < -- не обязательно -- -- тонкая настройка правил присоединения голов (по аналоги с member.set / member.merge) -- действует на все колонки member.head.attach одинаково. -- "newbie.confirm" : "режим подтверждения" ,"head_rule": < -- параметры, определяющие обработку голов при слиянии "multi": error|none|transplant|replace|replace_same_type|decapitate -- для многоголовых пользователей "single": error|none|transplant|replace|replace_same_type|decapitate -- для одноголовых "newbie": attach|none|replace|replace_same_type - для новых, несуществующих идентификаторов (без голов) >,"data_rule": "обработка данных при слиянии" -- как в member.merge > ,"no_member" : 0|1 -- не создавать подписчика. не обязательно, по умолчанию 0 - создавать -- специфическая настройка, что бы работал безопасный Экспресс-Выпуск по номерам адресов (описано в issue.send) -- требуется что бы внести только адреса (и у них появится необходимый номер) без создания подписчика (который не требуется для Экспресс-Выпуска) -- не поддерживается сочетание express и no_member. -- не поддерживается сочетание no_member и auto_group. -- в реестре должна быть только одна колонка ,"format" : " id-формата" -- дополнить данные каждого вносимого адреса данным из формата (игнорируется для КД пока форматы не получат поддержку КД) -- отсутствие или пусто - не дополнять ,"sequence.event" : 0|1 -- будет ли внесение/изменение данных вызывать срабатывание событийных действий -- отсутствие или пусто - вызова событий не будет -- остановить и/или начать прохождение последовательности - аналог sequence.member.stop/start для участников импорта -- касается всех участников импорта, вне зависимости поменялось у них что-то или нет -- сначала для адреса останавливаются прохождения по тригерам sequence.stop -- потом, вне зависимости от результата stop, запускаются прохождения по тригерам sequence.start -- не применимо при Эксрпесс-Импорте -- не применимо если no_member ,"sequence.stop" : [ номер-тригера-1, номер-тригера-2, . ] -- не обязательно ,"sequence.start" : [ номер-тригера-1, номер-тригера-2, . ] -- не обязательно ,"result" : [ способ возврата результата, смотрите общее описание ] -- данный вызов всегда асинхронный и способ "response" означает сохранение отчёта в хранилище отчётов >
< -- только для member.import.probe ,"uid": "идентификатор уже загруженных данных" ,"charset": "кодировка символов ( koi8-r | cp1251 | utf-8 | utf-7 | utf-16 | mac-cyrillic )" ,"separator": "разделитель символов ("," | ";" | "|" | "t")" ,"firstline": "использовать первую строку как строку конфигурации ( 1 | 0 )" ,"caption": [ -- поля конфигурации < -- при импорте по модели АВО для колонки которой найдено соответствие анкете/вопросу "source": "исходное значение кода колонки из CSV/XLSX" "name": "название анкета и вопроса", "anketa": "id анкеты", "quest": "id вопроса в анкете", "quest.type" : "тип вопроса в анкете" "quest.subtype" : "под-тип вопроса" -- еcли применимо к type "quest.width" : "длина поля" -- еcли применимо к type -- при импорте по модели АВО для колонки которой не найдено соответствие "name": "неопределенное значение из элемента строки конфигурации или null", -- при импорте по модели ДК "datakey": "ключ данных колонки", "mode" : "режим внесения", "type" : "тип данных", -- при импорте по модели ДК для колонки с динамическим ключом данных "dynamic": "1", -- для колонки, для которой конфигурации задано игнорирование "ignore" : 1 -- для колонки, для которой конфигурации задано вычислять при внесении "calc" : 1 >] ,"rows" : [ -- данные первых 15 значащих строк разбитые по полям с учёном указанного разделителя [ "колонка-1-строки-1" ,"колонка-2-строки-1" ,"колонка-3-строки-1" ] ,[ "колонка-1-строки-2" ,"колонка-2-строки-2" ,"колонка-3-строки-3"] . ] ,"cannot_import" : 0|1 -- может ли быть выполнен импорт с текущими параметрами запроса -- 0 - может -- 1 - нет -- Именно этот параметр, а не описанный далее параметр warnings сигнализирует о возможности/невозможности импорта, -- т.к. параметр warnings может содержать и не влияющие на запуск процесса импорта предупреждения - например, о том, -- что в первых строках файла есть неверно указанные адреса подписчиков, что не говорит о том, что во всем -- списке подписчиков будет так ,"warnings" : [ -- предупреждения о проблемах при анализе данных -- в первую очередь проверяйте параметр cannot_import -- если он показывает, что импорт невозможен, то тут содержится описание почему -- кроме этого, предупреждения могут показывать на проблемы с первыми адресами списка -- импорта, что не препятствует самому импорту < "id":"код ошибки", "explain": "доп. информация (скаляр, массив или хэш)" >. ] -- только для member.import ,"queue_position" : "номер в очереди импортирования" ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* >
Массовое изменение данных подписчиков¶
Вызов предназначен для единообразного изменения данных сразу многих адресов по правилам, описанных в «Формате заполнения».
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием того, как и какие адреса были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания.
Все попытки изменения системной анкеты member игнорируются, за исключением ответа error.
Установка member.error в «0» удаляет запись о проблемах доставки и снимает блокировку адреса из-за ошибок доставки, если таковая была.
В данный момент вызов не позволяет менять данные по модели КД, так как это происходит через указание формата, а форматы пока не совместимы с КД, но вы можете использовать вызов импорта подписчиков.
Одновременно может выполняться только один такой запрос:
< "action" : "member.update" ,"format" : код формата заполнения или универсального, из данных которого будут применены изменения ,"if_has" : что делать, если изменяемый пункт анкеты уже заполнен -- "overwrite" - заменить старое значение новым из формата -- "merge" - объединить старое и новое значения -- "skip" - оставить старое значение ,"if_hasnt" : что делать, если изменяемый пункт анкеты ещё не заполнен -- "set" - заполнить указанным в формате значением -- "skip" - оставить пункт незаполненным -- указание подписчиков одним из способов ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. не обязательно, система сама распознает email или msisdn или ,"list" : [ "идентификатор подписчика" ,"идентификатор подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный или ,"group" : код группы к участникам которой будут применены изменения ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ не обязательно. условие отбора поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. не обязательно, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный >
< -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : < "адрес-1" : 0|1 -- результат изменения - 1 - изменение применено, 0 - нет (например, адрес ошибочен или отсутствует) ,"адрес-2" : 0|1 . >>
Выслать письмо-подтверждение¶
Вызов позволяет отправить письма, в которых будут работать специальные команды шаблонизатора для подтверждения внесения в базу ( [% anketa_member_tag_a_confirm %] ) и удаления из стоп-листов ( [% param.url_unsub_cancel %] и [% param.url_unsub_sender_cancel %] ).
Запрос с указанием списка по умолчанию синхронный.
Запрос с указанием группы по умолчанию асинхронный. Используйте sync = 1, если вам реально нужен ответ с описанием какие адреса как были обработаны.
Асинхронные запросы возвращают номер трекера для отслеживания прогресса отправки.
При высылке с использованием group/group.filter/stat.uni/url создаётся выпуск, в который группируются отосланные письма.
< "action" : "member.sendconfirm" -- одно из ,'confirm' : 1 -- высылка писем для подтверждения внесения в базу ,'unsubcancel' : 1 -- высылка писем для удаления из глобального стоп-листа ,'unsubsendercancel' : 1 -- высылка писем для удаления из стоп-листа по отправителю. отправитель - тот что указан в черновике letter -- указание шаблона письма ,"letter" : "код информационного письма" -- обязательно -- информационное письмо должно иметь заполненный адрес отправителя и не находиться на модерации ,"issue_name" : "название выпуска" -- название создаваемого выпуска. Если отсутствует или пусто, то будет использована тема письма из letter -- не использутеся для email и list -- указание подписчиков одним из способов ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. Параметр необязателен, система сама распознает email или msisdn или ,"list" : [ "идентификатор подписчика" ,"идентификатор подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса. по умолчанию 1 - синхронный или ,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip. ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ параметр необязателен, условие отбора поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте только если не подходит значение по умолчанию [ "member.email" ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn >,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен. >
< ,"issue.id" : номер выпуска -- для group, group.filter, url и stat.uni высылаемые письма будут оформлены отдельным выпуском рассылки, -- номер которого и будет возвращён. Это позволяет изучить статистику по высланным приглашениям -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса ,"list" : < "адрес-1" : 0|1 -- результат высылки - 1 - выслано, 0 - нет (например, адрес ошибочен или отсутствует или не нуждается в подтверждении) ,"адрес-2" : 0|1 . >>
Подтвердить внесение в базу¶
При успешном подтверждении подписчик становится доступным для участия в рассылках (при отсутствии других противопоказаний к этому).
Если требуется обратное — заново установить состояние «Требуется подтверждение внесения в базу» — используйте вызовы member.set или member.update с установкой member.lockconfirm в «1».
< ,"error" : "error/member/wrongcookie" - неверный код. Если ошибка отсутствует, то подтверждение выполнено или не требовалось. >
Информация об адресе¶
Вызовы возвращают информацию об адресе, не связанную с существованием подписчика и даже в случае, если подписчик уже удалён.
< "obj" : < -- информация об адресе по структуре аналогичная ключу member вызова member.get "member" : < "id" : "номер адреса", -- он же номер подписчика "addr_type" : "email|msisdn|viber|csid|push|vk|tg|vknotify|vknotify" -- тип адреса "email" : "адрес", "haslock" : "наличие блокировки", -- 0 - нет, 1 - отписался/в стоп листе, 4 - ошибки доставки, 5 = 1 + 4 -- информация об ошибках доставки "error" : < "lock" : 0 -- нет блокировки из-за ошибок доставки, 1 - есть -- при наличии, информация об ошибках ,"date" : "2015-09-12 18:53:39" -- дата последней ошибки доставки (Ys) (удаляется при первой же успешной доставке) ,"str" : "name=test.ru type=A: Host not found" -- описание последней ошибки доставки (удаляется при первой же успешной доставке) ,"error" : 1 -- общее число ошибок доставки, произошедших подряд (устанавливается в 0 при первой же успешной доставке) ,"issue" : 123 -- выпуск последней ошибки доставки ,"letter" : 123 -- письмо последней ошибки доставки ,"lock_issue" : 456 -- выпуск, который привел к блокировке ,"lock_letter" : 456 -- письмо, которое привело к блокировке >, -- информация об отписке/стоп листе "lockremove" : 0|1, -- адрес отписан или в стоп-листе (1) или нет (0) -- обычный формат - записи только о глобальном стоп-листе "stoplist" : < -- в стоп-листе владельца аккаунта, если ключ присутствует в stoplist "owner" : < "dt" : "2015-11-17 15:02:45", -- дата внесения (Ys) "source" : "101.101.201.1" -- источник >, -- в стоп-листе, так как подписчик отписался, если ключ присутствует в stoplist "member" : < "dt" : "2015-11-17 15:02:45", -- дата внесения (Ys) "source" : "101.101.201.1" -- источник >> -- расширенный формат - with_stoplist = 2 - записи и о глобальном стоп-листе и об отписке от отправителей "stoplist" : [ < -- пример записи глобального стоп-листа "dt" : "2015-11-17 15:02:45", -- дата внесения (Ys) "source" : "101.101.201.1", -- источник "type" : "owner", -- запись внесена владельцем аккаунта "sender" : "" -- пусто - глобальный стоп-лист >, < -- пример записи стоп-листа по отправителю "dt" : "2015-11-17 15:02:45", -- дата внесения (Ys) "source" : "101.101.201.1", -- источник "type" : "member", -- запись внесена из-за действий подписчика "sender" : "test@test.ru" -- не пусто - отписка от этого отправителя >] > > >
Проверка адресов¶
Вызов проверяет список адресов на синтаксическую верность, даёт нормализованный вариант написания и (если указано) на то, что про этот адрес думает первичный MX, обслуживающий домен.
В ответе ключами списка являются адреса из исходного списка в неизменном виде. Нормализованный вид доступен в параметре email.
Если проверка SMTP не указана, то в ответе не будет частей, связанных с её результатами.
Стадии, на которых проверка SMTP закончилась ошибкой (параметр status):
resolver - ошибка запроса DNS, описание ошибки в параметре message nodomain - домен не существует nomxa - у домена нет ни одной записи MX или А connref - не удалось соединиться с MX banner - ошибка в первичном баннере helo - ошибка в ответ на HELO mailfrom - ошибка в ответ на MAIL FROM rcptto - ошибка в ответ на RCPT TO
Для понимания того, как работает SMTP и что значат все эти странные слова, полезно изучить RFC 5321.
< "action" : "email.test" ,"result" : [ способ возврата результата, смотрите общее описание ] -- отчёт содержит поля ответа - email,total,syntax,delivery.lock(как "ok" или "error"),smtp.status ,"delivery.error" : 0|1 - выводить данные по ошибкам доставки ,"smtp.test" : "проверять доступность по smtp" -- не обязательное поле -- 0 - не проверять (по умолчанию) -- lite - проверять, но без проверки существования адреса -- full - проверять, включая проверку существования адреса -- -- . Полная проверка "full" не всегда даёт результат -- Многие системы отвечают "существует" на любой адрес -- Многие системы примут такую проверку за спам-активность -- Используйте такую проверку, только если понимаете что делаете ,"smtp.timeout" : "таймаут в секундах" -- не обязательное поле, по умолчанию 15 ,"auto_group" : < -- параметр необязателен -- автоматически создать группу-список для не прошедших проверку подписчиков -- или дополнить любую существующую группу-список не прошедшими проверку подписчиков -- в группу заносят только те адреса, у которых нет синтаксических ошибок, но есть ошибки smtp и в базе уже есть подписчик с таким адресом -- отсутствие всего параметра auto_group означает ни создавать новую, ни пополнять существующую группу -- наличие auto_group, но без id и без name означает создание группы со стандартным кодом -- и со стандартным названием. Код созданной группы можно узнать, используя возвращаемый номер track.id -- и вызов track.get "id" : "идентификатор группы-списка для пополнения" -- при отсутствии такой группы она создаётся автоматически -- если параметр пуст или отсутствует, то используется стандартный -- код вида importYYYYYMMDDhhmmss l ,"name" : "название группы" -- название для создаваемой группы. -- если параметр пуст или отсутствует, то используется стандартное "Внесены " >, ,"clean_group" : 0|1 -- очищать (1) или нет (0) группу-список указанную в auto_group перед началом проверки. Параметр необязателен -- указание адресов одним из способов ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn или ,"list" : [ "идентификатор подписчика" ,"идентификатор подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный или ,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip. ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен >
< "list" : < -- ключ - оригинальное значение адреса из запроса " missing@CityCat.ru" : < "total" : "ok|bad" -- ok - syntax=ok, delivery.lock=0 (если заказывалось), smtp.status=ok (если заказывалось) -- bad - в других случаях ,"syntax" : "ok" -- результат синтаксической проверки адреса -- ok - нормально -- иначе код ошибки -- остальные поля не имеют смысла если syntax не "ok" ,"email" : "missing@citycat.ru" -- нормализованная форма адреса ,"email.id" : "номер адреса в системе" ,"delivery" : < -- если заказан вывод ошибок доставки "str" : "host said: 550 SMTP error from remote mail server after end of data: 552 5.2.2 Mailbox size limit", "lock" : "0", "dt" : "2018-07-26 11:58:06", "error" : "1" >, ,"smtp" : < -- если заказана проверка по smtp "status" : "rcptto" -- стадия возникновения ошибки ,"domain" : "citycat.ru" -- домен, для которого определялся первичный MX ,"mx" : "smtp.citycat.ru" -- первичный MX, используемый для теста ,"ip" : "81.9.34.192" -- ip-адрес использованного MX ,"ptr" : [ -- список имён, соответствующих ip-адресу "cat192.subscribe.ru" ] ,"code" : "550" -- код SMTP-ошибки (000 - тайм-аут) ,"dsn" : "5.1.1" -- Enchanced status code SMTP-ошибки (при наличии в ответе) ,"message" : ". User unknown" -- текст SMTP-ошибки или ошибки DNS > > ," PRO@subscribe.ru " : < "email" : "pro@subscribe.ru" ,"syntax" : "ok" ,"smtp" : < "status" : "ok" ,"domain" : "subscribe.ru" ,"mx" : "smtp.subscribe.ru" ,"ip" : "81.9.34.192" ,"ptr" : [ "cat192.subscribe.ru" ] >> ,"123@test@test.ru " : < "email" : null ,"syntax" : "error/email/multydog" -- код ошибки >> >
Удаление ошибок доставки¶
Удаляются записи об ошибках доставки указанных адресов.
С подписчика, при наличии, снимается блокировка из-за ошибок доставки.
Но наличие подписчика не обязательно (в отличии от вызова member.set, который работает именно с подписчиками)
< "action" : "email.cleanerror" -- указание адресов одним из способов ,"email": "идентификатор подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификатора. Параметр необязателен, система сама распознает email или msisdn или ,"list" : [ "идентификатор подписчика" ,"идентификатор подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный или ,"group" : код группы, участникам которой будут высланы повторные напоминания о подтверждении регистрации ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов, по одному на строке, возможно сжатие zip. ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов в списке. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный ,"track.info" : "дополнительная информация которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен >
< "list" : < -- ключ - оригинальное значение адреса из запроса "email1" : результат -- null - адрес синтаксически не верен -- 1 - ошибки доставки удалены, подписчик разблокирован (если был заблокирован) -- 0 - не было ошибок доставки ,"email2" : . >>
Обогащение данных подписчиков¶
Обогащение данных подписчиков это получение для интересующих вас адресов данных о их покупательском поведении.
Для подключения свяжитесь со Службой Поддержки.
Достаточно составить группу-список или группу-фильтр с интересующей вас аудиторией и указать связать эту группу с одной или несколькими тематиками (вызов sys.settings.get[tde.topic] ).
Система будет сама обновлять в данных подписчика специальный ключ данных tde по мере появления информации.
По полученным данным, например, можно сегментировать аудиторию или запускать триггеры реагирующие на покупки (купил корм для кошек — выслать напоминание, что надо регулярно вакцинировать животное).
Информация хранятся в ключе данных tde в виде следующей структуры
«код категории» :
"tde" : < "travellers_inexpensive" : < "count" : 2, "firstOccurrence" : "2021-12-06 18:18:53", "lastOccurrence" : "2021-12-13 18:36:38", "topic" : "travellers_inexpensive" >, "drugs_anticold" : < "count" : 1, "firstOccurrence" : "2022-03-19 17:54:00", "lastOccurrence" : "2022-03-19 17:54:00", "topic" : "drugs_anticold" >, "drugs_antiviral" : < "count" : 1, "firstOccurrence" : "2022-03-19 17:54:00", "lastOccurrence" : "2022-03-19 17:54:00", "topic" : "drugs_antiviral" >, "clothes_buyers" : < "count" : 2, "firstOccurrence" : "2022-05-12 18:16:08", "lastOccurrence" : "2022-10-04 14:41:27", "topic" : "clothes_buyers" >.
Полный лог появления записей по тематикам доступен через параметр tde в Универсальной Статистике.
Cписок доступных тематик
Автомобилисты | drivers |
Автомобилисты (отечественные авто) | drivers_russian_cars |
Автомобилисты (зарубежные авто) | drivers_foreign_cars |
Богатые (совершили дорогие покупки) | rich_people |
Беременные | pregnant |
Владельцы рыбок | fish_owners |
Владельцы собак | dogs_owners |
Владельцы грызунов | rodents_owners |
Владельцы птиц | birds_owners |
Владельцы котов и кошек | cats_owners |
Дачники | cottagers |
Женщины | women |
Кулинария | cooking |
Матери с дошкольниками | mothers_w_preschoolers |
Матери со школьниками | mothers_w_schoolers |
Мамы с детьми 0-3 год | mothers_w_children_0_3 |
Мамы с детьми 14-18 лет | mothers_w_children_14_18 |
Мамы с детьми 3-6 лет | mothers_w_children_3_6 |
Мамы с детьми 6-9 лет | mothers_w_children_6_9 |
Мамы с детьми 9-14 лет | mothers_w_children_9_14 |
Принтеры | printers |
Придерживаются ЗОЖ | healthy_lifestyle |
Путешественники | travellers |
Путешественники бизнес-классом | travellers_business_class |
Путешественники по России | travellers_rf |
Путешественники по бюджетным направлениям | travellers_inexpensive |
Путешественники по дорогим направлениям | travellers_expensive |
Покупатели спорт-инвентаря | sport_equipment_buyers |
Покупатели успокоительных | drugs_sedative |
Покупатели уходовых средств для волос | hair_care_product_buyers |
Покупатели уходовой косметики для тела | body_cosmetics_buyers |
Покупатели уходовой косметики для лица | facial_cosmetics_buyers |
Покупатели укладочных средств для волос | hair_styling_product_buyers |
Покупатели фастфуда | fast_food_buyers |
Покупатели лекарств для ЖКТ | drugs_gastric |
Покупатели бытовой техники для кухни | kitchen_appliances_buyers |
Покупатели бюджетных гаджетов | inexpensive_gadgets_buyers |
Покупатели билетов в кино (оффлайн) | cinema_ticket_buyers |
Покупатели одежды | clothes_buyers |
Покупатели одежды масс-маркета | mass_market_clothes_buyers |
Покупатели мебели | furniture_buyers |
Покупатели витаминов | vitamins |
Покупатели витаминов для беременных | vitamins_for_pregnant |
Покупатели витаминов для мужчин | vitamins_for_men |
Покупатели витаминов для волос | vitamins_for_hairs |
Покупатели витаминов для женщин | vitamins_for_women |
Покупатели витаминов для детей | vitamins_for_children |
Покупатели витаминов для кожи | vitamins_for_skin |
Покупатели противовирусных препаратов | drugs_antiviral |
Покупатели противогрибковых препаратов | drugs_antifungal |
Покупатели противопростудных лекарств | drugs_anticold |
Покупатели премиальных гаджетов | premium_gadgets_buyers |
Покупатели премиальных аксессуаров | premium_accessories_buyers |
Покупатели премиальной одежды | premium_clothes_buyers |
Покупатели премиальной косметики | premium_cosmetics_buyers |
Покупатели препаратов от кашля | drugs_antitussive |
Покупатели препаратов для сердечно-сосудистой системы | drugs_cardiovascular |
Покупатели препаратов для иммунной системы | drugs_for_immunity |
Покупатели подписок на кино / сериалы | online_cinema_subscribers |
Покупатели парфюма | perfume_buyers |
Покупатели декоративной косметики для лица | facial_makeup_buyers |
Покупатели антибиотиков | drugs_antibiotics |
Покупатели антигеммороидальных препаратов | drugs_antihemorrhoidal |
Покупатели аксессуаров масс-маркета | mass_market_accessories_buyers |
Покупатели крупной бытовой техники | domestic_appliances_buyers |
Покупатели косметики для ухода | cosmetics_buyers |
Рукоделие | handiwork |
Рыбалка / Охота | fishing_hunting |
Ремонт | apartment_renovation |
Студенты | students |
Чистовая отделка | apartment_renovation_finishing |
Черновой ремонт | apartment_renovation_rough |
Группы адресов — Сегментирование аудитории¶
Группы позволяют сформировать сегменты аудитории по самым разным критериям персональных данных, занесённых в базу, и по накопленной статистике о поведении подписчика.
Группы-списки — это списки адресов, формируемые вами в явном виде. Участие адреса в такой группе не зависит от его персональных данных и статистики. Выпуск и подсчёт статистик по таким группам несколько быстрее, так как список адресов предопределён.
Группа-фильтр — это динамический список адресов. Участие в такой группе описывается фильтром, применяемым к персональных данным и статистике поведения. Участие адреса в такой группе каждый раз устанавливается в момент проверки в реальном времени. За счёт этого выпуск и подсчёт статистик по таким группам несколько медленнее из-за фильтрации данных.
Фильтр группы-фильтра поддерживает оба формата хранения — и АВО, и КД.
Cписок групп¶
< ,"list" : [ < "id" : "код группы" ,"name" : "название" ,"type" : "тип группы" -- list или filter ,"addr_type" : "тип адресов" -- email|msisdn|viber|csid|push|vk|tg|vknotify ,"create.date" : "дата и время создания" -- Ys, null ,"update.date" : "дата и время последнего изменения" -- Ys, null ,"expimp" : "группа Экспресс-Импорта" -- 0 -пусто-отсутствует - это группа не от Экспресс-импорта -- -1 -группа от Экспресс-импорта, но данные уже удалены -- иначе - Экспресс-импорт и данные на месте ,"reltype" : . ,"relref" : . >. ] >
Создать группу¶
При создании группы типа filter она первоначально получит пустой набор правил отбора.
До явной установки желаемых правил отбор по такой группе всегда будет давать пусто.
< , "id" : "код созданной группы" >
Прочитать группу¶
Обратите внимание, что при вызове со списком групп, сообщения об ошибочных кодах групп будут возвращены не в errors (как это было бы при одиночном вызове), а в warnings, так как в целом считается, что вызов закончился успешно.
< -- для одной группы ,"obj" : < ,"id" : "код группы" ,"name" : "название группы" ,"type" : "тип группы" -- list или filter ,"addr_type" : "тип адресов" -- email|msisdn|viber|csid|push|vk|tg|vknotify ,"filter" : [ -- если запрошено фильтр группы как в вызове group.filter.get ] ,"create.time" : "дата и время создания" -- Ys, null ,"update.time" : "дата и время последнего изменения" -- Ys, null ,"expimp" : "группа Экспресс-Импорта" -- 0 -пусто-отсутствует - это группа не от Экспресс-импорта -- -1 -группа от Экспресс-импорта, но данные уже удалены -- иначе - Экспресс-импорт и данные на месте ,"caption" : [ -- если группа от Экспресс-импорта, то тут описана структура данных -- в том же формате, что используется в вызове импорта ] ,"count" : < -- для группы от Экспресс-импорта "total" : "количество уникальных адресов" >,"reltype" : . ,"relref" : . > -- или для нескольких групп ,"list" : [ < содержимое obj для одной группы >, < содержимое obj для другой группы >. ] ,"warnings" : [ -- может отсутствовать массив аналогичный по структуре массиву errors содержит ошибки для тех кодов групп из списка, которые ошибочны по тем или иным причинам ] >
Изменить группу¶
Не указанные параметры не изменяются.
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "group.get" соответствующей анкеты
Удалить группу¶
Получить правила фильтрации группы¶
Только для групп с типом filter
< ,"update.time" : "дата-время изменения фильтра" -- Ys ,"obj" : [ массив, описывающий фильтр ] ,"in_group" : < "count" : 0, -- сколько раз используется in_group или !in_group "uniq" : 0, -- сколько уникальных групп используется "list" : [], -- список уникальных групп "usage : < "group" : 123, . >, -- какая группа сколько раз использовалась "depth" : 0, -- максимальный уровень вложенности "max_reusage" : 0, -- максимально раз использования одной группы "tree" : "" -- строка представляющая собой дерево вложенности вызовов in_group/!in_group -- форматирована переводами строк и отступами для обозначения уровня вложенности >, >
Установить правила фильтрации группы¶
Только для групп с типом filter
Совпадение одного адреса с фильтром группы¶
Вызов в основном полезен для отладки сложных фильтров — по результату label можно видеть ход выполнения условий, а по safe — результат работы итератеров has.
< "match" : 0 | 1 | null -- с фильтром не совпало, совпало, ошибка фильтра ,"safe" : < . >-- данные, сохранённые итератерами has в фильтре ,"label" : < . >-- метки, сохранённые в фильтре при проходе по условиям >
Снимок группы / Расширить группу-список¶
В указанную группу вносятся адреса из другой группы, условия созданного на ходу фильтра или прочих возможных источников.
Так как источником может быть группа-фильтр или просто фильтр, то вы получаете неизменный «снимок» состояния группы на момент вызова.
Это полезно, например, если требуется провести несколько статистических анализов (не надо для каждого анализа заново искать подписчиков по фильтру и их состав не изменен) или для быстрого выхода рассылки с очень сложным фильтром (можно заранее сделать снимок, скажем ночью, и потом днём очень быстро по нему выпустить рассылку).
Также с помощью этого вызова можно добавлять группу-список участников из других групп, условий фильтра или прочих доступных источников
< "action" : "group.snapshot" "to" : < -- получатель данных "id" : "код группы" -- группа-список, в которую будут внесены адреса -- обратите внимание, что это не вызов импорта списков ! -- если адреса, указанные в источниках email, list, stat.uni на момент -- вызова отсутствуют в базе, то они не будут созданы и добавлены, -- для этого есть импорт подписчиков ,"clean" : 0|1 -- полностью очистить группу перед началом внесения ,"resync" : 0|1 -- после внесения новых участников удалить старых, не попадающих более под условия источника -- имеет смысл с group/group.filter/stat.uni, эквивалентно clean=1 для email/list, но более долго по исполнению >,"from" : < -- источник данных одно из "email" : "адрес подписчика" ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn -- или "list" : [ "адрес подписчика" ,"адрес подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный -- или "group" : код группы ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный -- или "group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный -- или "stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный> > ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен ,"sequence.event" : 0|1 -- будет ли добавление в группу генерировать событие для триггеров -- отсутствие или пусто - событий не будет >
< -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса -- ничего дополнительного >
Очистить группу-список¶
Вызов удаляет из участников группы-списка заданные адреса.
Сами адреса в базе остаются ! Удалением адресов из базы занимается вызов member.delete.
< "action" : "group.clean" ,"id" : "код группы" -- группа-список, из которой будут удалены адреса -- указание подписчиков одним из способов ,"all" : 1 -- все адреса, быстрый синхронный вызов -- для получения трекинга или асинхронности, используйте источник "group" c таким же значением что и "id" (более медленно) или ,"email" : "адрес подписчика" -- вызов синхронный ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn или ,"list" : [ "адрес подписчика" ,"адрес подписчика" . ] ,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 1 - синхронный или ,"group" : код группы участники которой будут удалены ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"group.filter" : [ фильтр отбора как у group.filter.set ] ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"url" : ссылка на файл со списком адресов. по одному на строке. возможно сжатие zip. ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный или ,"stat.uni" : < -- адреса для обработки получаются из запроса Универсальной статистики -- подразумевается unique = 1 "filter" : [ условие выборки как у запроса в вызове stat.uni ] ,"have" : [ параметр необязателен, условие отбора - поле группировки в фильтре ] ,"cache" : [ настройки кэширования как у запроса в вызове stat.uni ] ,"select" : [ . ] -- используйте, только если не подходит значение по умолчанию [ "member.email" ] >,"addr_type" : email|msisdn|viber|csid|push|vk|tg|vknotify|id -- тип идентификаторов. Параметр необязателен, система сама распознает email или msisdn ,"sync" : 0|1 -- изменение синхронности запроса, по умолчанию 0 - асинхронный ,"track.info" : "дополнительная информация которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен >
< -- для асинхронного запроса ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- для синхронного запроса -- ничего дополнительного >
Анкеты¶
Анкеты предназначены для описания структуры и иерархии данных для формата АВО.
Список анкет¶
< ,"list" : [ < "system" : "системная, да, нет (1, 0)" -- системные анкеты не доступны для изменения ,"id" : "уникальный идентификатор" ,"name" : "название", >. ] >
Чтение анкеты¶
< ,"obj" : < "id" : код-анкеты, "param" : < "name" : "название анкеты", "system" : 0|1 -- анкета системная, попытки изменения закончатся ошибкой >, "order" : [ -- порядок вопросов "код-вопроса3", "код-вопроса8", . "код-вопроса4" ] "quests" : < -- вопросы анкеты "код-вопроса" : < "id" : код-вопроса, "@" : номер по порядку, "name" : формулировка вопроса, "type" : тип вопроса, -- для типа "dt" "subtype" : под-тип вопроса -- yd - Дата и время с точностью от года до дня -- yh - Дата и время с точностью от года до часа -- ym - Дата и время с точностью от года до минуты -- ys - Дата и время с точностью от года до секунды -- для типа "free" "width" : ширина поля в байтах для типа free -- для типа "1m" или "nm" "answers" : < -- ответы вопроса "код ответа1" : "название ответа1", "код ответа2" : "название ответа2", . "код ответа3" : "название ответа3", >, "order" : [ -- порядок ответов "код ответа3", "код ответа1", . "код ответа2" ], "form" : < -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных >>, . >, >
Удаление анкеты¶
Создание анкеты¶
< ,"id" : "код анкеты" > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Сохранение анкеты¶
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Добавления нового вопроса анкеты¶
< "action" : "anketa.quest.add" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" -- добавление одного вопроса ,obj : < -- описание вопроса "name" : "Текст вопроса" ,"type" : "Тип вопроса" -- free - свободный ввод -- dt - дата и время -- 1m - выбор одного из списка -- nm - выбор нескольких из списка -- int - целое число -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода" -- обязателен, >0 -- для type=dt: ,"dtsubtype" : "точность для даты и времени" -- обязателен -- yd - от года до дня. в данных записывается и выводится в формате "YYYY-MM-DD" -- yh - от года до часа. в данных записывается и выводится в формате "YYYY-MM-DD hh" -- ym - от года до минуты. в данных записывается и выводится в формате "YYYY-MM-DD hh:mm" -- ys - от года до секунды. в данных записывается и выводится в формате "YYYY-MM-DD hh:mm:ss" -- для type=1m или nm (выбор из списка): ,"answers" : < -- ответы вопроса "код ответа 1" : "название ответа1" ,"код ответа 2" : "название ответа2" . ,"код ответа N" : "название ответаN" >,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" . ,"код ответа 4" ] -- необязательные для любого типа ,"id" : "уникальный идентификатор вопроса" -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных -- не обязательно ,"form" : < -- Видимость в форме "hidden" : 0|1 -- 0 - по умолчанию - поле в форме будет полем ввода 1 - поле в форме будет иметь тип hidden и значение default -- Обязательность заполнения ,"mustbe" : 0|1 -- 0 - по умолчанию - поле не обязательно для заполнения (игнорируется для hidden=1) -- при первоначальном отображении формы в поле будет значение default -- 1 - поле обязательно для заполнения -- Значение по умолчанию ,"default" : "значение по умолчанию" -- для всех вопросов кроме 1m и nm ,"default" : [код ответа] -- для вопросов 1m ,"default" : [код ответа1 , код ответа 2, . ] -- для вопросов nm -- в какой вопрос какой анкеты-хранилища копируется результат при подтверждении заполнения формы -- параметры или оба отсутствуют или оба указаны и не пустые -- анкета не может быть системной или показывать на саму себя -- тип вопроса, в который будет идти копирование должен совпадать с типом вопроса в obj -- для вопросов 1m и nm все возможные ответы текущего вопроса должны быть в ответах вопроса в который будет идти копирование ,"trans.ank" : "код анкеты" ,"trans.quest" : "код вопроса" >> -- добавление нескольких вопросов, любая ошибка отменяет все изменения. Будут добавлены или все вопросы или ни ,obj : [ < описание вопроса-1 >, < описание вопроса-2 >. ] -- не обязательно ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет >
< ,"obj" : < объект анкета как из ответа anketa.get >-- если "return_fresh_obj" : "1" -- в зависимости от вида параметра obj в вызове ,"id" : "id-добавленного вопроса" -- или ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове "id-добавленного вопроса-1" ,"id-добавленного вопроса-2" . ] >
Изменение вопроса анкеты¶
< "action" : "anketa.quest.set" ,"anketa.id" : "уникальный идентификатор анкеты вопроса" -- добавление одного вопроса ,"obj" : < -- описание вопроса "id" : "уникальный идентификатор вопроса" ,"name" : "Текст вопроса" -- параметры, определяемые типом вопроса: -- для type=free: ,"width" : "количество символов для свободного ввода, обязателен, >0" -- для type=1m или nm: ,"answers" : < -- ответы вопроса "код ответа 1" : "название ответа 1" ,"код ответа 2" : "название ответа 2" . ,"код ответа N" : "название ответа N" >,"order" : [ -- порядок ответов "код ответа 3" ,"код ответа 8" . ,"код ответа 4" ] ,"form" : < -- свойства вопроса при использовании анкеты в форме как анкеты для первичного приёма данных -- параметр необязателен -- при указании "form" в запросе, все параметры вопроса, связанные с ним, заменяются на новые указанные или удаляются >-- изменение нескольких вопросов, любая ошибка отменяет все изменения. Будут изменены или все вопросы, или не все. ,obj : [ < описание вопроса-1 >, < описание вопроса-2 >. ] -- не обязательно ,"return_fresh_obj" : 0|1 -- вернуть новый объект анкета -- да (1), нет (0, по умолчанию) >
< ,"obj" : < объект анкета как из ответа anketa.get >-- если "return_fresh_obj" : "1" -- в зависимости от вида параметра obj в вызове ,"id" : "id-добавленного вопроса" -- или ,"id" : [ -- порядок id соответствует порядку объектов в параметре obj в вызове "id-добавленного вопроса-1" ,"id-добавленного вопроса-2" . ] >
Удаление вопроса анкеты¶
Удаление нескольких вопросов транзакционно — удаляются или все (нет ошибок), или ни один (хоть одна ошибка).
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Изменение позиции вопроса анкеты¶
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Удаление ответа вопроса анкеты¶
Для вопросов типа «1m» и «nm».
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Изменение позиции ответа вопроса¶
Для вопросов типа «1m» и «nm».
< > если "return_fresh_obj" : "1" ответ -- как на запрос чтения "action" : "anketa.get" соответствующей анкеты
Выпуски рассылки¶
Способы выпуска¶
данное api — выпуск массовых рассылок и индивидуальных cообщений через вызов issue.send данного общего api
шлюз smtp — выпуск индивидуальных писем через протокол SMTP. Для этого свяжитесь со Службой поддержки
потоковое api — выпуск массовых и индивидуальных писем через специализированное api. Для этого свяжитесь со Службой поддержки
Все способы выпуска имеют общую интегрированную статистику по доставкам, открытиям и переходам, доступную через данное общее api (вызов stat.uni).
Варианты выпуска рассылок¶
Все рассылки (email, sms, viber, push, vk, tg, vknotify) выпускаются через вызов issue.send.
Для выпуска веб-пуш (push) необходимо сначала собрать подписчиков на своём сайте, установив и настроив скрипты как описано в «Подписка на веб-пуш».
Для выпуска ВКонтакте (vk) необходимо сначала зарегистрировать сообщество через веб-интерфейс.
Для выпуска Телеграм (tg) необходимо сначала зарегистрировать бота через веб-интерфейс или напрямую через создание внешней авторизации.
Есть пять вариантов использования issue.send:
1) Выпуск по группе-списку — это выпуск по заранее определённому и сохранённому списку получателей, неизменному если вы его не измените сами.
2) Выпуск по группе-фильтру — это выпуск по динамически отбираемому каждый раз сегменту получателей. Например, «Те кто получил письмо за последние 24 часа и ни разу не кликнул» — условие отбора зависит от времени и каждый раз результат будет разный.
3) Экспресс-выпуск — это выпуск по списку с данными для персонализации без его внесения в базу. Список и данные персонализации задаются каждый раз в вызове или указывается откуда их забрать.
Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа «Спасибо за регистрацию» или «Ваш код на сайте» это не Экспресс-выпуск, это транзакционные personal.
Типичная ошибка — использование Экспресс-выпуска для таких индивидуальных писем: система автоматически это замечает и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь.
Если один Экспресс-выпуск — выпуск по списку на много адресов вы разделите на Экспресс-выпуск на маленькие порции этого спискаю, то получится только медленнее. Кроме описанного выше снижения приоритета, в каждый выпуск добавятся затраты на его запуск. Самое долгое — проверка на попадания в спам по нескольким сервисам — это занимает от 20 до 120 секунд и мало от нас зависит, так как это сторонние сервисы. В итоге вы получите такую проверку и затраты времени на неё столько раз, на сколько кусков разрежете один выпуск.
Существует возможность использования Экспресс-Выпуска, что бы разрешиаь третьим лицам выпуски без сообшения им адресов получаетелей.
— загрузите адреса в систему без создания подписчика (импорт с параметром no_member:1)
— создайте саблогин с ограниченными правами для своего подрядчика
— сообщайте ему только номера адресов — member.id — можно получить через member.list
— подрядчик осуществляет Экспресс-Выпуск использую номера адресов с добавлением нужных данных персонализации
4) «Выпуск по группе Экспресс-Импорта» — как Экспресс-Выпуск, но реестре получателей не указывается в задании на выпуск, а берётся загруженый в Экспресс-Импорте.
5) Транзакционные письма — это выпуск одному конкретному получателю с данными персонализации. Именно этот тип выпуска предназначен для писем вида «Спасибо за регистрацию» или «Ваш код на сайте». Для этих выпусков имеется отдельный механизм, который позволяет выпускать их очень быстро. Рекомендуется выпускать Транзакционные письма по заранее сохранённому черновику — это исключает некоторые проверки, что позволяет формировать письмо ещё быстрее.
Группа-спискок | Группа-фильтр | Экспресс-выпуск | Транзакционное письмо | |
Адреса получателей | Заранее созданные в базе список | Динамический поиск по базе адресов данные которых удовлетворяют фильтру | Указываются при выпуске или забираются по ссылке | Указывается при выпуске |
Данные для персонализации | Из базы | Из базы | Указываются при выпуске | Из базы если не указаны при выпуске |
Количество переменных | Не ограничено | Не ограничено | Не ограничено | Не ограничено |
Шаблонизатор | Продвинутый | Продвинутый | Продвинутый | Продвинутый |
Собственные функции-плагины к шаблонизатору | Да | Да | Да | Да |
Сложные вложенные структуры данных | Да, в модели ДК | Да, в моделе ДК | Да | Да |
Подтверждение от владельца адреса | Требуется | Требуется | Требуется | Не обязательно |
Разбор жалоб на спам | Согласно договору | Согласно договору | Согласно договору | С особым пристрастием |
Лимит в месяц | Не ограничено в пределах тарифа | Не ограничено в пределах тарифа | Не ограничено в пределах тарифа | Первоначально равен максимально допустимому количеству адресов в базе. Далее в зависимости от репутации |
Отправить тестовый выпуск¶
Полный аналог «Отправить выпуск» issue.send за исключением того, что любой указанный sendwhen заменяется на test
Основная причина существования — иметь отдельное право на выпуск только тестов. Например, сотрудник «дизайнер» должен не мочь отправлять реальные выпуски (отбираем право issue.send), но тесты для себя должен быть отправить способен (оставляем ему право issue.send.test).
Отправить выпуск¶
Этот вызов асинхронный — получение положительного ответа означает, что задание на рассылку поставлено в очередь. Используйте возвращаемый track.id для отслеживания выпуска.
Это не гарантирует выпуск — он может не состоятся по причинам, которые не проверить на момент вызова (например, недоступность на момент преобразования ссылки, для которой производится преобразование для учёта переходов).
Индивидуальные данные персонализации для каждого адреса берутся из сохранённых в базе (группа-список, группа-фильтр) или из указанных прямо при выпуске (Экспресс-выпуск, Транзакционные письма) и доступны через префикс anketa шаблонизатора.
Данные формата АВО автоматически доступны как преобразованные в формат ДК.
Данные персонализации для каждого получателя могут быть дополнены внешними данными (формат ДК) в процессе выпуска. Подробнее в разделе «Внешние данные для персонализации»
Из списка участников группы и списка Экспресс-выпуска система автоматически исключает адреса, не подтвердившие внесение в базу, отписавшиеся, находящиеся в стоп-листе или имеющие постоянные ошибки доставки. Вам не надо предпринимать никаких дополнительных усилий для этого — всё происходит автоматически.
Для каждого сообщения (email, sms , viber, push, vk, tg, vknotify) система отслеживает статус доставки — доставлено/не доставлено (и с какой ошибкой), для каждой sms — дополнительно размер, предполагаемый оператор и стоимость доставки, для каждого vknotify — стоимость доставки. Это доступно через объект deliv вызова stat.uni (из этого следует что из deliv можно так же получить просто список участников выпуска).
Для каждого успешно доставленного email, viber, push система отслеживает факты открытия и факты перехода по каждой ссылке (если учёт переходов не был отключён при выпуске). Время каждого открытия/перехода и ip-адрес доступны через объекты read и click вызова stat.uni.
Дополнительно различаются открытия/переходы для html и amp-версий email-сообщений (read.source,click.source).
Также система отслеживает вид устройства, операционную систему, браузер и его версию, если произошло чтение или переход из письма. Для чтения также отслеживается его длительность. Это доступно через объект gadget вызова stat.uni.
При установке на страницах сайта специального счётчика, возможно отслеживание пути по сайту и достижения целевых страниц после перехода из письма — подробности в разделе «Целевые Страницы».
Каждое сообщение имеют уникальный идентификатор состоящий из номера выпуска и номера письма в выпуске. Поэтому вы можете получить описанную выше статистику с точностью до каждого email/sms/viber/push/vk/tg/vknotify каждого выпуска для каждого адресата.
Кроме системного уникального номера письма каждому письму можно присвоить клиентскую метку (custid), состоящую из одного или нескольких полей. Для этого настраивается список ключей данных, которые запоминаются в каждом выпуске для каждого получателя (отсутствующие в конкретном выпуске или пустые данные не в счёт). Они доступные через Универсальную статистику и позволяют присваивать письмам удобные для анализа клиента метки. Для настройки этой возможности обратитесь в Службу поддержки.
Благодаря поддержке нескольких идентификаторов у одного подписчика вам доступны разнообразные сценарии мультиканального взаимодействия с ним. Например, «Выслать письмо, а тем кто за 10 дней так и не прочёл и не сделал ни одного перехода, выслать смс».
При получении параметра выпуска из нескольких источников приоритет имеет параметр:
— указанный непосредственно в issue.send
— если параметр не указан или пуст, то параметр берётся из класса выпуска (issue.send, параметр class.id)
— если класс не указан, или параметр в нём не указан или пуст, то параметр берётся из черновика выпуска (issue.send, параметр draft.id)
— если черновик не указан, то берётся значение параметра по умолчанию
— если черновик указан, но параметр в нём не указан или пуст, то параметр берётся из класса черновика (issue.draft.set, параметр class.id)
— если класс не указан, или параметр в нём не указан или пуст, то берётся значение параметра по умолчанию
Исключение — так как параметр group обязателен в issue.send, то из другого источника он получен быть не может.
Исключение — параметр extra. Cуммируется по ключам первого уровня по всем источникам. Приоритет одноимённых ключей первого уровня как описано выше для параметров.
Исключение — список прикрепляемых файлов. Списки, заданные в черновике и выпуске, суммируются. Из двух одноимённых файлов приоритет у того, что указан в выпуске.
Содержимое выпуска из черновика — текст, тема, отправитель и прочее (кроме attaches) — полностью заменяют собой аналогичные параметры letter выпуска и имеет абсолютный приоритет.
Для того чтобы частично заменять в выпусках такие параметры черновика, используйте параметр weak_draft, указывая его одновременно с draft.id. Допустимые значения — пусто (отсутствует) — как по умолчанию в аккаунте (т.е. черновик сильнее параметров), 0 — черновик сильнее параметров, несмотря на настройку акканута, 1 — черновик слабее параметров, несмотря на настройку аккаунта и параметры содержимого выпуска, указанные в вызове заменяют аналогичные из черновика.
Транзакционные письма в течении календарных суток группируются в выпуски на основе номера черновка, использованного DKIM, номера формы или триггера (если письмо вызвано ими). Возможен альтернативный вариант — группировка только на основе первых трёх меток выпуска — настраивается через параметр issue.personal.groupby вызовы sys.settings.set
< "action" : "issue.send" или "issue.send.test", "name" : "Название выпуска", -- параметр необязателен, при отсутствии используется тема письма или имя отправителя sms -- из-за особенностей учёта выходов Транзакционных писем personal данный параметр -- для них будет работать не так, как ожидается и, в целом, бесполезен "label" : "метка" или [ "метка1", "метка2".. ], -- набор произвольных меток выпуска, позволяющих фильтровать/классифицировать -- от 0 до 10 строк не длиннее 128 символов -- параметр необязателен * параметры содержимого выпуска "letter" : < *** для sms * содержимое сообщения или указание параметров "from.name" : "Имя отправителя" -- обязателен и имя отправителя должно быть в списке уже промодерированных имён (вызовы issue.smssender.*) ,"message": < "sms" : "sms cообщение" >или черновик, из которого их взять. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь sms-версию *** для viber * содержимое сообщения или указание параметров "button.url" : "ссылка с кнопки" -- параметр обязателен, если нужна кнопка после сообщения ,"button.text" : "надпись на кнопке" -- параметр необязателен, по умолчанию "Узнать" ,"message": < "viber" : "viber cообщение" -- текст без форматирования >,"attaches": [ -- не обязательно, одна и только одна ссылка на возможную картинку отображаемую между текстом и кнопкой -- при выпуске по черновику, прикрепляемые файлы из черновика добавляются к указанным в списке -- если одноимённый файл или ccылка тут отсутствуют < "url" : "Внешние ссылки http / https / ftp / ftps / sftp" >, -- или < "url" : "персонализированный url - для каждого свой" >, -- подробнее в разделе "Персонализация выпуска" ] или черновик из которого их взять. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь viber-версию *** для push в браузеры * содержимое сообщения или указание параметров "subject" : "тема" -- обязательно ,"click.url" : "ссылка для клика" ,"message": < "push" : "текст cообщения" -- текст с переводами строк >,"icon.url" : "ссылка на иконку" -- https://, обычно 192х192. ,"image.url" : "ссылка на картинку" -- https:// ,"require_interaction" : 0|1 -- для закрытия сообщения ожидать нажатия подписчиком. по умолчанию 1 - ожидать -- глобально для аккаунта можно изменить параметром issue.push.require_interaction -- вызова sys.settings.set ,"actions": [ -- не обязательно, одна или две кнопки описываемые структурой < "action" : "действие кнопки", -- ссылка https:// -- или ключевое слово "close" - просто закрывает сообщение. -- или ключевое слово "clickurl" - при выпуске подставляется ссылка из параметра click.url "title" : "текст кнопки", -- рекомендация: до 36 символов. "icon" : "ссылка иконки кнопки" -- не обязательно -- https:// на том же сайте, где установлен service-worker, размер стороны 16-24 px >, . ] или черновик из которого их взять. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь push-версию *** для vk * содержимое сообщения или указание параметров "subject" : "тема" -- обязательно ,"message": < "vk" : "текст cообщения" -- текст, возможно с переводами строк -- дополнительно распознаются команды: -- * подстановки картинок -- * подстановки видео -- * разбиения текста на части
-- таким образом, в одном сообщении можно -- скомбинировать разные части, которые обычно -- отправляются по отдельности > или черновик из которого их взять. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь vk-версию *** для tg * содержимое сообщения или указание параметров "subject" : "тема" -- обязательно ,"message": < "tg" : "текст cообщения" -- текст MarkdownV2 -- не забывайте правильно экранировать управляющие символы -- -- для прикрепления/встраивания изображений и файлов используйте -- -- ![описание](медиа-ссылка) -- -- и они будут по порядку следования в тексте автоматически оформлены -- соответствующими сообщениями Телеграм -- "описание" в целом не обязательно. тип содержимого определяется по -- расширению файла и может быть уточнён указанием -- mediatype=document|animation|audio|video|voice|photo|venue -- -- Ещё можно указать "Контакт" -- -- ![ИмяКонтакта](+номертелефона) -- -- "Место встречи" (venue) и "Координаты" (location) -- -- ![](59.972611, 30.311311) -- ![SendSay office;SPb, Professora Popova, 23D](59.972612,30.311311?mediatype=location) -- ![SendSay office;SPb, Professora Popova, 23D](https://yandex.ru/maps/2/saint-petersburg/?ll=30.311398%2C59.972617&mediatype=venue) -- ![SendSay office;SPb, Professora Popova, 23D](https://www.google.com/maps/search/59.972612,30.311311?mediatype=venue) -- ![SendSay office;SPb, Professora Popova, 23D](https://www.google.com/maps/place/59°58'21.4"N+30°18'40.7"E?mediatype=venue) -- ![SendSay office;SPb, Professora Popova, 23D](https://google.ru/maps/@59.9723963,30.311142,18.5z?mediatype=venue) -- -- -- особенность при подстановке значений с каким либо оформлением вокруг -- например вот такое -- -- _[% переменная %]_ -- -- при пустом значении переменной приведёт в Телеграм совсем не к тому, что ожидается -- ошибка это или особенность, не известно -- для обхода добавляйте пробел после начального или перед конечным управляющим символом -- -- _[% переменная %] _ -- ^^^ пробел добавлен >,"settings" : < -- не обязательные параметры для специальных вещей -- Для всех деталей смотрите основную документацию Telegram -- -- InlineKeyboardMarkup: https://core.telegram.org/bots/api#inlinekeyboardmarkup -- -- ReplyKeyboardMarkup: https://core.telegram.org/bots/api#replykeyboardmarkup --*-- Кнопка запроса гео-положения -- -- ответ будет сохранён в ключи данных telegram.logitude и telegram.latitude -- "telegram" : < -- "longitude" : "30.12222", -- "latitude" : "59.12345" -- >"reply_markup" : < "keyboard" : [ [ < "text": "Сообщить, где я" ,"request_location": true >] ] > --*-- Кнопка запроса номера телефона -- -- ответ будет сохранён в ключи данных telegram.phone_number, telegram.last_name, telegram.first_name -- "telegram" : < -- "phone_number" : "79110000000", -- "last_name" : "Дед", -- "first_name" : "Ленин" -- >"reply_markup": < "keyboard" : [ [ < "text": "Сообщить телефон","request_contact": true >] ], "one_time_keyboard":true > --*-- Отображение клавиатуры типа ReplyKeyboardMarkup -- -- Данные никак не обрабатываются (не считая передачи далее, если настроено проксирование). -- Но если текст кнопки это команда боту, то она будет выполнена. "reply_markup": < "keyboard" : [ [ < "text": "/help">, ] ], "one_time_keyboard":true> > --*-- Удаление клавиатуры типа ReplyKeyboardMarkup "reply_markup": < "remove_keyboard":true >--*-- Клавиатура типа InlineKeyboardMarkup -- -- Сразу после нажатия кнопки бот отвечает "Вы выбрали ТекстКнопки" с целью зафиксировать в чате выбранный ответ -- -- Код кнопки сохраняется в указанном "datakey" -- -- Если в коде присутствуют команды, то они выполняются, а значение сохраняется без самой команды -- Поиск и обработка команд производится стандартным способом -- -- Для каждой кнопки клавиатуры формируется ссылка для учёта нажатий пользователя, как при нажатии на ссылку - считаются клики и это доступно в Универсальной статистике -- -- Формат ссылки: tgkey:///?code=&text= -- -- Пример tgkey://Name_bot/?code=12345&text=Yes "reply_markup": < "inline_keyboard" : [ [ -- первый ряд клавиатуры < "text" :"Male" , "callback_data": "m" >-- кнопка , < "text" :"Female" , "callback_data": "f" >-- другая кнопка ] ,[ -- второй ряд клавиатуры < "text" :"Kid" , "callback_data": "k" >-- ещё кнопка , < "text" :"Cat" , "callback_data": "c" >-- и ещё кнопка ] . ] > , "datakey": ["base.gender"] -- ключ данных для сохранения значения параметра callback_data нажатой кнопки > или черновик из которого взять текст и настройки. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь tg-версию *** для vknotify Содержимое сообщений должно быть зараннее согласовано с VK ! Только выпуски personal ! * содержимое сообщения или указание параметров "from.name" : "Имя отправителя" -- обязателен ,"message": < "vknotify" : "vknotify cообщение" -- текст до 1000 символов >или черновик, из которого их взять. Приоритет описан выше. "draft.id": "номер черновика, содержимое которого даст выпуск" -- должен иметь vknotify-версию *** для email * содержимое письма или указание параметров (дополнительно смотрите параметр letter.zip ниже "subject" : "Тема письма" -- обязательно не пусто ,"from.name" : "Имя отправителя" ,"from.email" : "Адрес отправителя (email)" -- обязательно не пустой для текстовых писем; адрес должен быть в списке уже подтверждённых адресов (вызовы issue.emailsender.*) -- -- Использование в качестве адреса отправителя адреса, принадлежащие Почте Mail.ru (mail.ru, bk.ru, inboc.ru, list.ru, mail.ua) - запрещено настройками Mail.Ru -- Рассылка с таким адресом не выйдет. Черновик - не сохранится. ---Более подробную информацию вы можете прочитать по адресу https://corp.mail.ru/ru/press/releases/9593/ ,"reply.name" : "Имя для обратного адреса для ответа" ,"reply.email" : "Обратный адрес для ответа (email)" -- адрес должен быть в списке уже подтверждённых адресов (вызовы issue.emailsender.*) -- возможен учёт и статистика ответов получателей -- для этого необходимо активировать через Службу поддержки настройку "Перехват ответов на письма выпуска" -- статистика доступна через deliv.replyed.* вызова stat.uni ,"to.name" : "Имя получателя" -- в этом поле уместна персонализация для подстановки имени и фамилии получателя ,"message": < -- одна или обе не пустые версии письма "html" : "html-версия письма" ,"amp" : "amp-версия письма" -- подробнее про особенности работы можно прочитать в нашей статье -- https://docs.sendsay.ru/email-campaigns/create-your-campaign/amp-campaign ,"text" : "текстовая версия письма" >или черновик из которого их взять. Приоритет описан выше "draft.id": "номер черновика содержимое которого даст выпуск", -- должен иметь html и/или текстовую версию * генерация текстовой версии из html -- при отсутствии текстовой версии и включённой её автоматической генерации из html-версии письма, создаётся текстовая версия -- поддерживаются базовые виды выделения текста. Таблицы не поддерживаются по умолчанию, но это можно обсудить со Службой поддержки "autotext" : 0|1|ширина -- 0 - отключено (по умолчанию) -- 1 - включено, ширина строки 80 символов -- ширина - включено, ширина строки - указанное число * прикреплённые файлы письма -- по умолчанию, mime-тип файла определяется по расширению -- по умолчанию, кодировкой текстовых файлов text/* считается utf-8 -- следующие имена файлов зарезервированы для внутренних нужд и не должны использоваться -- -- все начинающиеся с _ -- -- message.text -- message.sms -- message.viber -- message.push -- message.vk -- message.tg -- message.vknotify -- -- index.html -- index.htm -- index.shtml -- index.shtm -- -- attach.html -- attach.htm -- attach.shtml -- attach.shtm -- -- message.html -- message.htm -- message.shtml -- message.shtm ,"attaches": [ -- при выпуске по черновику, прикрепляемые файлы из черновика добавляются к указанным в списке -- если одноимённый файл или ccылка тут отсутствуют < "name" : "имя файла", ,"content": "содержимое файла закодированное base64", ,"encoding" : "base64", ,"mime-type" : "тип аттача", -- параметр необязателен, заменяет тип установленный по расширению имени аттача ,"charset" : "набор символов аттача", -- параметр необязателен, заменяет используемое по умолчанию utf-8 >, < "name" : "имя файла", ,"content": "содержимое файла", ,"mime-type" : "тип файла", -- параметр нобязателен, заменяет тип установленный по расширению имени файла ,"charset" : "набор символов файла" -- не обязательно, заменяет используемое по умолчанию utf-8 >, < "url" : "url откуда забрать. Внешние ссылки http / https / ftp / ftps / sftp или из хранилища загрузок rfs://upload/путь-до-файла " ,"mime-type" : "тип аттача", -- не обязательно, заменяет тип установленный по расширению имени аттача или полученный в ответ на запрос ,"charset" : "набор символов аттача", -- не обязательно, заменяет используемое по умолчанию utf-8 или полученный в ответ на запрос >, < "url" : "персонализированный url откуда забирать - для каждого свой" >, -- подробнее в разделе "Персонализация выпуска" -- генерация персонального pdf-документа на ходу. подробнее в разделе "Персонализация выпуска" < "pdf" : "номер черновика">-- генерация персонального excel-документа на ходу. подробнее в разделе "Персонализация выпуска" < "xlsx" : "номер черновика">. ] > * текст выпуска и картинки из архива (для email). не для Транзакционных выпусков -- В архиве ищется индексный файл, который даст текст выпуска - это первый регистронезависимый файл *.htm(l) с наименьшим уровнем вложенности и наименьшим среди одноуровневых именем. -- Остальное содержимое каталога, в котором он находится сохраняется в Хранилище картинок. -- Остальные части архива игнорируются. -- В содержимом индексного файла относительные ссылки в img-src и ссs-url() дополняются веб-базой каталога, куда было сохранено содержимое. -- Полученный результат записывается в letter-> message->html (т.е. это будет email). -- Остальные параметры по-прежнему передаются через явно указанный в вызове letter (например, тема). -- Если в вызове уже есть letter и в нём есть есть message, то это ошибка. ,"letter.zip" : "содержимое архива закодированное в base64" -- zip-архив, содержащий текст выпуска (в utf-8) и сопровождающие картинки для оформления * получатели выпуска ,"group" : "id группы | masssending - если это Экспресс-Выпуск | personal - Транзакционное письмо", -- -- Eсли фильтр группы описан в формате КД и в нём используется оператор has с параметром save, -- то один участник группы может попасть в рассылку несколько раз в зависимости от количества -- срабатываний has/save и параметра выпуска "multiple". -- В описании фильтра формата КД описано когда и чем это полезно. -- Выпуск Транзакционного письма (personal) в каналах Телеграм и ВКонтакте не может быть произведён -- "просто так", необходимо указывать какой бот или сообщество использовать. -- Для этого при personal необходимо указать дополнительный параметр-подсказку в выпуске или в черновике (для выпуска из триггеров, например) ,"basegroup.id" : "группа бота или сообщества" -- tg_xxxx или vk_xxx * параметры способа выпуска ,"sendwhen": "Когда выпустить (now - сейчас | later - отложенный | delay - задержанный | save - отложить на хранение | test - тестовый)", -- при использовании в "Действиях по расписанию" допустимы только now и test -- Тестовый выпуск не доступен для Экспресс-выпуска, Транзакционных писем -- Одновременно может быть не более 100 отложенных (later), задержанных (delay) и на хранении (delay) выпусков. Если этого мало, то свяжитесь со Службой поддержки. ,"weak_draft": "не обязательно. описано выше" ,"dkim.id" : "номер проверенного dkim-ключа или 0" -- если строго "0", то будет использоваться общий системный ключ -- если пусто/не задано/невалиден, то будет взят из черновика - если в черновике строго "0", то будет использоваться общий системный ключ -- если в черновике не задан или на момент выпуска выбранный ключ из черновика окажется не проверенным, -- то будет использоваться самый свежий из ключей, имеющихся для домена отправителя (from.email из вызова или черновика) (учтите правила поиска из вызова issue.dkim.create если dkim-ключ привязан к саблогину) -- если ключа точно по домену не будет, то домен будет сокращён на один уровень и поиск будет повторён, и так до домена второго уровня включительно -- если и ключа по домену, и его сокращённых вариантов не будет или на момент выпуска выбранный ключ по домену окажется не проверенным, -- то будет искаться любой валидный DKIM для любого возможно настроенного поддомена для домена отправителя (это не стандартный шаг, если такой поиск нужен, то попросите Службу поддержки его активировать) -- если такой есть, то будет использоваться самый свежий по времени настройки, -- будет использоваться значение, установленное через sys.settings.set -- если и его нет или не проверено, то будет использоваться общий системный ключ -- фильтр включения в выпуск - только адреса, попадающие под этот фильтр будут пропущены в выпуск -- в Экспресс-выпуске фильтр всегда работает по данным реестра, даже если получатель есть в базе как подписчик ,"issue_include_filter" : "код группы" -- или ,"issue_include_filter" : [ фильтр как group.filter.set ] -- фильтр исключения из выпуска - адреса, попадающие под этот фильтр будут исключены из выпуска -- в Экспресс-выпуске фильтр всегда работает по данным реестра, даже если получатель есть в базе как подписчик ,"issue_exclude_filter" : "код группы" -- или ,"issue_exclude_filter" : [ фильтр как group.filter.set ] -- Группы списки для исключения получателей ,"group.exclude" : [ "id-группы1", "id-группы2" . ] -- Если адрес получателя присутствует хотя бы в одной из указанных групп-списков, -- то он исключается из выпуска -- Это работает быстрее чем issue_exclude_filter -- Эта возможность позволяет, например, реализовать "стоп-лист по тематикам" - в письме -- размещается дополнительная ссылка "Не хочу получать эту тематику" ведущая на Форму -- А в выпусках "этой тематики" указывается исключить группу-список "Заполнившие Форму" -- список попавших в выпуск ,"issue_member_list" : "код группы-списка попавших в выпуск" -- в указанную группу-список накапливаются адреса, -- попавшие в выпуск по данному классу. -- каждый адрес вносится только один первый раз -- список отписавшихся из выпуска ,"unsub_list" : "код группы-списка отписавшихся из выпуска" -- В указанную группу-список накапливаются адреса, -- нажавшие в выпуске "ссылку тематической отписки" -- Каждый адрес вносится только один первый раз -- При последующих выпусках по этому классу -- участники - это группы-списка из него исключаются -- Ссылка тематической отписки оформляется как [% param.url_unsub_topic %] -- Также можно использовать ссылку "Отмены тематической отписки", -- оформляемую как [% param.url_unsub_topic_cancel %] -- Подписчики, нажавшие её в каком либо имеющимся у них старом письме -- (новые они не получают из-за нахождения в группе-списке отписки), -- удаляются из группы отписки и со следующего выпуска по этому -- классу могут опять получать письма (если нет других препятствий) -- игнорирование стоп-листа ,"ignore_stoplist" : 0|1 -- игнорировать пользовательский стоп-лист при выпуске -- доступно только при заключении отдельного соглашения ,"class.id" : "идентификатор класса выпуска" -- возможный источник параметров выпуска для тех, что не указаны непосредственно в issue.send ,"campaign.id" : "код кампании" -- или ,"campaign.id" : [ "код кампании 1", "код кампании 2" . ] -- Код кампании в которую будет включён выпуск -- пусто или не указан - будет включён в кампанию, если она указана в черновике -- 0 - не будет включён ни в какую кампанию, даже указанную в черновику -- не может быть указан с другими кодами если их несколько -- Код кампании (указанный или полученный из черновика) игнорирует если выпуск выходит -- в рамках АБ-тестирования или триггерной рассылки -- При успешном создании задания отложенного выпуска, он автоматически вносится в кампании указанные в campaign.id -- При выходе отложенного выпуска ранее заданный campaign.id игнорируется и выпуск вносится только в те кампании, -- в которых на момент выпуска состоит задание отложенного выпуска, сработавшее в кроне естественным путём (cron.runonce не считается) * при отложенном выпуске (later) указывается дополнительно дата, час и минута, не ранее которых выпускать -- Если на такие же дату-время уже запланирован выпуск по такой же группе, то новое задание принято не будет. -- ИСКЛЮЧЕНИЕ - Экспресс-выпуск и Транзакционные письма. -- Выпуски по этим группам могут быть запланированы на одну и ту же дату в любом количестве. "later.time" : "YYYY-MM-DD hh:mm" -- рекомендуемая точность - 5 минут. Т.е. mm из набора 0,5,10,15,20,25,30,35,40,45,50,55 -- другие значение mm допустимы, но фактически при выпуске могут быть округлены системой -- до ближайшего большего значения из указанного набора -- время не должно быть в прошлом * при задержанном выпуске (delay) указывается дополнительно на сколько минут задержать выпуск. -- Так как "задержка" реализуется созданием отложенного выпуска на "текущее время + delay.time", -- то действуют ТАКИЕ ЖЕ ОГРАНИЧЕНИЯ, что и при использовании later.time "delay.time" : "mm" * для Email - при выпуске теста (test) указываются адреса получателей. не более пяти. "mca": [ "e@mail.1", "e@mail.2", . ] * для Email - параметры преобразования ссылок для учёта перехода по ним в системе -- каждая ссылка в выпуске обсчитывается отдельно (даже повторяющиеся), -- но на это можно повлиять через параметр data-do-link-same "relink" : 0|1 -- Преобразовывать ссылки автоматически. По умолчанию - 1 - преобразовывать -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе, -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < -- если relink = 1, а какой то из параметров relink.param не указан, -- то считается что: link=1 и test=1 соответственно для всех рассылок кроме personal -- для personal это: link=1 и test=0 - объяснение ниже "link" : 0|1 -- преобразовывать ссылки тега -- 1 - да, 0 - нет -- преобразуются ссылки со схемами: http(s)://, ftp(s)://, viber://, fb-messenger://, skype:// "test": 0|1 -- проверять существование адресов (только если адрес подлежит преобразованию) -- 1 - да, 0 - нет -- при включённой проверке выпуск не выйдет если ссылка -- не действительна (ответ не 2xx, не 301, 302, 303, 307, 308 или 401 или тайм-аут 30 секунд) -- при положительных ответах 3хх дальнейшая проверка по пути редиректа не производится -- настройка "test"=1 не действует на домены vk.com, vkontake.ru, ok.ru, my.mail.ru, facebook.com, fb.com, instagram.com, twitter.com, -- pinterest.com, youtube.com, rutube.com, rutube.com, linked.in, odnoklassniki.ru, ok.ru, telegram.me, t.me, apps.apple.com, -- itunes.apple.com, play.google.com -- и их мобильные версии с префиксом "m" и версии с префиксом "www" -- ссылки с их использованием не проверяются на существование из-за непредсказуемости результата -- указывайте таким ссылкам явно data-do-link-test=1 для осуществления проверки -- никогда не проверяются ссылки с персонализацией и со схемами viber://, fb-messenger://, skype:// -- при выпуске А/B-тестирования всегда устанавливается test=0, так как такая проверка типичный источник -- проблем, когда одна часть теста выходит, а другая - нет -- указывайте ссылкам явно data-do-link-test=1 для осуществления проверки при А/B-тестировании -- Обратите внимание, что массовая отсылка выпусков Персональных gисем, может вызвать -- проблему выпуска из-за неудавшейся проверки адресов. Причина - система анализа частоты -- запросов сайта, для которой проверяется ссылка, может воспринять многократные постоянные -- запросы несколько подряд раз за короткое время (а именно так это будет выглядеть при массовой -- отсылке Персональных писем) как атаку на сайт и не давать проверить ссылку. -- Поэтому по умолчанию для personal проверка ссылок не производится. -- Включить её для всего выпуска вы всегда можете, задав параметр test в явном виде. -- Включить её для отдельных выпусков вы всегда можете атрибутом data-do-link-test -- Глобальные настройки из relink.param можно переопределить для любого -- конкретного тега A, указав в них нестандартные атрибуты -- "data-do-link-relink" и "data-do-link-test", влияющие на преобразование -- и тестирование по следующим правилам: -- -- Атрибут отсутствует или пуст - учитывается глобальная настройка -- Атрибут = 1 - делать действие, несмотря на глобальную настройку -- Атрибут = 0 - не делать действие, несмотря на глобальную настройку -- -- В отличие от параметра "test", зависящего от "link", -- явное указание атрибута data-do-link-test="1" всегда вызывает проверку ссылки -- несмотря на то, что преобразование для неё может и не проводиться -- из-за настроек link/data-do-link-relink -- несмотря на указание test=1, проверка не будет производиться, если через sys.settings.get -- установлено issue.link.notest = 1 (по умолчанию = 0). Только явное указание в теге А параметра data-do-link-test = 1 -- заставит всё же провести проверку -- В некоторых случаях например, блок товара с картинкой-названием-описанием с одной и той же ссылкой с каждого элемента, -- может не требоваться различать, какую именно ссылку нажали (карта кликов становится проще). -- Для того чтобы одинаковые ссылки получили в выпуске общий учёт переходов, надо явно указать в теге А - в атрибуте data-do-link-same="метка объединения", где "метка объединения" любое не пустое значение. -- Одна и та же ссылка, встреченная в любом месте выпуска и имеющая одну и ту же метку объединения, будет использовать -- один и тот же учёт переходов в этом выпуске. -- Разные ссылки могут иметь одинаковую метку - ссылки будут объединяться, но каждая с такими же как она. -- Метка нигде не запоминается - она только подсказывает при формировании выпуска, что ссылки различать не надо. > * для Viber - параметры преобразования ссылок для учёта перехода по ним -- Аналогично как для Email, но действует только на ссылку button.link, поэтому не имеет варианта image и не применимы замечания про атрибуты data-do-relink-* "relink" : 0|1 -- Преобразовывать ссылки автоматически. По умолчанию - 1 - преобразовывать -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < "link" : 0|1 "test" : 0|1 >* для Push - параметры преобразования ссылок для учёта перехода по ним -- Не имеет варианта image и не применимы замечания про атрибуты data-do-relink-* "relink" : 0|1 -- Преобразовывать ссылки автоматически. По умолчанию - 1 - преобразовывать -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < "link" : 0|1 -- действует на click.url "test": 0|1 -- действует на click,url, icon.url, image.url, actions.*.action >* для VK - параметры преобразования ссылок для учёта перехода по ним -- Не имеет варианта image и не применимы замечания про атрибуты data-do-relink-* "relink" : 0|1 -- Преобразовывать ссылки автоматически. По умолчанию - 1 - преобразовывать -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < "link" : 0|1 "test": 0|1 >* для TG - параметры преобразования ссылок для учёта перехода по ним -- Не имеет варианта image и не применимы замечания про атрибуты data-do-relink-* "relink" : 0|1 -- Преобразовывать ссылки автоматически. По умолчанию - 1 - преобразовывать -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < "link" : 0|1 "test": 0|1 >* для SMS - параметры преобразования ссылок для учёта перехода по ним -- Ссылки преобразуются через сокращатель, что дополнительно снижает длину (и, значит, цену) сообщения -- Доступна статистика переходов для тех, ссылок которыми воспользовались получатели "relink" : 0|1 -- Преобразовывать ссылки автоматически -- 1 - да -- 0 - нет -- не указано, пусто, null - по умолчанию -- -- По умолчанию 0 - в отличии от других форматов ! -- -- при сочетании c relink из черновика/класса значения 0, 1 и пусто перебивают указание в черновике/классе -- а при отсутствии в вызове или указании null - значение из черновика/класса сильнее "relink.param" : < "link" : 0|1 -- по умолчанию 0 "test" : 0|1 -- по умолчанию 0 >* для Email - параметр преобразования ссылок для отслеживания перехода по ним с помощью сторонних сервисов "link.qsid": "Параметр для отслеживания переходов по ссылкам через сторонние сервисы" -- добавляется ко всем ссылкам через query-string -- значение должно быть уже url-encoded -- при выпуске по черновику, если этот параметр пуст, то берётся link.qsid из черновика -- обычно содержит utm-метки и используется для отслеживания через сервисы типа Google Analitics -- не имеет ни какого отношения к параметра relink* -- если к какой-то ссылке параметр добавлять не требуется, то укажите в теге нестандартный -- параметр data-no-qsid со значением 1 * для Viber - параметр преобразования ссылок для отслеживания перехода по ним с помощью сторонних сервисов -- Аналогично как и для Email, но действует только на ссылку button.link "link.qsid": "Параметр для отслеживания переходов по ссылкам через сторонние сервисы" * для Push - параметр преобразования ссылок для отслеживания перехода по ним с помощью сторонних сервисов -- Аналогично как и для Email, но действует только на ссылку click.url "link.qsid": "Параметр для отслеживания переходов по ссылкам через сторонние сервисы" * для VK - параметр преобразования ссылок для отслеживания перехода по ним с помощью сторонних сервисов -- Аналогично как и для Email "link.qsid": "Параметр для отслеживания переходов по ссылкам через сторонние сервисы" * для TG - параметр преобразования ссылок для отслеживания перехода по ним с помощью сторонних сервисов -- Аналогично как и для Email "link.qsid": "Параметр для отслеживания переходов по ссылкам через сторонние сервисы" * список получателей и данные персонализации для Экcпресс-выпуска -- подробнее в разделе "Форматы данных для импортирования и Экспресс-выпуска" -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" -- Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа "Спасибо за регистрацию" или "Ваш код на сайте" это не сюда, это Транзакционные personal. -- Типичная ошибка - это использование Экспресс-выпуска для таких индивидуальных писем - система автоматически это замечает, и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь. "users.list": адреса и данные персонализации -- непосредственно в СSV или XLSX -- рекомендуется CSV - XLSX всё равно преобразуется внутри в CSV для того, чтобы подключить многопоточную обработку, а преобразование хоть и быстрое -- (тысячи строк с секунду), но на большом реестре всё равно займёт заметное время или -- Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа "Спасибо за регистрацию" или "Ваш код на сайте" это не сюда, это Транзакционные personal. -- Типичная ошибка - это использование Экспресс-выпуска для таких индивидуальных писем. Система автоматически это замечает, и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь. "users.list" : < "encoding" : "base64" ,"content" : "адреса и данные персонализации в base64" -- вариант для CSV и XLSX которые не получается передать в двоичном виде >, или -- Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа "Спасибо за регистрацию" или "Ваш код на сайте" это не сюда, это Транзакционные personal. -- Типичная ошибка - это использование Экспресс-выпуска для таких индивидуальных писем. Система автоматически это замечает, и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь. "users.list" : [ -- данные в формате JSON-массив < данные одного получателя >. ] или -- Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа "Спасибо за регистрацию" или "Ваш код на сайте" это не сюда, это Транзакционные personal. -- Типичная ошибка - это использование Экспресс-выпуска для таких индивидуальных писем. Система автоматически это замечает, и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь. "users.list" : < -- данные в формате JSON-объект-ABO "caption" : [ описание столбцов ] ,"rows" : [ [ данные одного получателя ] . ] >или -- Экспресс-выпуск предназначен для рассылки общей для многих получателей информации. Разовые письма типа "Спасибо за регистрацию" или "Ваш код на сайте" это не сюда, это Транзакционные personal. -- Типичная ошибка - это использование Экспресс-выпуска для таких индивидуальных писем. Система автоматически это замечает, и такие выпуски получают очень низкий приоритет и выходят в последнюю очередь. "users.url": "url" -- по которому находятся список адресов с данными для персонализации -- внешние ссылки http / https / ftp / ftps / sftp или из хранилища загрузок rfs://upload/путь-до-файла -- Для запросов по SOAP (например, к Siebel) схемы soap:// и soaps:// - обратитесь с Службу поддержки -- для получения дополнительной информации -- Для запросов из Google Big Query настройте внешнюю авторизация для схемы gbd:// (описано в вызовах authext.*) -- Данные получаются полной выборкой, из указанной в url вида gbd://authext:AUTHEXT_ID@DATASET_ID/TABLE_ID таблицы. -- Одна из колонок таблицы должна называться email - она послужит источником адресов получателей и доступно при персонализации текста письма под стандартным именем anketa.member.email. -- Название остальных колонок неважно, но оно должно начитаться с латинской буквы и продолжаться латинскими буквами и цифрами. -- Для использования данных в персонализации используйте подстановки вида [% anketa.t.НАЗВАНИЕ-КОЛОНКИ-ТАБЛИЦЫ %] для всех колонок таблицы кроме email. -- При оформлении выпуска как действия по расписанию не забудьте, что эту ссылку можно кастомизировать -- временем и указать количество и интервал попыток получения данных. Подробнее в разделе "Общие замечания". ,"users.url.remove" : "none|always|onerror|onok" -- параметр необязателен -- применимо только к rfs:// и http(s):// -- none - не удалять. По умолчанию -- always - всегда -- onerror - при завершении с ошибкой -- onok - при завершении без ошибок * параметры списка получателей для Экспресс-выпуска "only_unique": 0|1 -- Следить за уникальностью адресов в списке -- 1 - да, повторно встреченные адреса исключаются из выпуска -- 0 - нет, повторно встреченные адреса участвуют в рассылке * параметры объединения Экспресс-выпусков "accumulate" : 0|1 -- только для Экспресс-выпуска -- если Экспресс-выпуск с такими же именем (параметр "name") когда-либо уже выпускался в текущем интервале накопления, -- то этот запускаемый выпуск будет оформлен не как новый, а как продолжение уже вышедшего. -- полезно в случае, если ваши CRM не может выдать весь реестр для рассылки за раз, -- а только порциями. -- с учётом параллельности приёма и выпуска заданий на рассылку, настоятельно рекомендуется -- выпустить сначала первую порцию и потом уже последующие можно запускать параллельно "accumulate_by" : "month|week|day" -- интервал накопления. Параметр необязателен. По умолчанию month, если не изменено через sys.settings.set issue.accumulate_by -- календарная неделя, приходящаяся на два месяца, - это две разные недели для обеспечения правильного учёта месячного лимита трафика -- без разницы, какой именно интервал накопления был (и был ли вообще) у выпуска, который будет выбран базовым -- например, первого числа в понедельник выпуски с любым интервалом накопления будут использовать один и тот же выпуск с нужным именем как базовый, -- так как он будет удовлетворять и условию, что он в один и тот же день, и условию, что в одну и ту же неделю, и условию, что в один и тот же месяц * учёт множественных совпадений итератор в фильтре "multiple" : 0|1 -- что делать с множественными совпадениями итератора -- 0 - по умолчанию, выпустить одно письмо -- 1 - по одному письму на совпадение -- В описании фильтра формата КД описано когда и чем это полезно. * получатель для Транзакционных писем "email" : "адрес получателя или номер телефона получателя" -- данные для персонализации берутся из базы -- -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" -- -- при этом способе указания получателя он проверяется на возможность отсылки ему письма -- (синтаксическая верность адреса, стоп-лист, ошибки доставки, отписался) и вы сразу получите -- в ответ описание ошибки, если она есть -- при других способах задания получателя, проверка на возможность выпуска происходит -- только при формировании рассылки "customer.id" : "клиентский идентификатор письма" -- параметр необязателен, до 255 байт -- ваш идентификатор письма (например, номер вашего клиента) -- возвращается в callback и доступен через Универсальную статистику stat.uni -- доступен в шаблонизаторе как anketa.customer.id или "users.list": один адрес и данные персонализации -- непосредственно в JSON (два варианта) или в СSV или XLSX -- подробнее в разделе "Форматы данных для импортирования и Экспресс-выпуска" -- при указании только адреса данные персонализации берутся из базы -- при указании более чем одного адреса - ошибка выпуска -- данные персонализации могут быть дополнены внешними данными в процессе выпуска -- подробнее в разделе "Внешние данные для персонализации" * Ограничение на размер тиража -- параметр необязателен, по умолчанию - "100%" ,"users.slice" : "число" - тираж составит не более "число" первых получателей. Число - целое число больше нуля или ,"users.slice" : "процент%" - тираж составит указанный процент от всех получателей. Процент - целое число больше нуля и меньше 101 * Ограничение количества контактов на получателя -- ограничивает число высылаемых сообщений для каждого получателя -- -- если за последний interval получателю уже сформировано max и более сообщений, то он исключается из текущего выпуска -- -- если у выпуска есть класс (указан или получен из черновика), то в расчёт лимита берутся только выпуски, вышедшие по такому же классу -- -- если у выпуска нет класса , то в расчёт лимита берутся вообще все выпуски -- -- должны быть заданы оба параметра сразу или ни одного -- -- параметр необязателен, по умолчанию не ограничено ,"contact_rate" : < "interval" : "часы" -- за сколько последних часов проверять. Число от 1 или -1 за всё время -- или "interval" : "днейd" -- за сколько последних дней проверять. День начинается в 00:00:00. Число от 1 с окончанием "d" -- например: -- 1d - за сегодня, т.е. с 00:00:00 сегодня -- 2d - за вчера и сегодня, т.е. с 00:00:00 вчера ,"max" : "число" -- лимит сообщений. число от 1 >* Высылка письма в наиболее подходящее для каждого получателя время индивидуально на основе его прошлой активности -- для активации данной возможности просто обратитесь в Службу поддержки -- например, -- day и 4 - учитывая статистику дней недели, выбрать наилучшее время в ближайшие 4 часа -- week и 12 -учитывая суммарную статистику недели, выбрать наилучшее время в ближайшие 12 часа -- -- если используется day и в указанном интервале вообще не было активности, то алгоритм переключается на week, при этом interval устанавливается в 24, если он был более 24 -- -- если в указанном интервале лучшими являются несколько часов, то выбирается самый ранний -- -- не совместимо с выпуском по часовым поясам tz_observance -- -- заданы оба параметра сразу или ни одного -- -- параметр default необязателен и не учитывается без source и interval ,"tz_best" : < "source" : "day" или "week" -- лучшее время определять с учётом дня недели выпуска рассылки (day) или по суммарным данным всех дней недели (week). По умолчанию - day ,"interval" : число от 1 до 24 для week и от 1 до 168 для day -- число ближайших от выпуска часов, среди которых искать наилучший (считая и час выпуска). По умолчанию - 4 ,"default" -- от 00 до 23 -- час начала для тех, у кого время не определилось -- параметр необязателен, по умолчанию - текущий час для выпуска "сейчас" -- или час запуска для отложенного выпуска - т.е. для них письма будут -- отправляться сразу при выпуске -- если час указан, то начнут отправлять им письма, начиная с указанного часа сегодня, -- а если он уже полностью прошёл - с этого часа завтра >* Ограничение на частоту отправки -- -- Все ограничения касаются только первой попытки отправки сообщения. -- Если сообщение не принято сразу, то ограничения могут не быть соблюдены. -- При совместном использовании с tz_observance, ограничение на частоту отправки действует независимо в каждом -- часовом поясе. -- Для SMS частота автоматически ограничивается в каждом часовом поясе отдельно и без tz_observance. ,"tz_limit" < "default" : < -- ограничение на частоту отправки сообщений -- за rate минут будет передано в доставку в не более number сообщений -- начиная со второго раза, number будет увеличиваться на increase каждый раз от текущего значения -- Если параметр отсутствует или пуст или обе величины равны 0, -- то ограничения нет. "batch" : < -- или отсутствуют или указаны оба значения "number" : "сколько cообщений" -- обязательно, >= 200 ,"rate" : "за сколько минут" -- обязательно, >= 0 -- не обязательно, по умолчанию 0 ,"increase" : число -- увеличение number на указанное целое число, >= 0 -- или ,"increase" : "число%" -- увеличение number на указанное число процентов, >= 0 -- процент принимается с точностью до сотых -- при малых number, если наращивание даёт менее 1 получателя -- то принимается увеличение на 1 получателя -- процент равный нулю - отсутствие наращивания > > > * Учёт часового пояса получателя -- Параметр необязателен. -- Для не SMS при отсутствии учёта часового пояса всё выходит сразу (если нет прочих настроек). -- Для SMS при отсутствии явно заданного учёта часового пояса он учитывает на основании номера телефона. -- Не совместимо с tz_best. -- При выпуске с учётом временной зоны, письма будут заранее сформированы, но их первая попытка -- доставки начнётся не ранее, чем во временной зоне получателя начнётся указанный час -- по его локальному времени. -- -- Источником данных может быть один или несколько пунктов анкеты подписчика. -- -- Берётся первое определившееся время по порядку указания источников. -- -- Если часовой пояс не удалось определить ни по одному из источников, то письмо начинает -- доставляться как описано в default (с учётом tz_limit). -- -- В качестве указания на часовой пояс понимаются названия большинства стран и крупных городов -- в английском и русском написании (регистр не важен). -- -- А также числовые смещения относительно UTC в виде: -- -- +hhmm -hhmm UTC+hhmm UTC-hhmm -- +hh -hh UTC+hh UTC-hh -- +h -h UTC+h UTC-h -- hh -- h -- -- Используйте вызов sys.settings.get, чтобы проверить понимает ли система ваш способ записи. -- Если нет - обратитесь в Службу поддержки за расширением нашего списка городов и стран. -- -- Во избежание путаницы с пониманием часовых поясов, настоятельно рекомендуется планировать -- такие рассылки не менее чем за 24 часа и учитывать особенности России - текущий час в Москве -- по всех других часовых поясах страны (за исключением Калининграда) уже прошёл и настанет -- там через через 15-23 часа в зависимости от удалённости. -- При совместном использовании с tz_limit ограничение на частоту отправки действует независимо в каждом -- часовом поясе. -- Настройка может быть указана и будет учтена по убыванию приоритета: при выпуске, в классе выпуска, в черновике, в классе черновика, глобально (sys.settings.set) -- Если требуется отключить соблюдение местного времени, то в более приоритетном источнике необходимо задать tz_observance.source с не существующим ключом данных. ,"tz_observance" : < -- не обязательно "hour" : "час" -- от 00 до 23 -- час по местному времени для начала доставки писем -- не обязательно, по умолчанию - час из default ,"source" : [ -- параметр обязателен. Источники данных о временной зоне подписчика в его анкете. -- один и более. -- рекомендуется заполнять и использовать base.tz - поле "Часовой пояс" анкеты "Базовая" -- при отсутствии своих данных, можно использовать member.last.tz - автоматически -- обновляющееся системой значение на основании последнего клика или чтения "ключ-данных" ,"ключ-данных" ,"ключ-данных" . ] ,"default" -- от 00 до 23 -- час начала для тех, у кого местное время не определилось -- параметр необязателен, по умолчанию - текущий час для выпуска "сейчас" -- или час запуска для отложенного выпуска - т.е. для них письма будут -- отправляться сразу при выпуске -- если час указан, то письма начнут отправлять, начиная с указанного часа сегодня, -- а если он уже полностью прошёл - с этого часа завтра >* время жизни сообщения для Email ,"ttl" : число -- время в секундах хранения сообщения при невозможности доставить сразу (ошибки доставки 4xx) -- параметр необязателен. По умолчанию 4 дня -- не рекомендуется задавать менее 1 часа. Если всё же попробуете - расскажите нам, как получилось. * время жизни сообщения для Push ,"ttl" : число -- время в секундах хранения сообщения при невозможности отобразить сразу -- параметр необязателен. По умолчанию 12 часов * забота о переменных ,"care_vars" : [ список ключей данных ] -- не обязательно -- указанные в списке переменные ProScript проверяются для каждого письмо на пусто-непусто -- если пусто, то письмо отменяется с причиной "care for var VAR" -- проверяются только переменные название которых состоих из символов @a-zA-Z.[_]@ -- cписок из выпуска имеют приоритет над черновиком -- cписок ни как не проверяется на использование или не использование его переменных в их тексте -- или наличие в данных персонализации -- проверка реализуется через специальный ProScript вставляемый без перевода строки перед началом -- текста сообщения. при успешной провеке он не оставляется после себя ни какого текста. * данные произвольной структуры *одинаковые для всех подписчиков* -- эти данные трактуются в по модели КД -- эти данные будут доступны для шаблонизатора выпуска как переменные с именем, совпадающим с именем ключа хэша -- эти данные могут быть дополнены из черновика. указанные здесь имеют больший приоритет. -- эти данные могут быть дополнены внешними данными в процессе выпуска - подробнее в разделе "Внешние данные для персонализации" -- в настоящий момент зарезервированы имена: -- anketa - данные о конкретном подписчике -- lenta - данные для подстановки rss/atom каналов -- date - интерфейс к функциям работы с датой и временем -- form - форма опроса -- во избежание пересечений с новыми стандартными именами рекомендуется -- свои имена начинать с большой буквы ,"extra" : < "Key1" : [ 12, 34 ,56 ] -- пример использования [% Key1[2] %] ,"City" : < -- пример использования [% City.rus.long %] "rus" : < "long" : "Санкт-Петербург" ,"short" : "СПБ" ,"eng" : < "long" : "Leningrad" ,"short" : "LED" >> > ,"track.info" : "дополнительная информация, которая будет потом доступна в track.list/get" -- строка 1024 байта. Параметр необязателен ,"reltype" : . ,"relref" : . >
< ,"track.id" : номер -- номер асинхронного запроса для отслеживания с помощью track.* -- -- также можно получать callback по достижению трекером конечного состояния - т.е. по завершения выпуска -- -- после выпуска Транзакционного письма полученный письмом номер "letter" будет в отчёте track.get -- для данного track.id. Используя letter в stat.uni, можно получить информацию по данному конкретному -- Транзакционному письму. >