Получение статистики через Sendsay API
Универсальная статистика stat.uni — основной инструмент для получения статистических данных из CDP Sendsay через API: переходы, открытия, тиражи выпусков, результаты доставки, стоп-листы, формы и другое.
Вызов stat.uni предназначен для выборок статистики по многим объектам, а не для отслеживания отдельных писем в реальном времени.
Структура запроса
{
"apikey": "ваш-api-ключ",
"action": "stat.uni",
"select": ["поле1", "поле2", "функция(поле3)"],
"filter": [{ "a": "поле", "op": "оператор", "v": "значение" }],
"order": ["поле1", "-поле2"],
"skip": 0,
"first": 100
}
Основные параметры
| Параметр | Описание |
|---|---|
select | Обязательно. Список полей и/или функций агрегирования |
filter | Условия фильтрации. Все элементы объединяются через AND |
have | Дополнительный фильтр после агрегирования (синтаксис как у filter) |
order | Сортировка. Префикс - — по убыванию, + или без префикса — по возрастанию |
skip | Пропустить N строк от начала (по умолчанию 0) |
first | Количество строк после пропуска (по умолчанию все) |
caption | Массив заголовков столбцов (для CSV/XLSX) |
result | Способ возврата результата |
Поля и функции в select
Простые поля
"select": ["issue.id", "issue.subject", "issue.dt", "issue.members"]
Поля дат с точностью
Поля с датами поддерживают указание точности в формате dt:HL, где H — старший компонент, L — младший (из набора Y, M, D, h, m, s):
"select": ["issue.dt:YM", "issue.dt:YD"]
Примеры:
dt:YM— год и месяц,dt:Yh— от года до часа,dt:YY— только год.
Специальные производные от даты:
dt:DOW(день недели, 1–7),dt:DOY(день года),dt:WOY(неделя года, форматYYYY-Ww),dt:CW1D(первый день недели).
Функции агрегирования
"select": ["deliv.issue.id", "count(*)", "max(deliv.letter.dt)"]
Доступные функции:
count(*),count(unique поле),max(),min(),avg(),sum(),range(),stdev(),variance().
Перед именем поля в функциях можно использовать префикс unique.
Поле не может одновременно быть в списке выборки и использоваться в функциях агрегирования. Функция sum() для полей, хранящих уникальные счётчики (например, issue.u_readed), вернёт "NaN".
Карта преобразования значений
Поле можно задать как объект с map для преобразования значений:
"select": [
{
"field": "deliv.result",
"map": { "1": "Доставлено", "0": "В процессе", "-1": "Ошибка" },
"map.missing": "Неизвестно"
}
]
Константы
"select": ["const(123)", "const(\"текст\")", "const.ID", "const.current"]
const.current — текущее время, поддерживает указание точности и сдвига, например, const.current:YM - 1 day.
Фильтры — filter
Все элементы filter объединяются через оператор AND.
Операторы сравнения
| Оператор | Описание |
|---|---|
== | Равно |
!= | Не равно |
>, >=, <, <= | Сравнение |
in | Входит в список значений ("v": [...]) |
!in | Не входит в список |
is_null | Значение не определено (только для полей, помеченных null) |
!is_null | Значение определено |
Простой фильтр
"filter": [
{ "a": "issue.id", "op": "==", "v": 12345 },
{ "a": "issue.dt:YD", "op": ">=", "v": "2026-01-01" }
]
Логические группировки
"filter": [
{
"op": "OR",
"v": [
{ "a": "issue.id", "op": "==", "v": 111 },
{ "a": "issue.id", "op": "==", "v": 222 }
]
}
]
Доступне логические операторы:
OR,!OR,AND,!AND.
Фильтрация по идентификаторам адресов
При фильтрации по полям, хранящим идентификатор адреса (email.email, member.email и др.), значения v приводятся к стандартному значению автоматически. Указывайте addr_type в условии, если вы работаете не только с email и msisdn — это поможет исключить ложные совпадения между разными типами идентификаторов.
Сравнение с текущим временем — current
Значения полей с датами можно сравнивать с текущим временем:
"filter": [
{ "a": "issue.dt", "op": ">=", "v": "current - 7 days" },
{ "a": "read.dt", "op": ">=", "v": "current - 2 hours round" }
]
Формат:
current +/-N year +/-N month +/-N day +/-N hour round +/-N minute round +/-N second
Порядок — от года к секунде. Слово round при часах/минутах обнуляет младшие компоненты.
Примеры:
current - 1 month— начало прошлого месяца.current - 1 day— вчера (начало дня).current - 2 hours round— начало часа 2 часа назад.current - 0 month + 4 days— 5-е число текущего месяца.
Результат current неявно приводится к точности поля в ключе a.
Дополнительный фильтр — have
Дополнительный фильтр have фильтрует результат после агрегирования. Синтаксис как у filter, но можно использовать только поля из select и функции агрегирования.
Пример для фильтрации выпусков после 1 января с более чем 10 кликами:
{
"select": ["click.issue.id", "count(*)"],
"filter": [{ "a": "click.issue.dt:YD", "op": ">", "v": "2026-01-01" }],
"have": [{ "a": "count(*)", "op": ">", "v": 10 }]
}
Сортировка — order
"order": ["-issue.dt", "+count(*)"]
Префикс - — по убыванию, + или без префикса — по возрастанию.
Объединение запросов — join
В одном запросе stat.uni нельзя обращаться к разным областям данных (например, одновременно к доставкам и открытиям). Чтобы получить в одной таблице данные из нескольких областей, используйте конструкцию join.
Параметр join — это массив запросов, каждый к своей области. Параметр joinby задаёт размер уникального ключа — количество первых колонок, по которым результаты объединяются в строки. 0 — без ключа, объединяются все колонки.
Например, нужно выгрузить все события (доставка, открытия, клики, отписки) получателей конкретного выпуска:
{
"action": "stat.uni",
"result": "save",
"joinby": 2,
"join": [
{
"select": ["deliv.member.id", "deliv.issue.id", "deliv.member.email", "deliv.status"],
"filter": [{ "a": "deliv.issue.id", "op": "==", "v": "777" }]
},
{
"select": ["read.member.id", "read.issue.id", "count(*)"],
"filter": [{ "a": "read.issue.id", "op": "==", "v": "777" }]
},
{
"select": ["click.member.id", "click.issue.id", "count(*)"],
"filter": [{ "a": "click.issue.id", "op": "==", "v": "777" }]
},
{
"select": ["unsub.member.id", "unsub.issue.id", "min(unsub.dt)"],
"filter": [{ "a": "unsub.issue.id", "op": "==", "v": "777" }]
}
]
}
В результате получится таблица: member.id, issue.id, member.email, статус доставки, количество открытий, количество кликов, дата первой отписки.
Уникальный ключ здесь — первые 2 колонки (member.id + issue.id). Email берётся только из первого запроса (к доставкам), чтобы не запрашивать его в каждом подзапросе — это уменьшает объём данных и ускоряет выполнение.
В запросах для открытий, кликов и отписок результат намеренно агрегирован (count(*), min()). Без агрегации, если для одн ого ключа встречается несколько строк, используется только первая, а остальные отбрасываются.
Сортировка в join задаётся по номерам колонок: "-1n" — первая колонка, числовая, по убыванию; "+2s" — вторая, строковая, по возрастанию.
Ответ и способы получения результата
Синхронный (по умолчанию)
Если параметр result не указан, результат возвращается сразу в ответе:
{
"list": [
["12345", "Привет, весна!", "2026-01-15 10:00:00"],
["12346", "Специальное предложение", "2026-01-20 12:00:00"]
]
}
Данные возвращаются в массиве list, каждая строка — массив значений в порядке, заданном в select.
Синхронный режим предназначен для интерактивной работы. При автоматизации запросы могут быть прекращены системой (например, по длительности выполнения).
Для автоматизации используйте асинхронные способы.
Асинхронный
При указании любого result, кроме response, вызов возвращает track.id для отслеживания через track.get:
{
"track.id": 12345
}
Способы получения результата — result
Параметр result — массив из одного или нескольких способов. Можно комбинировать, чтобы, например, сохранить данные в отчёты и отправить уведомление на почту.
| Способ | Описание |
|---|---|
response | Вернуть в ответе (синхронно, по умолчанию) |
save | Сохранить в хранилище отчётов (хранится 90 дней) |
email_file | Отправить файл на email |
url_file | Загрузить на внешний ресурс по HTTP(S) или FTP(S) |
email_notify | Отправить уведомление на email (без самого результата) |
sms | Отправить SMS-уведомление (без самого результата) |
url_notify | Вызвать URL по GET (без самого результата) |
none | Не возвращать результат (для пересчёта кэша) |
Пример: сохранить отчёт в XLSX и отправить уведомление на почту:
"result": [
{ "type": "save", "filename": "report-{DT:Y-M}", "format": "xlsx" },
{ "type": "email_notify", "to": ["manager@example.com"] }
]
Для форматов csv, xlsx, html, json доступны дополнительные настр ойки:
compress(сжатие:zip,gzip,bzip2),separator(разделитель для CSV),utf8(кодировка для CSV).
Доступные области данных (поля)
Каждая область данных (issue.*, deliv.*, click.*, read.* и т. д.) содержит свои поля и может включать поля из связанных областей. Например, в области deliv доступны все поля выпуска через deliv.issue.*, все поля контакта через deliv.member.* и т. д. В одном запросе используйте поля из одной области, обращаясь к связанным данным через вложенные поля.
Запись xxx.yyy.* означает, что доступны все поля объекта yyy. Если поле само является набором полей другого объекта, то доступны и они. Например, click.issue.group.name — название группы из выпуска, в котором был клик.