Adset.ProAdset.ProKnowledge base
Home/Публичное HTTP API/Статистика: отчёты и экспорт

Статистика: отчёты и экспорт

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 описаны в головной статье раздела.

Связанные статьи