Cómo subir tu catálogo para SiteChat
Si usas SiteChat en tu propio sitio web (no en una tienda Shopify), puedes enviar registros de productos estructurados a Shoply para que los compradores puedan encontrarlos en el chat de SiteChat y en la búsqueda de productos.
Estos endpoints usan el mismo Settings → Store owner API secret que el resto de la API para comerciantes de Shoply, y la página Product Catalog del administrador de SiteChat puede llamarlos con tu token de acceso de administrador mientras has iniciado sesión. Las tiendas Shopify siguen sincronizando los datos del catálogo a través de Shopify; estas rutas de carga están disponibles solo para cuentas de SiteChat que no sincronizan ya un catálogo de Magento.
En el administrador de SiteChat, Product Catalog abre un área al estilo de Shopify con Products, Collections e Inventory. Puedes agregar o editar productos, importar CSV/Excel, agrupar productos en colecciones manuales y ajustar cantidades de inventario.
¿Qué APIs están disponibles?
| API | Método | Qué hace |
|---|---|---|
/merchant/products/batch | POST | Crea o reemplaza por completo hasta 50 productos en una sola solicitud |
/merchant/products | POST | Crea o reemplaza por completo un producto |
/merchant/products | GET | Lee un producto importado por source y external_id |
/merchant/products | PATCH | Actualiza parcialmente un producto; reemplazar variantes o metafields requiere la versión de GET |
/merchant/products | DELETE | Archiva de forma reversible un producto (status=archived) |
/merchant/products/list | GET | Pagina productos importados para tablas de administración |
/merchant/products/images | POST | Sube una imagen de producto y devuelve una URL pública HTTPS |
/merchant/collections | GET / POST | Lista o crea colecciones manuales |
/merchant/collections/{id} | GET / PUT / DELETE | Lee, reemplaza o archiva una colección |
/merchant/inventory | GET | Lista filas de inventario (cantidades de productos y variantes) |
/merchant/inventory/adjust | POST | Establece la cantidad controlada de un producto o variante |
Los guardados exitosos de productos hacen que Shoply reconstruya el índice de la tienda. Hasta que esa reconstrucción termine, las respuestas informan index_status: "pending". Luego, los productos publicados aparecen tanto en el índice de productos como en el conocimiento usado por el chat de SiteChat.
¿Quién puede usar estas APIs?
- Tu tienda debe ser una cuenta de SiteChat (
app_platformes SiteChat). - Se rechazan claves de tiendas Shopify (incluido cualquier dominio
*.myshopify.com). - La autenticación debe usar un secreto de API válido del propietario de la tienda o un token de acceso de administrador de SiteChat para el
store_keyexacto de la solicitud. - Los tokens de Shopify Admin API no pueden llamar a estas rutas.
Crea o rota el secreto del propietario de la misma forma que con otras integraciones de Merchant API: Cómo usar la API para comerciantes de Shoply. En la consola de administración de SiteChat, abre Product Catalog para gestionar productos, colecciones e inventario —o importar un archivo CSV o Excel— sin tener que gestionar el secreto por tu cuenta.
¿Cómo funciona la autenticación?
Desde un conector de servidor
Llama a la API desde un backend confiable a través de HTTPS. Coloca una cadena JSON en el encabezado Authorization:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"store_owner_api_secrete": "YOUR_STORE_OWNER_API_SECRET"
}store_owner_api_secrete es el nombre de campo público, incluida la ortografía histórica. También se acepta store_owner_api_secret. Esto no es un token Bearer.
Desde el administrador de SiteChat
La página Product Catalog envía en su lugar tu sesión de administrador iniciada:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"admin_auth_token": "YOUR_SITECHAT_ACCESS_TOKEN"
}access_token se acepta como alias de admin_auth_token.
El parámetro de consulta store_key debe coincidir con el encabezado. Mantén los secretos del propietario solo en variables de entorno del lado del servidor; nunca en un script del escaparate, una URL o un repositorio público.
export SHOPLY_STORE_KEY="your-sitechat-store-key"
export SHOPLY_STORE_OWNER_API_SECRETE="shoply_owner_key_example123.secret-value"¿Cómo subo productos?
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"}
}
]
}
]
}Campos y reglas requeridos
- Campos de producto obligatorios:
external_id,title,url,currency,priceyavailable.statususapublishedpor defecto. - Inventario opcional: establece
tracks_inventoryentruey unaquantityno negativa en el producto o la variante. Entonces Shoply deriva la disponibilidad a partir del inventario (quantity > 0) y almacenatotal_inventorypara las listas del administrador. sourcenombra la conexión del catálogo (no necesariamente una plataforma). Usa un nombre estable comowoocommerce-main. Caracteres permitidos: letras minúsculas, números, guiones bajos y guiones; hasta 64 caracteres. Los productos creados desde formularios en el administrador usan por defecto la fuenteadmin.- La identidad del producto es la combinación de tienda, fuente y ID externo. Los upserts
POSTpor lotes y unitarios son reemplazos completos, no parches: los campos opcionales omitidos se borran. UsaPATCHpara actualizaciones parciales. - Los lotes contienen de 1 a 50 productos y como máximo 2,000,000 bytes por solicitud. El JSON validado de cada producto está limitado a 128,000 bytes, con un máximo de 250 variantes.
- Prefiere cadenas decimales para los precios. La moneda es un código de tres letras en mayúsculas.
- Las URL del producto y de las imágenes deben ser HTTP(S). La importación no recupera esas URL por ti.
- Usa
metafieldspúblicos para especificaciones de producto que se puedan buscar (el equivalente en SiteChat a los metafields de producto de Shopify). Los valores deben ser cadenas simples. Se aceptaattributesheredado como alias. Elmetadataprivado del producto ya no es compatible. - Los productos
draftyarchivedse omiten del siguiente índice publicado. Los productos publicados agotados siguen indexados con su disponibilidad asociada. - Las colecciones manuales almacenan un título, una descripción, un estado y una lista de pertenencias de productos (
source+external_id). Las colecciones inteligentes/basadas en reglas no son compatibles en esta versión.
Ejemplo de respuesta exitosa
{
"results": [
{
"external_id": "123",
"product_id": "sitechat_product::woocommerce-main::<sha256-of-external-id>",
"status": "stored"
}
],
"index_status": "pending",
"index_revision": 1
}Shoply valida toda la solicitud antes de escribir. Un HTTP 200 aún puede incluir algunos resultados failed con error: "storage_error". Inspecciona cada resultado y vuelve a intentar los productos fallidos. Si index_status es request_failed, el almacenamiento se realizó correctamente pero no se programó la indexación; vuelve a intentar también los productos almacenados.
Ejemplo en 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")¿Cómo verifico un producto importado?
GET https://api.shoplyai.ai/merchant/products?store_key=YOUR_SITECHAT_STORE_KEY&source=woocommerce-main&external_id=123
Usa el mismo encabezado Authorization. La respuesta incluye schema_version, updated_at, index_status y el product normalizado. Los registros inexistentes devuelven HTTP 404.
Después de que el indexador en segundo plano publique una reconstrucción, el estado de lectura por producto pasa a ser indexed, excluded (para productos draft o archived) o limit_exceeded. Usa GET /merchant/products/list para el listado del administrador. Archiva de forma reversible con DELETE /merchant/products (o establece status en archived / draft) para mantener un producto fuera del siguiente índice publicado; no hay eliminación permanente en esta versión.
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"])¿Cómo actualizo de forma segura variantes o metafields?
Para un PATCH que contenga variants, metafields o el campo heredado attributes, primero lee el producto con GET. Crea la edición a partir de esa respuesta e incluye su valor updated_at de nivel superior como expected_updated_at en el cuerpo del PATCH. Esto también se aplica al borrar variantes o 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 significa que faltaba la versión o que otra actualización cambió el producto. Lee el producto más reciente y vuelve a combinar los cambios que pretendías hacer antes de reintentar. No adjuntes una versión nueva a una lista antigua de variantes: eso podría sobrescribir valores de inventario más recientes.
Las integraciones existentes que hacen PATCH de estos campos sin una versión deben actualizarse. Las solicitudes PATCH solo de escalares, los ajustes de inventario dedicados y los reemplazos completos mediante POST o importación por lotes no requieren este campo. Los reemplazos completos siguen reemplazando todo el producto.
¿Puedo subir imágenes de productos?
Sí. Si una imagen ya está disponible en una URL pública HTTPS estable, coloca esa URL en la lista images del producto o en el campo image de una variante. Las URL públicas HTTPS de S3 funcionan. Las rutas sin formato s3:// y las URL firmadas de corta duración no.
Para que Shoply aloje el archivo, sube bytes sin procesar de la imagen desde tu backend:
POST https://api.shoplyai.ai/merchant/products/images?store_key=YOUR_SITECHAT_STORE_KEY
Content-Type: image/pngEnvía los bytes sin procesar del archivo, no JSON, base64 ni datos de formulario multipart. Se aceptan JPEG, PNG y WebP, de hasta 10 MiB y 20 millones de píxeles. Las imágenes animadas no son compatibles. Shoply convierte la imagen a WebP y elimina los metadatos incrustados.
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 devuelve url, content_type, size_bytes, width y height. Subir una imagen por sí sola no la asocia a un producto ni solicita indexación. Incluye la URL devuelta en un producto completo y vuelve a enviarlo mediante /merchant/products/batch.
Si se vuelve a subir la misma imagen para la misma cuenta, se reutiliza su URL. Una imagen modificada recibe una nueva URL. No hay un endpoint para eliminar imágenes en esta versión.
¿Cuándo aparecen los productos en el chat y la búsqueda?
Después de guardar correctamente un lote, Shoply solicita una reconstrucción de índice en segundo plano. Las respuestas informan index_status: "pending" hasta que el worker publique el nuevo índice. No hay una garantía fija de tiempo de finalización.
- Los productos publicados entran tanto en la búsqueda de productos como en el conocimiento usado por el chat de SiteChat.
- Los productos draft y archived se excluyen en la siguiente reconstrucción.
- Si no se programó la indexación (
index_status: "request_failed"), vuelve a intentar el lote para los productos que ya se almacenaron correctamente.
¿Qué errores debo esperar?
| Estado HTTP | Significado |
|---|---|
403 | Secreto faltante, inválido, vencido o revocado; tienda incorrecta; o una cuenta que no es de SiteChat |
404 | El producto importado solicitado no existe |
413 | La solicitud o la imagen supera el límite de tamaño |
415 | La carga de imagen usó un Content-Type no compatible |
422 | Campos no válidos, IDs duplicados, imágenes animadas o demasiado grandes, o se superaron límites del modelo |
503 | Falla temporal de almacenamiento |
Los secretos vencen después de 90 días. Crea un reemplazo en Settings → Store owner API secret antes del vencimiento y revoca cualquier secreto que ya no necesites. El mismo secreto también puede llamar a endpoints de analíticas, conversación y conocimiento documentados en la guía de Merchant API.
Para obtener ayuda con una integración, contacta a Shoply AI.
