Перейти к основному содержимому

Актуальная аутентификация ShopStory API

Пока в production

На сегодняшний день все production интеграции используют applicationId в query параметрах. Переход на Bearer токены находится в закрытой бете и будет объявлен отдельно, когда станет доступен всем клиентам. Планируемое окно публичного релиза — H1 2026; следите за апдейтами в релиз-нотах и на этой странице.

Эта страница помогает:

  • безопасно работать с текущим методом applicationId
  • защитить идентификатор от конкурентов и ботов
  • подготовиться к миграции на Bearer токены, когда она станет доступной

🔓 Production метод: applicationId

applicationId — это идентификатор вашего магазина/приложения в ShopStory.

GET https://app.shopstory.live/v3/streams?applicationId=your-app&limit=20

Лучшие практики защиты

  • 🔐 Держите значение в секрете: храните в переменных окружения или секрет-хранилищах CI/CD
  • ♻️ Используйте уникальные значения для dev/staging/prod окружений
  • 🔄 Ротируйте идентификатор при смене команды или подозрении на утечку
  • 💻 Не размещайте в публичном фронтенд-коде — проксируйте запросы через бэкенд
  • 📊 Следите за аномальными запросами по логам и rate-limit событиям

Пример бэкенд-прокси (Node.js)

express/server.js
import fetch from 'node-fetch';
import express from 'express';

const app = express();
const APPLICATION_ID = process.env.SHOPSTORY_APPLICATION_ID;

app.get('/api/shopstory/streams', async (req, res) => {
const search = new URLSearchParams({
applicationId: APPLICATION_ID,
limit: req.query.limit ?? '12',
offset: 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);
});

Как минимизировать риск угадывания applicationId

  • Используйте длинные случайные значения (например, shop_ab12cd34ef вместо бренда в чистом виде)
  • Не используйте одинаковый ID на production и demo сайтах
  • Включите дополнительную проверку referrer/IP на своем прокси, чтобы ограничить выдачу каталога
  • Рассмотрите rate limiting на своей стороне: блокируйте IP, делающие подозрительно много запросов
  • Получайте уведомления об ошибках 401/404 — они часто появляются во время подбора идентификаторов

🚧 Bearer токены (закрытая бета)

Bearer токены — целевая модель аутентификации. Сейчас она доступна ограниченному числу клиентов. Когда функциональность станет публичной, мы обновим документацию и отправим инструкции по миграции.

Что уже готово

  • ✅ Архитектура токенов и маршрутов проверена с пилотными клиентами
  • ✅ Бэкенд поддерживает параллельную работу токенов и applicationId
  • ⚠️ UI для управления токенами находится в разработке
  • ⚠️ Аудит, IP whitelist и scopes появятся одновременно с публичным релизом

Формат токена

sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxx

Как запросить доступ

Свяжитесь с вашим Customer Success менеджером или напишите на support@shopstory.live. Команда оценит готовность и согласует пилот.


📋 Как будет выглядеть миграция

⚠️ Эта секция описывает план на релиз. Выполняйте его только после официального уведомления о запуске токенов.

Чек-лист подготовки

  1. Обновите SDK/бэкенд, чтобы принимать оба способа (query и заголовок)
  2. Создайте конфигурацию для токена (переменная окружения, секрет в Vault и т.д.)
  3. Настройте мониторинг 401/403 ошибок
  4. Запланируйте ротацию токена сразу после GA-релиза
  5. Сообщите команде поддержки о переходе, чтобы закрыть старые applicationId

🚨 Обработка ошибок

400 Bad Request

{
"status": 400,
"body": {
"error": {
"code": "InvalidApplication",
"message": "Unknown applicationId"
}
}
}

Когда возникает:

  • applicationId не указан или содержит опечатку
  • ID клиента отключен или удалён

Как исправить:

  1. Проверьте переменные окружения и конфигурацию прокси
  2. Убедитесь, что значение действительно существует в ShopStory
  3. Для продакшена используйте отдельные ID на каждое окружение

401 Unauthorized (β)

После релиза токенов 401 будет возвращаться, если заголовок Authorization отсутствует или токен отозван. Следите за обновлениями в релиз-нотах.

429 Rate Limit

{
"status": 429,
"body": {
"error": {
"code": "RateLimitExceeded",
"message": "Too many requests"
}
}
}

Совет: Реализуйте экспоненциальный бэкофф и не параллельте запросы больше лимитов. См. Rate limiting.


💡 Примеры использования

React приложение

useShopStoryAPI.js
import { useState, useEffect } from 'react';

// Фронтенд обращается к вашему безопасному прокси
export function useShopStoryAPI(endpoint, options = {}) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
async function fetchData() {
try {
const response = await fetch(
`/api/shopstory${endpoint}`,
{
headers: {
'Accept': 'application/json'
},
...options
}
);

const result = await response.json();

if (result.status !== 200) {
throw new Error(result.body?.error?.message || 'API Error');
}

setData(result.body);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}

fetchData();
}, [endpoint, options]);

return { data, loading, error };
}

// Использование
function StreamsList() {
const { data, loading, error } = useShopStoryAPI('/v3/streams?limit=10');

if (loading) return <div>Загрузка...</div>;
if (error) return <div>Ошибка: {error}</div>;

return (
<div>
{data.availableStreams.map(stream => (
<div key={stream.id}>{stream.name}</div>
))}
</div>
);
}

Node.js Backend

shopstory-client.js
class ShopStoryClient {
constructor({ applicationId, apiToken } = {}) {
if (!applicationId) {
throw new Error('applicationId is required for production');
}

this.applicationId = applicationId;
this.apiToken = apiToken; // будет использоваться, когда токены станут доступны
this.baseURL = 'https://app.shopstory.live';
}

buildUrl(endpoint, params = {}) {
const url = new URL(`${this.baseURL}${endpoint}`);
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.set(key, String(value));
}
});

if (this.apiToken) {
// Bearer токен в будущем заменит query параметр
return { url: url.toString(), headers: { Authorization: `Bearer ${this.apiToken}` } };
}

url.searchParams.set('applicationId', this.applicationId);
return { url: url.toString(), headers: {} };
}

async request(endpoint, { params = {}, method = 'GET', body } = {}) {
const { url, headers } = this.buildUrl(endpoint, params);

const response = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
...headers
},
body
});

const data = await response.json();

if (data.status !== 200) {
const error = new Error(data.body?.error?.message || 'API Error');
error.code = data.body?.error?.code;
error.status = data.status;
throw error;
}

return data.body;
}

getStreams(params = {}) {
return this.request('/v3/streams', { params });
}

getQuickState(translationId) {
return this.request('/v3/translation/quick-state', {
params: { translationId }
});
}
}

// Использование
const client = new ShopStoryClient({
applicationId: process.env.SHOPSTORY_APPLICATION_ID,
apiToken: process.env.SHOPSTORY_API_TOKEN // появится позже
});

const streams = await client.getStreams({ limit: 20 });
console.log('Streams:', streams.availableStreams);

📚 Дополнительные ресурсы


❓ FAQ

Можно ли использовать один токен для нескольких приложений?

Token функциональность пока недоступна публично. Когда она станет активной, мы порекомендуем уникальные токены на приложение/окружение.

Что делать если токен утек?

Доступ в закрытой бете. На этапе production-релиза появится UI для отзывов. До тех пор полагайтесь на защиту applicationId и обращайтесь в поддержку.

Как часто нужно менять токены?

Рекомендации по ротации будут опубликованы в релиз-нотах, когда токены станут общедоступными.

Можно ли ограничить токен по IP?

Функциональность IP whitelist находится в разработке.

Сколько токенов можно создать?

Ограничения и квоты будут объявлены вместе с релизом токенов.


Готовы начать? Перейдите к Quickstart, настройте интеграцию с applicationId и подготовьте код к будущей миграции.