◆ Sapport для разработчиков Справочник API Каталог ошибок OpenAPI
Разделы

#Отчёты стратега

Статус: Доступно (чтение). Работают GET /strategist/reports и GET /strategist/reports/{id} (область strategist:read). Отчёты строятся на агрегатах; названия конкурентов скрыты, снимок аналитики, модель и стоимость прогона не отдаются.

Стратег — ИИ-маркетолог Sapport. Он собирает данные вашего сайта и рекламы (трафик, поисковые запросы, статьи, конкуренты, CRM-воронка в счётчиках) и раз в сутки и раз в неделю готовит отчёт: что произошло, что тревожит и что стоит сделать. API отчётов отдаёт этот отчёт вашей системе в виде структуры, а не готового текста для мессенджера.

Доступ: strategist:read. Платно: нет (чтение готового отчёта). ПДн: нет — отчёт строится на агрегатах и счётчиках, персональных данных учеников и лидов в нём нет.

Публичный API отдаёт отчёты стратега двух видов: суточные (daily) и недельные (weekly). Прогоны других модулей, которые лежат в той же таблице отчётов (например, креативы), через API не отдаются.

#Базовый адрес

ЯчейкаАдрес
RUhttps://formula-cream.pro/api/public/v1
ENhttps://wfacademy.org/api/public/v1
IDhttps://wfacademy.id/api/public/v1

Ошибки, пагинация, пределы — Соглашения. Ключи и области — Аутентификация. Во всех примерах ключ заведомо ненастоящий.

#Точки

Метод и путьОбластьЧто делает
GET /strategist/reportsstrategist:readСписок отчётов: шапки без тела
GET /strategist/reports/{id}strategist:readОдин отчёт целиком

Отчёт создаёт сам стратег по расписанию. Заказать отчёт запросом API нельзя. Список — курсорный (Пагинация).

#Структура отчёта

Отчёт отвечает на три вопроса: что главное, что тревожит и что делать.

БлокПолеЧто внутри
ГлавноеhighlightsКороткие факты периода
ТревогиconcernsПроблемы и риски: провалы показателей, разрывы в графике, пункты «Не делать»
РекомендацииactionsЧто сделать, с приоритетом, ожидаемым эффектом и доказательствами
ДоказательстваevidenceКейсы и данные, на которые опираются рекомендации

#Шапка отчёта (элемент списка)

ПолеТипОписание
idstring (uuid)Идентификатор отчёта
report_datestring (дата, YYYY-MM-DD)Дата отчёта
report_typestringВид отчёта: daily (суточный) или weekly (недельный)
summary_textstringКраткая сводка
actions_countintegerЧисло рекомендаций
data_as_ofobjectНа какой момент актуальны данные отчёта: {показатель: дата YYYY-MM-DD} (например, {"gsc": "2026-10-09", "tracker": "2026-10-11"}); ключ snapshot — дата снимка аналитики, на котором построен отчёт. Пустой объект, если снимка нет
delivered_atstring (ISO 8601) | nullКогда отчёт доставлен в Telegram-бот; null, если не доставлялся

Список возвращает только шапки: тело отчёта в нём не отдаётся ни при каком наборе прав.

#Отчёт целиком

ПолеТипОписание
idstring (uuid)Идентификатор отчёта
report_datestringДата отчёта
report_typestringВид отчёта: daily или weekly
summary_textstringКраткая сводка
data_as_ofobjectКак в шапке
highlightsarrayГлавное
concernsarrayТревоги
actionsarray of objectРекомендации (ниже)
evidenceobjectДоказательства (ниже)

Ссылки на внутренние объекты (статья, запрос, продукт) в текстах highlights, concerns и rationale заменяются читаемыми подписями.

#Рекомендация (actions[])

ПолеТипОписание
titlestringЧто сделать
prioritystringhigh, medium или low
rationalestringПочему это нужно
target_refstring | nullЧто затронет: ссылка на объект (статья, запрос, продукт)
expected_effectobject | nullОжидаемый эффект: metric (показатель), delta (изменение), horizon_days (срок в днях)
check_after_daysinteger | nullЧерез сколько дней проверить результат
basisstringНа чём стоит рекомендация (таблица ниже)

Поля target_ref, expected_effect, check_after_days и basis есть в структуре новых отчётов. В отчётах, созданных до их появления, этих полей нет или они пусты (см. «Открытые вопросы»).

#Основание рекомендации (basis)

ЗначениеСмысл
own_measuredИзмерено на ваших данных
observed_patternЗамечено у конкурентов
researchОпирается на внешнее исследование
hypothesisПредположение без подтверждения. Это значение по умолчанию

Рекомендация без единого кейса помечена как hypothesis: стратег называет догадку догадкой.

#Доказательства (evidence)

Для каждой рекомендации прикладывается до трёх доказательств.

ПолеТипОписание
evidence.actions[]arrayПо одному элементу на рекомендацию (в порядке actions)
evidence.actions[].indexintegerНомер рекомендации
evidence.actions[].statusstringsupported (подтверждена доказательствами) или unsupported
evidence.actions[].basisstringОснование (как в таблице выше)
evidence.actions[].items[]arrayДоказательства
evidence.actions[].items[].refstringСсылка на источник
evidence.actions[].items[].kindstringВид источника, например own (ваши данные), competitor (конкурент), pulse (пульс), signal (сигнал); набор может расширяться
evidence.actions[].items[].labelstringПодпись источника
evidence.actions[].items[].urlstringАдрес страницы (необязательно)
evidence.actions[].items[].quotestringЦитата (необязательно)

Подписи, адреса и цитаты подставляет сервер из данных, которые он сам выдал стратегу; модель присылает только ссылку. Поэтому в доказательствах нет выдуманных адресов.

Проверка доказательств честно ограничена. Сервер проверяет, что ссылка выдана им самим и что цитата взята из источника. Он не проверяет, что кейс действительно подтверждает вывод. Поле evidence.validation.relevance_checked всегда false.

#Срез без сырья конкурентов

В v1 сырьё конкурентов (право competitors.raw) интеграции недоступно, поэтому отчёт всегда урезан: не возвращаются raw_signals (снимок аналитики), модель, стоимость прогона, а в доказательствах скрыты домены конкурентов и модельные детали. Структура блоков при этом сохраняется. Креативные отчёты не отдаются вовсе.

#GET /strategist/reports

ПараметрТипОбязательноОграниченияПример
limitintegerнет1–100, по умолчанию 2510
cursorstringнетЗначение next_cursor; живёт 24 часа
report_typestringнетdaily или weeklydaily
{
  "data": [
    {
      "id": "3d8f1b52-6a47-4c9e-b0d3-9e51a2c7f804",
      "report_date": "2026-10-11",
      "report_type": "daily",
      "summary_text": "Трафик из поиска вырос, конверсия в заявку без изменений.",
      "actions_count": 3,
      "data_as_of": { "gsc": "2026-10-09", "tracker": "2026-10-11" },
      "delivered_at": "2026-10-11T06:10:04Z"
    }
  ],
  "next_cursor": null
}
curl "https://formula-cream.pro/api/public/v1/strategist/reports?limit=10" \
  -H "Authorization: Bearer $SAPPORT_API_KEY"
# SAPPORT_API_KEY=sap_ru_test_EXAMPLE0KEYID_… (пример, не настоящий ключ)
const res = await fetch(
  "https://formula-cream.pro/api/public/v1/strategist/reports?limit=10",
  { headers: { Authorization: `Bearer ${process.env.SAPPORT_API_KEY}` } },
);
const { data, next_cursor } = await res.json();
r = httpx.get(
    "https://formula-cream.pro/api/public/v1/strategist/reports",
    params={"limit": 10},
    headers={"Authorization": f"Bearer {os.environ['SAPPORT_API_KEY']}"},
)
page = r.json()
$ch = curl_init("https://formula-cream.pro/api/public/v1/strategist/reports?limit=10");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SAPPORT_API_KEY")],
]);
$page = json_decode(curl_exec($ch), true);

#GET /strategist/reports/{id}

ПараметрТипОбязательноОграниченияПример
idstring (uuid)даОтчёт вашего арендатора3d8f1b52-6a47-4c9e-b0d3-9e51a2c7f804

Чужой или несуществующий отчёт — 404 not_found.

{
  "id": "3d8f1b52-6a47-4c9e-b0d3-9e51a2c7f804",
  "report_date": "2026-10-11",
  "report_type": "daily",
  "summary_text": "Трафик из поиска вырос, конверсия в заявку без изменений.",
  "data_as_of": { "gsc": "2026-10-09", "tracker": "2026-10-11" },
  "highlights": [
    "Переходы из поиска выросли на странице про увлажняющие кремы"
  ],
  "concerns": [
    "Нет новых статей уже 12 дней"
  ],
  "actions": [
    {
      "title": "Выпустить статью про выбор увлажняющего крема",
      "priority": "high",
      "rationale": "Запрос растёт, статьи по теме на сайте нет.",
      "target_ref": "keyword:EXAMPLE",
      "expected_effect": { "metric": "переходы из поиска", "delta": "+10%", "horizon_days": 30 },
      "check_after_days": 21,
      "basis": "own_measured"
    }
  ],
  "evidence": {
    "actions": [
      {
        "index": 0,
        "status": "supported",
        "basis": "own_measured",
        "items": [
          { "ref": "own:EXAMPLE", "kind": "own", "label": "Поисковые запросы за 28 дней" }
        ]
      }
    ]
  }
}
curl "https://formula-cream.pro/api/public/v1/strategist/reports/$REPORT_ID" \
  -H "Authorization: Bearer $SAPPORT_API_KEY"
const res = await fetch(
  `https://formula-cream.pro/api/public/v1/strategist/reports/${reportId}`,
  { headers: { Authorization: `Bearer ${process.env.SAPPORT_API_KEY}` } },
);
const report = await res.json();
for (const action of report.actions) {
  console.log(action.priority, action.title);
}
r = httpx.get(
    f"https://formula-cream.pro/api/public/v1/strategist/reports/{report_id}",
    headers={"Authorization": f"Bearer {os.environ['SAPPORT_API_KEY']}"},
)
report = r.json()
for action in report["actions"]:
    print(action["priority"], action["title"])
$ch = curl_init("https://formula-cream.pro/api/public/v1/strategist/reports/" . $reportId);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("SAPPORT_API_KEY")],
]);
$report = json_decode(curl_exec($ch), true);

#Событие

СобытиеКогда
strategist.report.readyГотов новый отчёт

Нагрузка тонкая: тип события и report_id. Сам отчёт забирайте запросом GET /strategist/reports/{id}. Подпись, повторы и проверка событий — Вебхуки.

#Ошибки

Общий формат и каталог кодов — Соглашения. Для этих точек:

КодHTTPКогда
invalid_api_key401Ключ не принят
scope_missing403Нет области strategist:read
not_found404Отчёта нет или он чужой
validation_failed422Неверный report_type, limit вне 1–100 или просроченный курсор (errors[].field = /cursor)
rate_limited429Превышен предел частоты

#Открытые вопросы