Как загрузить ваш каталог для SiteChat
Если вы используете SiteChat на собственном веб-сайте (не в магазине Shopify), вы можете отправлять структурированные записи о товарах в Shoply, чтобы покупатели могли находить их в чате SiteChat и в поиске по товарам.
Эти эндпоинты используют тот же Settings → Store owner API secret, что и остальная часть Shoply Merchant API, а страница Product Catalog в админке SiteChat может вызывать их с вашим токеном доступа администратора после входа в систему. Магазины Shopify продолжают синхронизировать данные каталога через Shopify; эти маршруты загрузки доступны только для учетных записей SiteChat, которые уже не синхронизируют каталог Magento.
В админке SiteChat раздел Product Catalog открывает область в стиле Shopify с разделами Products, Collections и Inventory. Вы можете добавлять или редактировать товары, импортировать CSV/Excel, группировать товары в ручные коллекции и корректировать складские остатки.
Какие API доступны?
| API | Method | Что делает |
|---|---|---|
/merchant/products/batch | POST | Создает или полностью заменяет до 50 товаров в одном запросе |
/merchant/products | POST | Создает или полностью заменяет один товар |
/merchant/products | GET | Считывает один импортированный товар по source и external_id |
/merchant/products | PATCH | Частично обновляет один товар; для замены вариантов или metafields требуется версия из GET |
/merchant/products | DELETE | Мягко архивирует товар (status=archived) |
/merchant/products/list | GET | Постранично выводит импортированные товары для административных таблиц |
/merchant/products/images | POST | Загружает изображение товара и возвращает публичный HTTPS URL |
/merchant/collections | GET / POST | Выводит список или создает ручные коллекции |
/merchant/collections/{id} | GET / PUT / DELETE | Считывает, заменяет или архивирует одну коллекцию |
/merchant/inventory | GET | Выводит список строк остатков (количества товаров и вариантов) |
/merchant/inventory/adjust | POST | Устанавливает отслеживаемое количество для товара или варианта |
При успешном сохранении товаров Shoply получает запрос на перестроение индекса магазина. Пока это перестроение не завершено, ответы возвращают index_status: "pending". После публикации товары затем появляются и в индексе товаров, и в базе знаний, используемой чатом SiteChat.
Кто может использовать эти API?
- Ваш магазин должен быть учетной записью SiteChat (
app_platformis SiteChat). - Ключи магазина Shopify (включая любой домен
*.myshopify.com) отклоняются. - Аутентификация должна использовать либо действительный секрет API владельца магазина, либо токен доступа администратора SiteChat для точного
store_keyв запросе. - Токены Shopify Admin API не могут вызывать эти маршруты.
Создавайте или ротируйте секрет владельца так же, как и для других интеграций Merchant API: How to Use the Shoply Merchant API. В админ-консоли SiteChat откройте Product Catalog, чтобы управлять товарами, коллекциями и остатками — или импортировать CSV или Excel файл — без необходимости самостоятельно управлять секретом.
Как работает аутентификация?
Из серверного коннектора
Вызывайте API из доверенного backend по HTTPS. Поместите JSON-строку в заголовок Authorization:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"store_owner_api_secrete": "YOUR_STORE_OWNER_API_SECRET"
}store_owner_api_secrete — это публичное имя поля, включая историческое написание. store_owner_api_secret также принимается. Это не токен Bearer.
Из админки SiteChat
Страница Product Catalog вместо этого отправляет вашу административную сессию после входа:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"admin_auth_token": "YOUR_SITECHAT_ACCESS_TOKEN"
}access_token принимается как псевдоним для admin_auth_token.
Параметр запроса store_key должен совпадать с заголовком. Храните секреты владельца только в серверных переменных окружения — никогда в storefront-скрипте, URL или публичном репозитории.
export SHOPLY_STORE_KEY="your-sitechat-store-key"
export SHOPLY_STORE_OWNER_API_SECRETE="shoply_owner_key_example123.secret-value"Как загрузить товары?
POST https://api.shoplyai.ai/merchant/products/batch?store_key=YOUR_SITECHAT_STORE_KEY
{
"source": "woocommerce-main",
"products": [
{
"external_id": "123",
"title": "Trail shoes",
"description": "Water-resistant hiking shoes.",
"url": "https://example.com/products/trail-shoes",
"currency": "USD",
"price": "49.95",
"original_price": "59.95",
"available": true,
"status": "published",
"images": ["https://example.com/images/trail-shoes.jpg"],
"categories": ["Footwear"],
"metafields": {"material": "Leather"},
"variants": [
{
"external_id": "124",
"title": "Brown / 42",
"sku": "TRAIL-BR-42",
"price": "49.95",
"available": true,
"metafields": {"color": "Brown", "size": "42"}
}
]
}
]
}Обязательные поля и правила
- Обязательные поля товара:
external_id,title,url,currency,priceиavailable. Значениеstatusпо умолчанию —published. - Необязательные данные по остаткам: установите
tracks_inventoryвtrueи неотрицательноеquantityу товара или варианта. Тогда Shoply будет определять доступность по наличию на складе (quantity > 0) и сохранятьtotal_inventoryдля административных списков. sourceзадает название подключения каталога (не обязательно платформы). Используйте стабильное имя, напримерwoocommerce-main. Разрешенные символы: строчные буквы, цифры, подчеркивания и дефисы; до 64 символов. Товары, созданные через формы в админке, по умолчанию получают sourceadmin.- Идентичность товара — это комбинация магазина, source и external ID. Batch и одиночные
POSTupsert-запросы — это полные замены, а не патчи: пропущенные необязательные поля очищаются. ИспользуйтеPATCHдля частичных обновлений. - Пакеты содержат 1–50 товаров и не более 2,000,000 байт запроса. Валидированный JSON каждого товара ограничен 128,000 байтами, максимум с 250 вариантами.
- Для цен предпочтительно использовать десятичные строки. Валюта — это трехбуквенный код в верхнем регистре.
- URL товаров и изображений должны быть HTTP(S). Импорт не загружает эти URL за вас.
- Используйте публичные
metafieldsдля пригодных к поиску характеристик товара (аналог Shopify product metafields в SiteChat). Значения должны быть обычными строками. Устаревшееattributesтакже принимается как псевдоним. Приватныеmetadataтовара больше не поддерживаются. - Товары со статусом
draftиarchivedне включаются в следующий опубликованный индекс. Распроданные опубликованные товары остаются в индексе с указанной доступностью. - Ручные коллекции хранят заголовок, описание, статус и список принадлежности товаров (
source+external_id). Умные/основанные на правилах коллекции в этом релизе не поддерживаются.
Пример успешного ответа
{
"results": [
{
"external_id": "123",
"product_id": "sitechat_product::woocommerce-main::<sha256-of-external-id>",
"status": "stored"
}
],
"index_status": "pending",
"index_revision": 1
}Shoply проверяет весь запрос перед записью. HTTP 200 все равно может содержать некоторые результаты failed с error: "storage_error". Проверяйте каждый результат и повторно отправляйте неудачные товары. Если index_status равен request_failed, сохранение прошло успешно, но индексация не была запланирована — повторно отправьте и уже сохраненные товары.
Пример на Python
import json
import os
import requests
store_key = os.environ["SHOPLY_STORE_KEY"]
headers = {
"Authorization": json.dumps({
"store_key": store_key,
"store_owner_api_secrete": os.environ["SHOPLY_STORE_OWNER_API_SECRETE"],
})
}
response = requests.post(
"https://api.shoplyai.ai/merchant/products/batch",
params={"store_key": store_key},
headers=headers,
json={
"source": "custom",
"products": [{
"external_id": "123",
"title": "Trail shoes",
"url": "https://example.com/products/trail-shoes",
"currency": "USD",
"price": "49.95",
"available": True,
}],
},
timeout=60,
)
response.raise_for_status()
result = response.json()
failed = [item["external_id"] for item in result["results"] if item["status"] != "stored"]
if failed:
raise RuntimeError(f"Products need retry: {failed}")
if result["index_status"] == "request_failed":
raise RuntimeError("Products saved, but retry the batch to request indexing")Как проверить импортированный товар?
GET https://api.shoplyai.ai/merchant/products?store_key=YOUR_SITECHAT_STORE_KEY&source=woocommerce-main&external_id=123
Используйте тот же заголовок Authorization. Ответ включает schema_version, updated_at, index_status и нормализованный product. Для отсутствующих записей возвращается HTTP 404.
После того как фоновый индексатор публикует перестроенный индекс, статус обратного чтения по каждому товару становится indexed, excluded (для товаров со статусом draft или archived) или limit_exceeded. Используйте GET /merchant/products/list для административного списка. Выполняйте мягкое архивирование через DELETE /merchant/products (или установите status в archived / draft), чтобы товар не попал в следующий опубликованный индекс; жесткого удаления в этом релизе нет.
record = requests.get(
"https://api.shoplyai.ai/merchant/products",
params={
"store_key": store_key,
"source": "woocommerce-main",
"external_id": "123",
},
headers=headers,
timeout=30,
)
record.raise_for_status()
print(record.json()["index_status"], record.json()["product"]["title"])Как безопасно обновлять варианты или metafields?
Для PATCH, содержащего variants, metafields или устаревшее поле attributes, сначала прочитайте товар через GET. Постройте изменение на основе этого ответа и включите его значение верхнего уровня updated_at как expected_updated_at в тело PATCH. Это также применяется при очистке вариантов или metafields.
current_response = requests.get(
"https://api.shoplyai.ai/merchant/products",
params={"store_key": store_key, "source": "woocommerce-main", "external_id": "123"},
headers=headers,
timeout=30,
)
current_response.raise_for_status()
current = current_response.json()
updated_metafields = {**current["product"].get("metafields", {}), "material": "Leather"}
response = requests.patch(
"https://api.shoplyai.ai/merchant/products",
params={"store_key": store_key},
headers=headers,
json={
"source": "woocommerce-main",
"external_id": "123",
"expected_updated_at": current["updated_at"],
"metafields": updated_metafields,
},
timeout=30,
)
response.raise_for_status()HTTP 409 означает, что версия отсутствовала или другое обновление изменило товар. Прочитайте актуальную версию товара и снова объедините ваши предполагаемые изменения перед повторной попыткой. Не прикрепляйте новую версию к старому списку вариантов: это может перезаписать более новые значения остатков.
Существующие интеграции, которые выполняют PATCH этих полей без версии, необходимо обновить. PATCH-запросы только со скалярными значениями, отдельные корректировки остатков и полные замены через POST или пакетный импорт не требуют этого поля. Полные замены все равно заменяют товар целиком.
Можно ли загружать изображения товаров?
Да. Если изображение уже доступно по постоянному публичному HTTPS URL, поместите этот URL в список images товара или в поле image варианта. Публичные HTTPS URL в S3 работают. Необработанные пути s3:// и короткоживущие подписанные URL — нет.
Чтобы Shoply размещал файл у себя, загрузите необработанные байты изображения из вашего backend:
POST https://api.shoplyai.ai/merchant/products/images?store_key=YOUR_SITECHAT_STORE_KEY
Content-Type: image/pngОтправляйте необработанные байты файла, а не JSON, base64 или multipart form data. Поддерживаются JPEG, PNG и WebP, размером до 10 MiB и 20 миллионов пикселей. Анимированные изображения не поддерживаются. Shoply конвертирует изображение в WebP и удаляет встроенные метаданные.
with open("trail-shoes.png", "rb") as image_file:
response = requests.post(
"https://api.shoplyai.ai/merchant/products/images",
params={"store_key": store_key},
headers={**headers, "Content-Type": "image/png"},
data=image_file,
timeout=60,
)
response.raise_for_status()
image_url = response.json()["url"]HTTP 201 возвращает url, content_type, size_bytes, width и height. Загрузка одного только изображения не привязывает его к товару и не запрашивает индексацию. Включите возвращенный URL в полный объект товара и снова отправьте его через /merchant/products/batch.
Если то же изображение повторно загружается для той же учетной записи, используется тот же URL. Измененное изображение получает новый URL. Эндпоинта удаления изображений в этом релизе нет.
Когда товары появляются в чате и поиске?
После успешного пакетного сохранения Shoply запрашивает фоновое перестроение индекса. Ответы возвращают index_status: "pending", пока worker не опубликует новый индекс. Фиксированной гарантии по времени завершения нет.
- Опубликованные товары попадают и в поиск по товарам, и в базу знаний, используемую чатом SiteChat.
- Черновики и архивированные товары исключаются при следующем перестроении.
- Если индексация не была запланирована (
index_status: "request_failed"), повторно отправьте пакет для товаров, которые уже были успешно сохранены.
Какие ошибки можно ожидать?
| HTTP status | Значение |
|---|---|
403 | Отсутствующий, недействительный, истекший или отозванный секрет; неверный магазин; или не-SiteChat учетная запись |
404 | Запрошенный импортированный товар не существует |
413 | Запрос или изображение превышает ограничение размера |
415 | При загрузке изображения использовался неподдерживаемый Content-Type |
422 | Недопустимые поля, дублирующиеся ID, анимированные или слишком большие изображения, либо превышены ограничения модели |
503 | Временная ошибка хранилища |
Срок действия секретов истекает через 90 days. Создайте замену в Settings → Store owner API secret до истечения срока и отзовите все секреты, которые вам больше не нужны. Тот же секрет также может вызывать эндпоинты аналитики, диалогов и знаний, задокументированные в Merchant API guide.
Если вам нужна помощь с интеграцией, contact Shoply AI.
