Статистика: отчёты и экспорт
Statistics API отдаёт агрегированные отчёты трекера — метрики × группировки × фильтры за период. Это те же данные, что показывает Конструктор отчётов в кабинете. Подходит для BI-систем, регулярных выгрузок и внешних дашбордов.
Ключи метрик, группировок и фильтруемых полей собраны в статье Статистика: справочник полей. Получение токена, общий формат ответов и ошибок — в головной статье раздела.
Скоупы
| Скоуп | Доступ | В дефолте PAT |
|---|---|---|
api:stats |
POST /api/stats/query — отчёты |
да |
api:stats:export |
POST /api/stats/export/csv — выгрузка CSV |
да |
api:stats:meta |
GET /api/stats/meta/* — справочники |
да |
Все операции требуют права запроса статистики — оно есть у всех ролей. BUYER видит только свою статистику, TEAM_LEAD — статистику команды с учётом настроек доступа к ресурсам, TEAM_OWNER и TECH — команду, ADMIN — всё.
Эндпойнты
Базовый префикс — /api/stats. Тело запросов — JSON, ответы — application/json (для экспорта — text/csv).
| Метод | Путь | Скоуп | Назначение |
|---|---|---|---|
POST |
/api/stats/query |
api:stats |
Отчёт: метрики × группировки + фильтры, с пагинацией |
POST |
/api/stats/export/csv |
api:stats:export |
Та же выборка в CSV (без пагинации, до 100 000 строк) |
GET |
/api/stats/meta/metrics |
api:stats:meta |
Каталог метрик |
GET |
/api/stats/meta/groups |
api:stats:meta |
Каталог группировок |
GET |
/api/stats/meta/filters |
api:stats:meta |
Список фильтруемых полей |
GET |
/api/stats/meta/distinct?field=&q=&limit= |
api:stats:meta |
Подсказки значений поля (autocomplete) |
GET |
/api/stats/meta/os-versions?q=&limit= |
api:stats:meta |
Подсказки версий ОС |
Для
/api/stats/**действует отдельный лимит частоты — 3 запроса в секунду с одного IP (burst 10). Сверх лимита шлюз отвечает429.
POST /api/stats/query
Тело запроса (StatsQueryDto):
{
"time": {
"preset": "last7", // ИЛИ from/to
"from": "2026-05-01 00:00:00",
"to": "2026-05-20 23:59:59",
"timezone": "UTC"
},
"groups": ["day", "cmp_campaign"],
"metrics": ["clicks", "cpa_accept", "revenue", "roi"],
"filters": [
{ "field": "user_country", "op": "in", "value": ["US", "CA"] },
{ "field": "cmp_offer", "op": "eq", "value": "65f0…" }
],
"pagination": { "page": 1, "limit": 100 },
"sort": { "field": "clicks", "order": "desc" },
"attributionWindow": { "hours": 24, "eventType": "click" }
}
Поля запроса
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
time |
TimeRangeDto |
да | Временной интервал отчёта |
groups |
string[] |
нет | Ключи группировок (см. справочник). Пустой массив — агрегат «всего» |
metrics |
string[] |
нет | Ключи метрик (см. справочник). По умолчанию ["clicks"] |
filters |
FieldFilterDto[] |
нет | Фильтры по полям (см. ниже) |
pagination |
{ page, limit } |
нет | page ≥ 1, 1 ≤ limit ≤ 100000 (по умолчанию 100) |
sort |
{ field, order } |
нет | order ∈ {asc, desc}; field — ключ метрики или группировки из запроса |
attributionWindow |
{ hours, eventType } |
нет | Окно атрибуции для Push-метрик: 1 ≤ hours ≤ 720, eventType ∈ {click, view} |
time (TimeRangeDto)
| Поле | Описание |
|---|---|
preset |
один из пресетов ниже; имеет приоритет над from/to |
from |
'YYYY-MM-DD' или 'YYYY-MM-DD HH:mm:ss' (разделитель — пробел или T). Без миллисекунд и без суффикса таймзоны (Z, +03:00) — такой формат вернёт ошибку валидации |
to |
то же; необязателен, если задан from |
timezone |
IANA-таймзона (Europe/Moscow), по умолчанию UTC. Границы интервала и группировки по времени считаются в ней |
Нужно передать либо preset, либо from (опционально с to).
| Пресет | Период |
|---|---|
today |
сегодня с 00:00 до текущего момента |
yesterday |
полные предыдущие сутки |
last7 |
последние 7 дней, включая сегодня |
last30 |
последние 30 дней |
thisWeek |
с понедельника текущей недели |
prevWeek |
предыдущая полная неделя (Пн–Вс) |
thisMonth |
с 1-го числа текущего месяца |
prevMonth |
предыдущий полный месяц |
filters[] (FieldFilterDto)
Каждый фильтр — { "field", "op", "value" }. Поле должно входить в список GET /api/stats/meta/filters.
Оператор op |
Семантика | Тип value |
|---|---|---|
eq |
равно | строка/число |
neq |
не равно | строка/число |
in |
значение из списка | массив |
not_in |
значения нет в списке | массив |
gt / gte |
больше / больше или равно | число |
lt / lte |
меньше / меньше или равно | число |
between |
в диапазоне | [min, max] — массив из 2 элементов |
like |
подстрока без учёта регистра (ClickHouse ILIKE) |
строка с % |
Серверные фильтры. Поля cmp_team и cmp_user всегда переопределяются сервером согласно роли владельца токена: заданное клиентом значение cmp_team игнорируется, а cmp_user пересекается с разрешённым набором пользователей. Ограничить отчёт чужими данными через API нельзя.
Правила
groupsиmetricsпринимают только ключи из справочников; неизвестный ключ — ошибка422.- Если у группировки есть «name»-вариант (
cmp_campaign↔cmp_campaign_name), он добавляется в строки автоматически — передавать его отдельно не нужно. attributionWindowвлияет только на метрики Push Attribution (push_postclick_*); без него эти метрики вернут нули.- Метрики LTV/Cohort (
ltv_*,ftds,registrations…) используются вместе с группировкамиcohort_*,reg_cohort_*,lifetime_days*. - Для
queryрекомендуетсяlimit ≤ 10 000; для полной выгрузки используйте CSV.
Пример ответа
{
"data": {
"rows": [
{
"day": "2026-05-13T00:00:00+00:00",
"cmp_campaign": "65f0…",
"cmp_campaign_name": "Brand A — RU",
"clicks": 18432,
"cpa_accept": 122,
"revenue": 2840.55,
"roi": 0.36
}
],
"total": { "clicks": 18432, "cpa_accept": 122, "revenue": 2840.55 },
"page": 1,
"limit": 100,
"rowCount": 1
},
"traceId": "01HX…"
}
rows — строки отчёта (ключи группировок + метрики), total — итог по всей выборке без учёта пагинации, rowCount — число строк на текущей странице. Доли (roi, click_to_dep и т.п.) приходят как числа в диапазоне 0..1, деньги — в USD.
POST /api/stats/export/csv
То же тело StatsQueryDto. Ответ — text/csv; charset=utf-8, имя файла stats-report-YYYY-MM-DD.csv. Пагинация игнорируется, выгрузка ограничена 100 000 строк.
curl -X POST 'https://adset.pro/api/stats/export/csv' \
-H 'Authorization: Bearer pat_…' \
-H 'Content-Type: application/json' \
--data-binary @query.json -o report.csv
Справочники GET /api/stats/meta/*
Справочники — живой источник ключей: если в платформе появилась новая метрика, она сразу есть в meta/metrics. Ответы имеют вид { "data": [ … ], "traceId" }; кэшируйте их на стороне интеграции.
meta/metrics
{
"key": "roi",
"type": "calculated",
"title": "ROI",
"group": "Finance",
"format": "percent",
"dependencies": ["revenue", "cost"],
"table": "events"
}
type — direct (прямой агрегат) или calculated (вычисляется из dependencies); format — подсказка для форматирования: ceil (целое), finance (деньги), percent (доля 0..1), number; table — таблица ClickHouse, в которой метрика существует.
meta/groups
{ "key": "cmp_campaign", "title": "Campaign", "group": "Campaign", "tables": ["events", "events_push", "events_push_attributed"] }
tables — в каких таблицах группировка валидна; группировки и метрики в одном запросе должны пересекаться хотя бы по одной таблице.
meta/filters
{ "field": "user_country", "type": "list", "group": "Traffic", "name": "Country" }
meta/distinct
Подсказки значений поля: GET /api/stats/meta/distinct?field=user_country&q=us&limit=20. Поле должно входить в meta/filters.
{
"data": [
{ "label": "US", "value": "US" },
{ "label": "Australia", "value": "AU" }
],
"traceId": "01HX…"
}
Для сущностей (cmp_campaign, cmp_offer, cmp_cpa…) value — это ObjectId, label — имя. Этот же эндпойнт удобно использовать, чтобы найти id для фильтра по названию.
meta/os-versions
То же, что distinct?field=user_os_ver, но с дополнительной нормализацией версий ОС.
Примеры
Отчёт по дням и кампаниям за прошлую неделю
curl -X POST 'https://adset.pro/api/stats/query' \
-H 'Authorization: Bearer pat_…' \
-H 'Content-Type: application/json' \
-d '{
"time": { "preset": "prevWeek", "timezone": "Europe/Moscow" },
"groups": ["day", "cmp_campaign"],
"metrics": ["clicks", "cpa_accept", "revenue", "roi"],
"filters": [
{ "field": "user_country", "op": "in", "value": ["US","CA","GB"] }
],
"pagination": { "page": 1, "limit": 50 },
"sort": { "field": "revenue", "order": "desc" }
}'
Подсказки по странам
curl -G 'https://adset.pro/api/stats/meta/distinct' \
-H 'Authorization: Bearer pat_…' \
--data-urlencode 'field=user_country' \
--data-urlencode 'q=u' \
--data-urlencode 'limit=10'
LTV-когорта по неделям
curl -X POST 'https://adset.pro/api/stats/query' \
-H 'Authorization: Bearer pat_…' \
-H 'Content-Type: application/json' \
-d '{
"time": { "preset": "last30" },
"groups": ["cohort_week", "lifetime_days"],
"metrics": ["ftds", "ltv_d0", "ltv_d1_7", "ltv_d8_30", "ltv_total", "ltv_per_ftd"],
"pagination": { "page": 1, "limit": 1000 }
}'
Push Attribution с окном 48 часов
curl -X POST 'https://adset.pro/api/stats/query' \
-H 'Authorization: Bearer pat_…' \
-H 'Content-Type: application/json' \
-d '{
"time": { "preset": "last7" },
"groups": ["day", "event_push_id"],
"metrics": ["push_views", "push_clicks", "push_postclick_accepts", "push_click_to_accept_rate"],
"attributionWindow": { "hours": 48, "eventType": "click" }
}'
Экспорт CSV
curl -X POST 'https://adset.pro/api/stats/export/csv' \
-H 'Authorization: Bearer pat_…' \
-H 'Content-Type: application/json' \
--data-binary @query.json -o report.csv
Ошибки
| HTTP | Когда |
|---|---|
400 time is required |
не передан time |
400 time.preset or time.from/time.to required |
в time нет ни preset, ни from |
422 validationError |
неверный формат даты, неизвестный op, метрика или группировка; подробности — в details[] |
403 forbidden + Insufficient OAuth scope. Required: api:stats… |
у токена нет нужного скоупа (например, PAT без api:stats:export вызывает CSV) |
429 |
превышен лимит 3 запроса/с на /api/stats/** |
Общий формат ошибок и коды 401/403 описаны в головной статье раздела.
Связанные статьи
- Статистика: справочник полей — все ключи фильтров, группировок и метрик
- Справочник метрик — что означает каждая метрика и как её читать
- MCP-сервис Adset — те же отчёты через LLM-клиенты
