<!-- Canonical: https://docs.shopstory.live/docs/guide/quickstart -->

# Public API Quickstart

Public API подходит для собственного интерфейса поверх данных ShopStory, доступных только для чтения. Для готовых web-компонентов используйте [Web SDK](<https://docs.shopstory.live/docs/guide/web-sdk>), для видео в нативном приложении — [Mobile SDK](<https://docs.shopstory.live/docs/guide/mobile-sdk>).

## Проверить пример локально

[Скачайте API starter](<https://docs.shopstory.live/downloads/shopstory-api-starter.zip>). Нужен Node.js 22+. В архиве есть скрипт запроса и непустой синтетический fixture со связанными ID эфира и товара.

```bash
node request-streams.mjs --fixture streams.fixture.json
```

Ожидаемый результат: запись `stream-vod-1`, статус `finished`, строковый товарный ID `0001001`. Это проверка API-клиента без сетевого запроса; fixture не запускает SDK и не подтверждает воспроизведение. Для реальных данных задайте `SHOPSTORY_APPLICATION_ID` и выполните `node request-streams.mjs`.

Следующий шаг — [схема ответа API, карточки каталога и плеера](<https://docs.shopstory.live/docs/guide/catalog-streams#catalog-api-flow-caption>): в том же ZIP есть browser-пример с товарами и вызовом основного Web SDK на реальных данных.

## До запроса

Получите у команды ShopStory:

1. `applicationId` проекта.
2. Подтверждение нужного окружения.
3. Регистрацию точного origin, если запрос будет выполняться из браузера.
4. Тестовый эфир или подтверждение, что пустая выборка сейчас ожидаема.

`applicationId` выбирает конфигурацию проекта. Он виден в браузерных запросах и не является паролем. Не используйте его как доказательство полномочий для операций с корзиной, заказом или персональными данными.

## Первый запрос

Для cURL-примера нужны `curl` с поддержкой `--fail-with-body` и `jq`. Для Node.js — версия 22+.

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

- cURL
- Node.js

check-streams.sh

```bash
export SHOPSTORY_APPLICATION_ID="assigned-application-id"
set -o pipefail

curl --silent --show-error --fail-with-body --max-time 8 --get \
  "https://app.shopstory.live/v3/streams" \
  --data-urlencode "applicationId=${SHOPSTORY_APPLICATION_ID}" \
  --data-urlencode "limit=3" \
  --data-urlencode "offset=0" \
  | jq -e '
      if .status != 200 then
        error(.body.message // "ShopStory request failed")
      elif ([.body.availableStreams, .body.plannedStreams,
             .body.products, .body.streamers, .body.categories]
            | all(type == "array") | not) then
        error("Expected catalog collection arrays")
      else
        {
          status,
          total: .body.total,
          available: (.body.availableStreams | length),
          planned: (.body.plannedStreams | length)
        }
      end
    '
```

check-streams.mjs

```javascript
const applicationId = process.env.SHOPSTORY_APPLICATION_ID;

if (!applicationId) {
  throw new Error('SHOPSTORY_APPLICATION_ID is required');
}

const url = new URL('https://app.shopstory.live/v3/streams');
url.search = new URLSearchParams({
  applicationId,
  limit: '3',
  offset: '0',
}).toString();

const response = await fetch(url, {
  signal: AbortSignal.timeout(8_000),
});

if (!response.ok) {
  throw new Error(`ShopStory HTTP ${response.status}`);
}

const payload = await response.json();

if (!payload || !Number.isInteger(payload.status)) {
  throw new Error('Invalid ShopStory response envelope');
}

if (payload.status !== 200) {
  throw new Error(payload.body?.message || `ShopStory status ${payload.status}`);
}

const collections = ['availableStreams', 'plannedStreams', 'products', 'streamers', 'categories'];
if (!payload.body || collections.some(name => !Array.isArray(payload.body[name]))) {
  throw new Error('Expected catalog collection arrays');
}

console.log({
  total: payload.body.total,
  available: payload.body.availableStreams.length,
  planned: payload.body.plannedStreams.length,
});
```

Количество элементов зависит от проекта и текущих публикаций. Smoke-тест прошёл, если получены HTTP `200`, верхнеуровневый `status: 200` и массивы в `body`.

Пример успешного ответа:

streams-envelope.json

```json
{
  "status": 200,
  "body": {
    "availableStreams": [],
    "plannedStreams": [],
    "products": [],
    "streamers": [],
    "categories": [],
    "total": 0
  },
  "serverTime": "2025-01-15T10:15:30.000Z"
}
```

Пустые массивы могут быть корректным результатом. Они не доказывают проблему доступа.

## Ошибка параметров

Некоторые `/v3/*` возвращают валидационную ошибку внутри JSON-конверта при транспортном HTTP `200`:

validation-error.json

```json
{
  "status": 400,
  "body": {
    "error": "invalid",
    "message": "invalid applicationId"
  },
  "serverTime": "2025-01-15T10:15:30.000Z"
}
```

Всегда проверяйте оба уровня. [Схема проверок ответа](<https://docs.shopstory.live/docs/guide/architecture#api-response-checks-caption>) и общая функция обработки приведены в разделе «Формат запросов и ответов».

## Фильтры и пагинация

`GET /v3/streams` поддерживает:

| Параметр | Назначение |
| --- | --- |
| `limit` | Размер страницы. Значения выше 100 обрабатываются как 100. |
| `offset` | Смещение от начала выборки |
| `feedProductId` | Точный ID товара из согласованного фида |
| `categoryId` | Категория ShopStory |
| `status` | `planned`, `online` или `finished` |

Фильтры объединяются. Не преобразуйте товарные ID в числа:

filter-by-product.sh

```bash
export SHOPSTORY_APPLICATION_ID="assigned-application-id"
export SHOPSTORY_PRODUCT_ID="product-id-from-feed"

curl --silent --show-error --fail-with-body --max-time 8 --get \
  "https://app.shopstory.live/v3/streams" \
  --data-urlencode "applicationId=${SHOPSTORY_APPLICATION_ID}" \
  --data-urlencode "feedProductId=${SHOPSTORY_PRODUCT_ID}" \
  --data-urlencode "limit=10"
```

Полная схема: [Каталог эфиров](<https://docs.shopstory.live/docs/guide/catalog-streams>).

Используйте одно строковое значение `feedProductId` в товарном фиде, на web-PDP, в native-PDP и в product action. Не вводите отдельный mobile-ID. Если commerce API ритейлера принимает другой ключ, преобразуйте его на границе commerce-системы.

## Запуск в браузере

Браузерный запрос разрешён только с origins, зарегистрированных ShopStory для проекта. Если запрос из терминала или с сервера работает, а браузер показывает ошибку CORS:

1. Сверьте точный scheme, hostname и port текущей страницы.
2. Убедитесь, что запрос направлен в нужное окружение.
3. Передайте origin менеджеру интеграции ShopStory.

Не обходите CORS открытым relay и не добавляйте учётные данные в URL. Сервер клиента может применять собственные правила доступа, кеширования и наблюдаемости. `applicationId` остаётся видимым идентификатором.

## Production-чеклист

- HTTP-запрос имеет ограниченный тайм-аут на стороне клиента.
- Проверяются HTTP-код, JSON-конверт и состояние ресурса.
- Интерфейс различает загрузку, пустую выдачу и ошибку.
- Новые необязательные поля не ломают парсер.
- Идентификаторы остаются строками.
- Повторные запросы ограничены и выполняются с backoff.
- Сбой ShopStory не блокирует основной каталог или checkout клиента.
- Реальные пароли, cookies и токены не вставляются в публичные онлайн-инструменты.

## Следующие шаги

- [Формат запросов и ответов](<https://docs.shopstory.live/docs/guide/architecture>)
- [Каталог эфиров](<https://docs.shopstory.live/docs/guide/catalog-streams>)
- [Mini-player API](<https://docs.shopstory.live/docs/guide/mini-player>)
- [Mobile SDK](<https://docs.shopstory.live/docs/guide/mobile-sdk>)
- [Интеграция с интернет-магазином](<https://docs.shopstory.live/docs/guide/custom-commerce-integrations>)
- [Аналитика и события](<https://docs.shopstory.live/docs/guide/analytics>)
- [Эксплуатация и безопасность](<https://docs.shopstory.live/docs/operations/security>)
