Published
How to Upload Your Catalog for SiteChat
If you use SiteChat on your own website (not a Shopify store), you can send structured product records to Shoply so shoppers can find them in SiteChat chat and product search.
These endpoints use the same Settings → Store owner API secret as the rest of the Shoply Merchant API, and the SiteChat admin Product Catalog page can call them with your signed-in admin access token. Shopify stores continue to sync catalog data through Shopify; these upload routes are available only for SiteChat accounts that do not already sync a Magento catalog.
In the SiteChat admin, Product Catalog opens a Shopify-style area with Products, Collections, and Inventory. You can add or edit products, import CSV/Excel, group products into manual collections, and adjust stock quantities.
What APIs Are Available?
| API | Method | What it does |
|---|---|---|
/merchant/products/batch | POST | Create or fully replace up to 50 products in one request |
/merchant/products | POST | Create or fully replace one product |
/merchant/products | GET | Read back one imported product by source and external_id |
/merchant/products | PATCH | Partially update one product (read-merge-write) |
/merchant/products | DELETE | Soft-archive a product (status=archived) |
/merchant/products/list | GET | Page through imported products for admin tables |
/merchant/products/images | POST | Upload a product image and receive a public HTTPS URL |
/merchant/collections | GET / POST | List or create manual collections |
/merchant/collections/{id} | GET / PUT / DELETE | Read, replace, or archive one collection |
/merchant/inventory | GET | List stock rows (product and variant quantities) |
/merchant/inventory/adjust | POST | Set tracked quantity for a product or variant |
Successful product saves ask Shoply to rebuild the store index. Until that rebuild finishes, responses report index_status: "pending". Published products then appear in both the product index and the knowledge used by SiteChat chat.
Who Can Use These APIs?
- Your store must be a SiteChat account (
app_platformis SiteChat). - Shopify store keys (including any
*.myshopify.comdomain) are rejected. - Authentication must use either a valid store-owner API secret or a SiteChat admin access token for the exact
store_keyin the request. - Shopify Admin API tokens cannot call these routes.
Create or rotate the owner secret the same way as other Merchant API integrations: How to Use the Shoply Merchant API. In the SiteChat admin console, open Product Catalog to manage products, collections, and inventory—or import a CSV or Excel file—without managing the secret yourself.
How Does Authentication Work?
From a server connector
Call the API from a trusted backend over HTTPS. Put a JSON string in the Authorization header:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"store_owner_api_secrete": "YOUR_STORE_OWNER_API_SECRET"
}store_owner_api_secrete is the public field name, including the historical spelling. store_owner_api_secret is also accepted. This is not a Bearer token.
From the SiteChat admin
The Product Catalog page sends your signed-in admin session instead:
{
"store_key": "YOUR_SITECHAT_STORE_KEY",
"admin_auth_token": "YOUR_SITECHAT_ACCESS_TOKEN"
}access_token is accepted as an alias for admin_auth_token.
The store_key query parameter must match the header. Keep owner secrets in server-side environment variables only—never in a storefront script, URL, or public repository.
export SHOPLY_STORE_KEY="your-sitechat-store-key"
export SHOPLY_STORE_OWNER_API_SECRETE="shoply_owner_key_example123.secret-value"How Do I Upload Products?
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"}
}
]
}
]
}Required fields and rules
- Required product fields:
external_id,title,url,currency,price, andavailable.statusdefaults topublished. - Optional inventory: set
tracks_inventorytotrueand a nonnegativequantityon the product or variant. Shoply then derives availability from stock (quantity > 0) and storestotal_inventoryfor admin lists. sourcenames the catalog connection (not necessarily a platform). Use a stable name such aswoocommerce-main. Allowed characters: lowercase letters, numbers, underscores, and hyphens; up to 64 characters. Form-created products in admin default to sourceadmin.- Product identity is the combination of store, source, and external ID. Batch and single
POSTupserts are full replacements, not patches: omitted optional fields are cleared. UsePATCHfor partial updates. - Batches contain 1–50 products and at most 2,000,000 request bytes. Each product’s validated JSON is limited to 128,000 bytes, with at most 250 variants.
- Prefer decimal strings for prices. Currency is a three-letter uppercase code.
- Product and image URLs must be HTTP(S). Importing does not fetch those URLs for you.
- Use public
metafieldsfor searchable product specs (SiteChat’s analogue of Shopify product metafields). Values must be plain strings. Legacyattributesis accepted as an alias. Private productmetadatais no longer supported. draftandarchivedproducts are left out of the next published index. Sold-out published products stay indexed with availability attached.- Manual collections store a title, description, status, and a list of product memberships (
source+external_id). Smart/rule-based collections are not supported in this release.
Sample success response
{
"results": [
{
"external_id": "123",
"product_id": "sitechat_product::woocommerce-main::<sha256-of-external-id>",
"status": "stored"
}
],
"index_status": "pending",
"index_revision": 1
}Shoply validates the whole request before writing. An HTTP 200 can still list some failed results with error: "storage_error". Inspect every result and retry failed products. If index_status is request_failed, storage succeeded but indexing was not scheduled—retry the stored products as well.
Python example
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")How Do I Verify an Imported Product?
GET https://api.shoplyai.ai/merchant/products?store_key=YOUR_SITECHAT_STORE_KEY&source=woocommerce-main&external_id=123
Use the same Authorization header. The response includes schema_version, updated_at, index_status, and the normalized product. Missing records return HTTP 404.
After the background indexer publishes a rebuild, per-product readback status becomes indexed, excluded (for draft or archived products), or limit_exceeded. Use GET /merchant/products/list for admin listing. Soft-archive with DELETE /merchant/products (or set status to archived / draft) to keep a product out of the next published index; there is no hard-delete in this release.
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"])Can I Upload Product Images?
Yes. If an image is already available at a lasting public HTTPS URL, put that URL in the product images list or a variant’s image field. Public S3 HTTPS URLs work. Raw s3:// paths and short-lived signed URLs do not.
To have Shoply host the file, upload raw image bytes from your backend:
POST https://api.shoplyai.ai/merchant/products/images?store_key=YOUR_SITECHAT_STORE_KEY
Content-Type: image/pngSend the raw file bytes, not JSON, base64, or multipart form data. JPEG, PNG, and WebP are accepted, up to 10 MiB and 20 million pixels. Animated images are not supported. Shoply converts the image to WebP and removes embedded metadata.
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 returns url, content_type, size_bytes, width, and height. Uploading an image alone does not attach it to a product or request indexing. Include the returned URL in a complete product and submit it again through /merchant/products/batch.
The same image uploaded again for the same account reuses its URL. A changed image receives a new URL. There is no image-delete endpoint in this release.
When Do Products Appear in Chat and Search?
After a successful batch save, Shoply requests a background index rebuild. Responses report index_status: "pending" until the worker publishes the new index. There is no fixed completion-time guarantee.
- Published products enter both product search and the knowledge used by SiteChat chat.
- Draft and archived products are excluded on the next rebuild.
- If indexing was not scheduled (
index_status: "request_failed"), retry the batch for the products that already stored successfully.
What Errors Should I Expect?
| HTTP status | Meaning |
|---|---|
403 | Missing, invalid, expired, or revoked secret; wrong store; or a non-SiteChat account |
404 | The requested imported product does not exist |
413 | The request or image exceeds the size limit |
415 | Image upload used an unsupported Content-Type |
422 | Invalid fields, duplicate IDs, animated or oversized images, or model limits exceeded |
503 | Temporary storage failure |
Secrets expire after 90 days. Create a replacement in Settings → Store owner API secret before expiry, and revoke any secret you no longer need. The same secret can also call analytics, conversation, and knowledge endpoints documented in the Merchant API guide.
For help with an integration, contact Shoply AI.
