Quickstart — первые запросы
Этот раздел только для кастомной API-интеграции. Если нужен путь без ручного API-кода, используйте Web SDK.
Перед началом
Нужно подготовить:
applicationIdвашего проекта.- Серверный proxy (backend/serverless), чтобы не раскрывать
applicationIdв публичном фронтенде. - Доступ к
https://app.shopstory.live.
Интерактивная проверка
GET
/v3/streams
Базовый smoke-тест
- cURL
- Node.js (fetch)
smoke-test.sh
export SHOPSTORY_APPLICATION_ID="your-app-id"
curl -s "https://app.shopstory.live/v3/streams?applicationId=${SHOPSTORY_APPLICATION_ID}&limit=3" \
| jq '{ status, total: .body.total, available: (.body.availableStreams|length), planned: (.body.plannedStreams|length) }'
smoke-test.mjs
const appId = process.env.SHOPSTORY_APPLICATION_ID;
const url = `https://app.shopstory.live/v3/streams?applicationId=${appId}&limit=3`;
const res = await fetch(url);
const payload = await res.json();
console.log({
httpStatus: res.status,
status: payload.status,
total: payload.body?.total,
available: payload.body?.availableStreams?.length ?? 0,
planned: payload.body?.plannedStreams?.length ?? 0,
});
Ожидаемый формат:
expected-response.json
{
"status": 200,
"total": 62,
"available": 62,
"planned": 0
}
Формат ответа (envelope)
Все ответы ShopStory API оборачиваются в единый конверт:
{
"status": 200,
"serverTime": "2026-02-25T14:20:02.343Z",
"body": { ... }
}
| Поле | Описание |
|---|---|
status | Бизнес-статус операции (может отличаться от HTTP-кода) |
serverTime | Серверное время в ISO 8601 |
body | Данные ответа или объект ошибки |
Важно: всегда проверяйте оба уровня — HTTP-код ответа и поле status внутри JSON. Подробнее: Архитектура.
Пагинация и фильтры
filters-and-pagination.sh
# Пагинация
curl -s "https://app.shopstory.live/v3/streams?applicationId=${SHOPSTORY_APPLICATION_ID}&limit=12&offset=0" \
| jq '{ status, total: .body.total }'
# Фильтр по feedProductId
curl -s "https://app.shopstory.live/v3/streams?applicationId=${SHOPSTORY_APPLICATION_ID}&feedProductId=183966" \
| jq '{ status, total: .body.total }'
# Фильтр по categoryId
curl -s "https://app.shopstory.live/v3/streams?applicationId=${SHOPSTORY_APPLICATION_ID}&categoryId=264" \
| jq '{ status, total: .body.total }'
# Фильтр по status
curl -s "https://app.shopstory.live/v3/streams?applicationId=${SHOPSTORY_APPLICATION_ID}&status=online" \
| jq '{ status, total: .body.total }'
Подтвержденные значения фильтра status: planned, online, finished.
Реальное поведение ошибок (важно)
По состоянию на 24 февраля 2026:
/v3/streamsбезapplicationId:- HTTP
200, внутри конвертаstatus: 400,body.error: "invalid".
- HTTP
/v3/streamsс некорректнымstatus:- HTTP
200, внутри конвертаstatus: 400.
- HTTP
/v3/streamsс нечисловымfeedProductId:- HTTP
200,status: 200, обычноtotal: 0(без422).
- HTTP
/v2/mini-player/streamбезproductCode/feedProductId:- HTTP
400,status: 400.
- HTTP
Пример ошибки:
error-envelope.json
{
"status": 400,
"body": {
"error": "invalid",
"message": "invalid applicationId"
},
"serverTime": "2026-02-24T14:20:01.108672592Z"
}
Минимальный server proxy (Node.js)
- Express
- Next.js Route Handler
shopstory-proxy-express.js
import express from 'express';
const app = express();
const APP_ID = process.env.SHOPSTORY_APPLICATION_ID;
app.get('/api/shopstory/streams', async (req, res) => {
const search = new URLSearchParams({
applicationId: APP_ID,
limit: String(req.query.limit ?? 10),
offset: String(req.query.offset ?? 0),
});
const upstream = await fetch(`https://app.shopstory.live/v3/streams?${search}`);
const payload = await upstream.json();
res.status(200).json(payload);
});
app/api/shopstory/streams/route.ts
import { NextResponse } from 'next/server';
const APP_ID = process.env.SHOPSTORY_APPLICATION_ID;
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const upstreamParams = new URLSearchParams({
applicationId: APP_ID ?? '',
limit: searchParams.get('limit') ?? '10',
offset: searchParams.get('offset') ?? '0',
});
const upstream = await fetch(`https://app.shopstory.live/v3/streams?${upstreamParams}`);
const payload = await upstream.json();
return NextResponse.json(payload, { status: 200 });
}