#Чат со стратегом
Статус: Планируется. Публичного API чата нет: разговор со стратегом доступен в кабинете Sapport (раздел «Продвижение», вкладка «Стратег») и в служебном Telegram-боте. Страница описывает замысел из проекта; поля и коды предварительные и могут измениться при выпуске. Сроки не обещаются.
Чат со стратегом — разговор с ИИ-маркетологом. Вы задаёте вопрос («почему упал трафик из поиска», «какие темы у конкурентов мы не покрыли»), стратег смотрит ваши данные инструментами чтения и отвечает. Если он считает, что нужно действие, он предлагает его, но не выполняет: решение остаётся за человеком.
Доступ: strategist:chat — разговор; strategist:read — чтение сессий. Платно: да, каждый ход списывается с кошелька арендатора (Платные операции). ПДн: стратег работает с агрегатами и счётчиками (в том числе воронкой CRM в счётчиках); персональных данных учеников и лидов он не получает.
Интеграция видит только свои сессии. Сессии, начатые людьми в кабинете или в служебном Telegram-боте, и сессии других интеграций через API недоступны.
#Базовый адрес
| Ячейка | Адрес |
|---|---|
| RU | https://formula-cream.pro/api/public/v1 |
| EN | https://wfacademy.org/api/public/v1 |
| ID | https://wfacademy.id/api/public/v1 |
Ошибки, идемпотентность, асинхронные операции — Соглашения. Ключи и области — Аутентификация. Во всех примерах ключ заведомо ненастоящий.
#Точки
| Метод и путь | Область | Что делает |
|---|---|---|
POST /strategist/chat/sessions | strategist:chat | Завести сессию разговора |
GET /strategist/chat/sessions | strategist:read | Список сессий |
GET /strategist/chat/sessions/{id} | strategist:read | Сессия с репликами |
POST /strategist/chat/sessions/{id}/turns | strategist: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-… |
message | string | да | 1–4000 символов, после обрезки пробелов не пусто | Почему упал трафик из поиска? |
wait (query) | integer | нет | 0–20 секунд | 20 |
Заголовок Idempotency-Key | string | да | До 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:
| Поле реплики | Тип | Описание |
|---|---|---|
content | string | Ответ стратега |
tool_calls[] | array | Что стратег смотрел: name (инструмент), summary (краткое описание, например «посмотрел трафик за 14 дней») |
actions[] | array of string | Идентификаторы действий, которые стратег подготовил в этом ходе |
truncated | string | 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 — по общим соглашениям.
| Поле | Тип | Описание |
|---|---|---|
id | string (uuid) | Идентификатор |
title | string | null | Заголовок |
message_count | integer | Число реплик в сессии |
total_cost | object | Суммарная стоимость сессии: {amount, currency}, amount — строка |
created_at, updated_at | string (ISO 8601) | Даты |
#GET /strategist/chat/sessions/{id}
Сессия целиком: реплики по порядку, до 400 реплик.
| Поле реплики | Тип | Описание |
|---|---|---|
id | string (uuid) | Идентификатор |
role | string | user, assistant, tool |
content | string | null | Текст. У реплик tool всегда null |
kind | string | null | action — реплика-карточка предложения |
action_id | string (uuid) | Для карточек предложений: идентификатор действия; актуальное состояние читайте там |
tool_calls[], actions[], truncated | У реплик assistant: как в таблице выше | |
created_at | string (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_key | 401 | Ключ не принят |
scope_missing | 403 | Нет strategist:chat / strategist:read |
not_found | 404 | Сессии нет или она чужая |
validation_failed | 422 | Пустой вопрос или длиннее 4000 символов; wait вне 0–20; просроченный курсор |
idempotency_conflict | 409 | Idempotency-Key уже использован с другим телом |
invalid_state | 409 | В сессии уже идёт ход: дождитесь завершения операции |
insufficient_funds | 402 | Не хватает средств на кошельке |
spend_limit_reached | 402 | Сработал предел трат, параллелизма или стоимости операции |
upstream_unavailable | 503 | Нет ключа модели или модель недоступна |
service_unavailable | 503 | Недоступно хранилище пределов: платный ход не принят |
rate_limited | 429 | Превышен предел частоты платных запросов |
#Открытые вопросы
- Параллельные ходы (техническое). В кабинете второй ход в той же сессии до завершения первого не предусмотрен; страница описывает его как
409 invalid_state. Точное поведение уточнится при выпуске. - Предел стоимости хода в валюте кошелька (техническое). В кабинете предел задан в долларах США (0,25) и
cost_usdхода возвращается числом. В API стоимость отдаётся строкой{amount, currency}в валюте кошелька; способ пересчёта предела в валюту ячейки не описан. - Значения
truncated(техническое). Значенияcalls,time,wallet,costвведены этой страницей по внутренним причинам остановки цикла; в проекте они не названы. - Форма реплики с результатом хода (техническое). Поля
actions[]иaction_idвместо кабинетныхpending/pending_stateпредложены этой страницей.