# Статистика и отчёты
Public API даёт доступ к той же системе аналитики, что и админка Sales Ninja: агрегированные отчёты по проекту в целом, по конкретной персонализации/A/B-тесту/rule-based действию/моделируемой конверсии/сегменту/антиботу.
Два эндпоинта:
| HTTP | Что делает |
|---|---|
GET /public/api/v1/analytics/constructor?rootEntityType=…&rootEntityId=… | Каталог допустимых полей фильтра, группировок, метрик, дефолтов и лимитов. |
POST /public/api/v1/analytics/aggregated | Построить отчёт. |
# Когда какой rootEntityType
rootEntityType | Что считаем |
|---|---|
project | По проекту в целом. rootEntityId игнорируется (он выводится из токена). |
personalization | По конкретной персонализации. Пресет учитывает её цели и атрибуцию. |
abTest | По конкретному A/B-тесту. |
ruleBasedAction | По конкретному rule-based действию. |
modeledConversion | По моделируемой конверсии. Пресет ставится автоматически (стандартный или сегментный). |
audienceSegment | По сегменту (атрибуция фиксирована на UserSegments). |
antiBot | По антибот-модели (профиль AntiBotPerformance). |
Опросы и Яндекс.Директ в текущей версии Statistics V2 не поддерживаются — конструктор отдаст 404 с
понятным hint.
# Конструктор аналитики
GET https://api.sales-ninja.me/public/api/v1/analytics/constructor?rootEntityType=personalization&rootEntityId=8f3a…
Headers:
X-SN-TOKEN: <ваш токен>
Что возвращает (укрупнённо):
filterFields[]— поля фильтра:code,name,valueType,allowedOperators[],enumValues[].groupByFields[]— поля, по которым можно группировать.metrics[]— доступные метрики, сcode/name/unit.defaults— рекомендуемыеgroupBy,metrics,attributionType,distribution,granularity,samplingMode.limits— снимок ограничений для текущего трафик-тира проекта:
| Поле | Что значит |
|---|---|
maxGroupBy | Максимальная длина groupBy[]. |
maxPeriodDays | Максимум toUtc - fromUtc в днях. |
maxFilterNodeCount | Суммарное число узлов фильтра (групп + контейнеров). |
maxFilterDepth | Максимальная глубина вложенности фильтра. |
maxFilterPredicateCount | Суммарное число листовых предикатов. |
cooldownSeconds | Кулдаун между «тяжёлыми» вызовами того же проекта. |
isExpensive | Признак того, что текущий план считается «тяжёлым». |
Лимиты — снимок на момент запроса; те же лимиты применяются сервером при сборе самого отчёта. Если запрос их
нарушает — отчёт возвращается со status: "error" и reasonCode.
costMode(balanced,cheap) — параметр на конструкторе принимается для совместимости с MCP-вариантом API, но на Public API всегда трактуется какbalanced. Cheap-режим зарезервирован для AI-агентов.
# Отчёт
POST https://api.sales-ninja.me/public/api/v1/analytics/aggregated
Headers:
X-SN-TOKEN: <ваш токен>
Content-Type: application/json
# Минимальный пример — по проекту в целом
{
"rootEntityType": "project",
"fromUtc": "2026-04-01T00:00:00Z",
"toUtc": "2026-04-30T23:59:59Z",
"periodGranularity": "week",
"attributionType": "allConversions",
"groupBy": ["trafficSourceType", "device"],
"metrics": ["sessions", "conversions", "revenue"],
"filters": {
"operator": "and",
"predicates": [
{ "field": "trafficIsBrand", "operator": "equal", "value": "false" }
],
"nodes": []
},
"samplingMode": "auto"
}
# Параметры запроса
| Поле | Описание |
|---|---|
rootEntityType | См. таблицу выше. |
rootEntityId | UUID конкретной сущности (если rootEntityType ≠ project). |
fromUtc / toUtc | Границы периода (UTC). |
periodGranularity | Гранулярность периодов: day, week, month, quarter, year, none (агрегация без разбивки). |
attributionType | Тип атрибуции: allConversions, firstSession, userSegments, … (зависит от пресета). |
groupBy[] | Список кодов полей для группировки. Подмножество groupByFields[] конструктора. |
metrics[] | Список кодов метрик. Подмножество metrics[] конструктора. |
filters | N-арный фильтр (см. ниже). |
samplingMode | На Public API только auto. |
costMode | Принимается, но игнорируется (всегда balanced на Public API). |
# Структура фильтра
Фильтр — N-арное дерево (в отличие от условий показа, которые бинарные):
{
"operator": "and",
"predicates": [
{ "field": "trafficSourceType", "operator": "equal", "value": "ad" },
{ "field": "device", "operator": "in", "value": "Mobile,Tablet" }
],
"nodes": [
{
"operator": "or",
"predicates": [
{ "field": "utmCampaign", "operator": "equal", "value": "spring_sale" },
{ "field": "utmCampaign", "operator": "equal", "value": "summer_sale" }
],
"nodes": []
}
]
}
Операторы группы: and, or, not. Допустимые operator каждого predicate берутся из allowedOperators
поля в конструкторе.
# Ответ
{
"status": "calculated",
"trafficTier": "medium",
"isExpensive": true,
"averageSessionsPerDay": 12345,
"requestedRootEntityType": "project",
"effectiveRootEntityType": "project",
"guardrails": {
"trafficTier": "medium",
"maxGroupByCount": 3,
"maxPeriodDays": 45,
"...": "..."
},
"report": {
"reportId": "…",
"result": {
"periods": [
{ "fromUtc": "2026-04-01T00:00:00Z", "toUtc": "2026-04-07T23:59:59Z", "label": "Apr 1–7" }
],
"rows": [
{
"groupKeys": [
{ "fieldCode": "trafficSourceType", "value": "ad", "displayValue": "Ad" },
{ "fieldCode": "device", "value": "mobile", "displayValue": "Mobile" }
],
"periods": [
{ "metricValues": [
{ "metricCode": "sessions", "value": 1234 },
{ "metricCode": "conversions", "value": 42 },
{ "metricCode": "revenue", "value": 555 }
] }
],
"total": { "metricValues": [ "..." ] }
}
],
"grandTotal": { "metricValues": [ "..." ] },
"dictionaries": { "...": "..." }
}
}
}
# Правила соответствия
rows[*].groupKeys[i].fieldCode == request.groupBy[i]— порядок ключей совпадает с порядком в запросе.rows[*].periods[i].metricValues[k].metricCode == request.metrics[k]— порядок и количество метрик совпадают с запросом.rows[*].periods— длина = длинаresult.periods[].
# Статусы
status | Что значит | Что делать |
|---|---|---|
calculated | Отчёт готов. | Использовать report. |
queued | Отчёт в очереди. | Повторить тот же POST через retryAfterSeconds, или забрать по reportId. |
error | Не удалось построить. | Смотреть error, reasonCode, hint. Типичные причины: запрос нарушает limits, неподдерживаемый rootEntityType, плохие параметры. |
# Алгоритм
GET /analytics/constructor?rootEntityType=<x>&rootEntityId=<id>— узнать, что вообще можно запросить и какие лимиты.- Взять
defaultsкак стартовую точку, при необходимости — заменитьgroupBy[]/metrics[]/attributionTypeсвоими значениями (из соответствующих каталогов конструктора). - Собрать
filtersизfilterFields[]. Каждый предикат —{field, operator, value}; группировать через{operator, predicates[], nodes[]}. - Соблюсти лимиты из
limits(длинаgroupBy, период, глубина и размер фильтра). POST /analytics/aggregated. Наstatus: "queued"— повторить запрос или забрать отчёт поreportId.
# cURL
# 1. Каталог
curl "https://api.sales-ninja.me/public/api/v1/analytics/constructor?rootEntityType=project" \
-H "X-SN-TOKEN: $SN_TOKEN"
# 2. Отчёт
curl -X POST "https://api.sales-ninja.me/public/api/v1/analytics/aggregated" \
-H "X-SN-TOKEN: $SN_TOKEN" \
-H "Content-Type: application/json" \
-d @report.json