Шаринг диалогов Shopping Assistant

Шаринг позволяет создать публичную read-only версию существующего диалога Shopping Assistant. Покупатель может отправить ссылку другому человеку, а клиентский интерфейс — показать сообщения и товарные подборки без доступа к исходному диалогу.

Публичная версия создается как неизменяемый снимок и действует 30 дней. Ее можно отозвать раньше.

Как работает сценарий

  1. Покупатель открывает действие «Поделиться» в существующем диалоге.
  2. Клиент вызывает POST /dialogs/share с идентификаторами пользователя и диалога.
  3. Shopping Assistant создает неизменяемый snapshot и возвращает share_token, shared_path и срок действия.
  4. Получатель открывает публичную страницу клиента.
  5. Страница вызывает GET /dialogs/shared/{share_token} и отображает безопасную версию диалога.
  6. При необходимости клиент отзывает ссылку через POST /dialogs/share/revoke.

Идентификаторы

В API шаринга используются snake_case поля. Передавайте в них те же значения, с которыми создавался исходный диалог:

API шаринга Shopping Assistant API Значение
user_id resourceId user.uid пользователя Gravity Field.
dialog_id threadId Стабильный ID исходного диалога.
through_message_id assistantMessageId или id из /shopping/history Последнее сообщение, которое нужно включить в публичную версию.

tenant_id не передается в API шаринга. Shopping Assistant проверяет пару user_id + dialog_id и определяет секцию по сохраненным metadata исходного диалога. Поля tenant_id, client_id и любые другие поля вне контракта приводят к ответу 400.

POST /dialogs/share

Создает новую публичную версию диалога.

POST https://shopping-assistant-api.gravityfield.ai/dialogs/share
Content-Type: application/json

Запрос

curl --request POST \
  --url 'https://shopping-assistant-api.gravityfield.ai/dialogs/share' \
  --header 'Content-Type: application/json' \
  --data '{
    "user_id": "665f0a000000000000000001",
    "dialog_id": "thread-8f2b1c",
    "through_message_id": "shopping:assistant:8a21..."
  }'
Поле Обязательное Назначение
user_id Да Значение resourceId, с которым был создан диалог.
dialog_id Да Значение threadId исходного диалога.
through_message_id Нет Последнее сообщение публичной версии. Сообщение включается в snapshot. Если поле не передано, используется последнее сообщение диалога.

Можно указать ID сообщения пользователя или ассистента. Сообщение должно принадлежать исходному диалогу.

Ответ

API возвращает 201 Created:

{
  "share_token": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
  "shared_path": "/dialogs/shared/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
  "through_message_id": "shopping:assistant:8a21...",
  "expires_at": "2026-09-25T12:00:00.000Z"
}
Поле Назначение
share_token Токен публичной версии. Считайте его секретом ссылки и не передавайте в аналитику или логи.
shared_path Относительный путь публичного JSON endpoint-а.
through_message_id Фактическое последнее сообщение, включенное в snapshot.
expires_at Дата окончания действия ссылки в ISO 8601.

Каждый успешный запрос создает отдельный snapshot. Новые сообщения исходного диалога не изменяют уже созданную публичную версию.

GET /dialogs/shared/{share_token}

Возвращает публичную версию диалога. Для запроса не нужны user_id, dialog_id или tenant_id: доступ определяется наличием действующего токена.

curl --request GET \
  --url 'https://shopping-assistant-api.gravityfield.ai/dialogs/shared/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'

Ответ

{
  "created_at": "2026-08-26T12:00:00.000Z",
  "expires_at": "2026-09-25T12:00:00.000Z",
  "messages": [
    {
      "role": "user",
      "created_at": "2026-08-26T11:59:50.000Z",
      "content": "Подбери беговые кроссовки для ежедневных тренировок"
    },
    {
      "role": "assistant",
      "created_at": "2026-08-26T12:00:00.000Z",
      "response": {
        "contents": [
          {
            "type": "message",
            "value": "Вот несколько подходящих вариантов."
          },
          {
            "type": "products",
            "title": "Для ежедневных пробежек",
            "categories": ["Спорт", "Беговые кроссовки"],
            "value": [
              {
                "sku": "SKU-123",
                "category_id": "42",
                "name": "Runner Pro",
                "price": 12990,
                "features": "Амортизация; нейтральная пронация",
                "brand": "Example",
                "url": "https://shop.example/products/SKU-123",
                "image_url": "https://cdn.example/SKU-123.jpg"
              }
            ]
          }
        ]
      }
    }
  ]
}

Контракт публичной версии

type SharedDialogResponse = {
  created_at: string;
  expires_at: string;
  messages: Array<
    | {
        role: "user";
        created_at: string;
        content: string;
      }
    | {
        role: "assistant";
        created_at: string;
        response: {
          contents: Array<
            | { type: "message"; value: string }
            | {
                type: "products";
                title?: string;
                categories?: string[];
                value: SharedProduct[];
              }
          >;
        };
      }
  >;
};

type SharedProduct = {
  sku?: string;
  category_id?: string;
  name: string;
  price?: number | null;
  features?: string;
  brand?: string;
  url?: string;
  image_url?: string;
};

В публичную версию не попадают:

  • идентификаторы пользователя, диалога и сообщений;
  • изображения, загруженные пользователем;
  • кнопки и быстрые ответы;
  • оценки ответов;
  • latency и tracking events;
  • внутренние и служебные поля товарных блоков.

Публичный токен нельзя использовать для продолжения или изменения исходного диалога.

POST /dialogs/share/revoke

Отзывает публичную ссылку.

curl --request POST \
  --url 'https://shopping-assistant-api.gravityfield.ai/dialogs/share/revoke' \
  --header 'Content-Type: application/json' \
  --data '{
    "user_id": "665f0a000000000000000001",
    "dialog_id": "thread-8f2b1c",
    "share_token": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  }'

API отзывает ссылку только при совпадении user_id, dialog_id и share_token. Ответ 204 No Content возвращается и после успешного отзыва, и если такая связка не существует. Повторный отзыв безопасен и также возвращает 204.

После отзыва GET /dialogs/shared/{share_token} возвращает 404.

Ошибки и ограничения

Endpoint HTTP-статус Причина Что делать клиенту
Create 400 Некорректный JSON, отсутствует обязательное поле или передано поле вне контракта. Проверить payload. Не передавать tenant_id и client_id.
Create 404 Диалог не найден, не принадлежит user_id, не содержит секцию в metadata или through_message_id не найден. Проверить идентификаторы и при необходимости восстановить историю.
Read 404 Токен некорректен, не существует, истек или был отозван. Показать единое состояние «Ссылка недоступна».
Любой 429 Превышен лимит запросов. Повторить запрос через число секунд из заголовка Retry-After.
Любой 500 Не удалось создать, получить или отозвать публичную версию. Показать ошибку и предложить повторить запрос.

Лимиты API:

  • создание и отзыв — до 20 запросов в минуту с одного IP;
  • создание — дополнительно до 5 ссылок в минуту для одного диалога;
  • получение — до 60 запросов в минуту с одного IP;
  • неуспешное получение — до 10 запросов в минуту с одного IP.

Все ответы используют Cache-Control: no-store. Не кешируйте snapshot в общем кеше и не передавайте share_token в аналитику, error tracking или прикладные логи.

Рекомендации для интерфейса

  • Показывайте действие «Поделиться» только после появления хотя бы одного сообщения в диалоге.
  • Если пользователь выбирает конкретный ответ, передавайте его ID как through_message_id.
  • Для публичной страницы предусмотрите состояния загрузки, недоступной ссылки и ошибки сети.
  • Ссылки товаров открывайте по значениям url из snapshot-а.
  • Не показывайте на публичной странице элементы продолжения диалога, оценки или внутренние действия исходного чата.
  • Можно предложить получателю начать новый диалог, но для него нужно создать новые threadId и resourceId; продолжать исходный диалог по публичному токену нельзя.
  • После отзыва ссылки обновляйте состояние интерфейса, не проверяя существование токена по ответу revoke endpoint-а.

Связанные материалы

Shopping Assistant API
/shopping_assistant/api_reference/

Интеграция по API
/shopping_assistant/integration/