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

#Чат со стратегом

Статус: Планируется. Публичного API чата нет: разговор со стратегом доступен в кабинете Sapport (раздел «Продвижение», вкладка «Стратег») и в служебном Telegram-боте. Страница описывает замысел из проекта; поля и коды предварительные и могут измениться при выпуске. Сроки не обещаются.

Чат со стратегом — разговор с ИИ-маркетологом. Вы задаёте вопрос («почему упал трафик из поиска», «какие темы у конкурентов мы не покрыли»), стратег смотрит ваши данные инструментами чтения и отвечает. Если он считает, что нужно действие, он предлагает его, но не выполняет: решение остаётся за человеком.

Доступ: strategist:chat — разговор; strategist:read — чтение сессий. Платно: да, каждый ход списывается с кошелька арендатора (Платные операции). ПДн: стратег работает с агрегатами и счётчиками (в том числе воронкой CRM в счётчиках); персональных данных учеников и лидов он не получает.

Интеграция видит только свои сессии. Сессии, начатые людьми в кабинете или в служебном Telegram-боте, и сессии других интеграций через API недоступны.

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

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

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

#Точки

Метод и путьОбластьЧто делает
POST /strategist/chat/sessionsstrategist:chatЗавести сессию разговора
GET /strategist/chat/sessionsstrategist:readСписок сессий
GET /strategist/chat/sessions/{id}strategist:readСессия с репликами
POST /strategist/chat/sessions/{id}/turnsstrategist:chatЗадать вопрос (ход разговора). Платно

#Как устроен ход

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

POST …/sessions/{id}/turns  (Idempotency-Key)   →  202 Accepted + operation
         │
         ├── ?wait=N (до 20 с): ждём то же задание
         ├── GET /operations/{id}
         └── события strategist.turn.completed, operation.completed → GET …/sessions/{id}

Ход может занять заметное время: стратег последовательно вызывает инструменты и только потом отвечает. Поэтому не держите соединение, а подпишитесь на событие или опрашивайте операцию.

#Инструменты стратега

Интеграции доступны инструменты чтения данных (трафик, поисковые запросы, статьи, конкуренты в обобщённом виде, воронка CRM в счётчиках) и инструмент propose_topic («предложить тему»). Инструменты рекламы (право ads.manage) и сырьё конкурентов (право competitors.raw) в v1 недоступны.

Ограничения хода:

ЧтоЗначение
Длина вопросадо 4000 символов
Вызовов инструментов за ходне более 6
Предельное время хода90 секунд
Предел стоимости одного ходаСохраняется. Сегодня равен 0,25 доллара США; ход, достигший предела, останавливается и отдаёт то, что успел
Памятьв следующий ход подмешиваются последние 20 реплик сессии
Ответне длиннее 4000 токенов

Если предел достигнут, стратег не обрывает разговор молча: он отдаёт то, что успел, а в ответе указана причина остановки (поле truncated, ниже).

Модель стратега выбирает платформа, в запросе её указать нельзя. Историю сессии платформа берёт из своей базы, а не из запроса: прислать «историю» вместе с вопросом нельзя. Это защищает от подмены («пользователь уже всё подтвердил»).

#POST /strategist/chat/sessions

Заводит пустую сессию, принадлежащую вашей интеграции. Тело запроса не нужно.

{
  "id": "c2e84a17-9d03-4f5b-a6c8-3b71e0d92f45",
  "title": null,
  "message_count": 0,
  "created_at": "2026-10-11T10:00:00Z"
}

Если заголовок не задан, он формируется из первых 80 символов первого вопроса.

curl -X POST https://formula-cream.pro/api/public/v1/strategist/chat/sessions \
  -H "Authorization: Bearer $SAPPORT_API_KEY" \
  -H "Idempotency-Key: 8b3d1f60-2e47-4a95-b7c1-6d0e9a5f3c28"
# SAPPORT_API_KEY=sap_ru_test_EXAMPLE0KEYID_… (пример, не настоящий ключ)

#POST /strategist/chat/sessions/{id}/turns

Задаёт вопрос в сессии. Платно.

ПараметрТипОбязательноОграниченияПример
id (путь)string (uuid)даСессия вашей интеграцииc2e84a17-…
messagestringда1–4000 символов, после обрезки пробелов не пустоПочему упал трафик из поиска?
wait (query)integerнет0–20 секунд20
Заголовок Idempotency-KeystringдаДо 255 символов0e8a2f61-…

Вопрос записывается в сессию сразу, до проверки кошелька и до работы модели. Если ход не удался (отказ кошелька, сбой модели), реплика остаётся в истории.

Ответ 202 Accepted — конверт operation вида strategist.turn. Если за wait секунд ход завершился, в конверте уже status: "succeeded" и usage; иначе — текущее состояние:

{
  "operation": {
    "id": "op_EXAMPLE01",
    "type": "strategist.turn",
    "status": "running",
    "created_at": "2026-10-11T10:00:05Z",
    "resource": { "type": "strategist_session", "id": "c2e84a17-9d03-4f5b-a6c8-3b71e0d92f45" }
  }
}

Стоимость хода — usage.cost в конверте завершённой операции, в валюте кошелька арендатора; usage.model — модель, выбранная платформой. Результат хода читается из сессии: GET /strategist/chat/sessions/{id}. Ответ стратега — последняя реплика роли assistant:

Поле репликиТипОписание
contentstringОтвет стратега
tool_calls[]arrayЧто стратег смотрел: name (инструмент), summary (краткое описание, например «посмотрел трафик за 14 дней»)
actions[]array of stringИдентификаторы действий, которые стратег подготовил в этом ходе
truncatedstring | nullПричина остановки до полного ответа: calls (исчерпан предел вызовов), time (вышло время), wallet (не хватило средств), cost (достигнут предел стоимости хода); null, если ответ полный
{
  "id": "5e9b2d73-1c48-4a06-b7f5-80d3a6c1e294",
  "role": "assistant",
  "content": "Трафик из поиска упал на 12% за неделю: основная потеря на двух страницах про гидролаты. За тот же период там не было обновлений.",
  "tool_calls": [
    { "name": "traffic_by_source", "summary": "посмотрел трафик по источникам за 14 дней" }
  ],
  "actions": [],
  "truncated": null,
  "created_at": "2026-10-11T10:00:19Z"
}

Ход, который не удался (отказ кошелька, сбой модели), завершается операцией failed с error; реплика пользователя при этом остаётся в истории.

curl -X POST "https://formula-cream.pro/api/public/v1/strategist/chat/sessions/$SESSION_ID/turns?wait=20" \
  -H "Authorization: Bearer $SAPPORT_API_KEY" \
  -H "Idempotency-Key: 0e8a2f61-7c4b-4d19-a3f5-9b1c6d2e8f47" \
  -H "Content-Type: application/json" \
  -d '{"message":"Почему упал трафик из поиска?"}'
const res = await fetch(
  `https://formula-cream.pro/api/public/v1/strategist/chat/sessions/${sessionId}/turns?wait=20`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SAPPORT_API_KEY}`,
      "Idempotency-Key": crypto.randomUUID(),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ message: "Почему упал трафик из поиска?" }),
  },
);
if (res.status === 202) {
  const { operation } = await res.json();
  // дождитесь события strategist.turn.completed (или operation.completed) либо опрашивайте GET /operations/{id}
}
r = httpx.post(
    f"https://formula-cream.pro/api/public/v1/strategist/chat/sessions/{session_id}/turns",
    params={"wait": 20},
    headers={
        "Authorization": f"Bearer {os.environ['SAPPORT_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"message": "Почему упал трафик из поиска?"},
    timeout=30,
)
if r.status_code == 202:
    operation = r.json()["operation"]
$ch = curl_init("https://formula-cream.pro/api/public/v1/strategist/chat/sessions/" . $sessionId . "/turns?wait=20");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("SAPPORT_API_KEY"),
        "Idempotency-Key: " . bin2hex(random_bytes(16)),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode(["message" => "Почему упал трафик из поиска?"]),
]);
$res = curl_exec($ch);

#GET /strategist/chat/sessions

Список сессий вашей интеграции, новые сверху. Курсорный список: параметры limit (1–100, по умолчанию 25) и cursor — по общим соглашениям.

ПолеТипОписание
idstring (uuid)Идентификатор
titlestring | nullЗаголовок
message_countintegerЧисло реплик в сессии
total_costobjectСуммарная стоимость сессии: {amount, currency}, amount — строка
created_at, updated_atstring (ISO 8601)Даты

#GET /strategist/chat/sessions/{id}

Сессия целиком: реплики по порядку, до 400 реплик.

Поле репликиТипОписание
idstring (uuid)Идентификатор
rolestringuser, assistant, tool
contentstring | nullТекст. У реплик tool всегда null
kindstring | nullaction — реплика-карточка предложения
action_idstring (uuid)Для карточек предложений: идентификатор действия; актуальное состояние читайте там
tool_calls[], actions[], truncatedУ реплик assistant: как в таблице выше
created_atstring (ISO 8601)Время

Ответы инструментов наружу не отдаются: это снимки вашей аналитики, и экрану нужно лишь имя вызова («посмотрел трафик за 14 дней»), которое есть в tool_calls.

Чужая или несуществующая сессия — 404 not_found.

curl "https://formula-cream.pro/api/public/v1/strategist/chat/sessions/$SESSION_ID" \
  -H "Authorization: Bearer $SAPPORT_API_KEY"

#Предложения, подготовленные в разговоре

Стратег не исполняет управляющие действия. Он создаёт ожидающее действие и показывает его человеку. Исполняется оно только отдельным запросом от человека; стратег подтвердить своё предложение не может никаким способом, ни прямо, ни «второй репликой от вашего имени».

В v1 через этот механизм проходит один вид предложений:

ДействиеЧто произойдёт после подтверждения
propose_topic — предложить темуТема попадёт в очередь тем в состоянии proposed; статья не пишется

Деньги и публикации действие не затрагивает: после подтверждения тему нужно утвердить отдельно, а генерацию статьи заказать явно.

Действия подтверждаются и отклоняются запросами POST /strategist/actions/{id}/confirm и POST /strategist/actions/{id}/cancel (область strategist:write). Состояния действия (proposed, confirmed, executed, failed, cancelled, expired), срок жизни 7 суток и правила повторных решений описаны в разделе Объект действия.

#События

СобытиеКогда
strategist.turn.completedХод разговора завершён (успешно или с ошибкой)
operation.completedЗавершилась операция strategist.turn; в data — конверт operation

Нагрузка strategist.turn.completed тонкая: session_id, идентификатор операции и итог (succeeded или failed). Текст ответа забирайте запросом GET /strategist/chat/sessions/{id}. Подпись, повторы, проверка — Вебхуки.

#Ошибки

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

КодHTTPКогда
invalid_api_key401Ключ не принят
scope_missing403Нет strategist:chat / strategist:read
not_found404Сессии нет или она чужая
validation_failed422Пустой вопрос или длиннее 4000 символов; wait вне 0–20; просроченный курсор
idempotency_conflict409Idempotency-Key уже использован с другим телом
invalid_state409В сессии уже идёт ход: дождитесь завершения операции
insufficient_funds402Не хватает средств на кошельке
spend_limit_reached402Сработал предел трат, параллелизма или стоимости операции
upstream_unavailable503Нет ключа модели или модель недоступна
service_unavailable503Недоступно хранилище пределов: платный ход не принят
rate_limited429Превышен предел частоты платных запросов

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