SiteChat용 카탈로그를 업로드하는 방법
자체 웹사이트에서 SiteChat을 사용하는 경우(Shopify 스토어가 아닌 경우), 구조화된 상품 레코드를 Shoply로 전송하여 쇼핑객이 SiteChat 채팅과 상품 검색에서 해당 상품을 찾을 수 있도록 할 수 있습니다.
이 엔드포인트들은 나머지 Shoply Merchant API와 동일한 Settings → Store owner API secret를 사용하며, SiteChat 관리자 Product Catalog 페이지는 로그인된 관리자 액세스 토큰으로 이를 호출할 수 있습니다. Shopify 스토어는 계속해서 Shopify를 통해 카탈로그 데이터를 동기화합니다. 이러한 업로드 라우트는 이미 Magento 카탈로그를 동기화하지 않는 SiteChat 계정에서만 사용할 수 있습니다.
SiteChat 관리자에서 Product Catalog를 열면 Products, Collections, Inventory가 있는 Shopify 스타일 영역이 열립니다. 상품을 추가하거나 수정하고, CSV/Excel을 가져오고, 상품을 수동 컬렉션으로 그룹화하고, 재고 수량을 조정할 수 있습니다.
어떤 API를 사용할 수 있나요?
| API | Method | 기능 |
|---|---|---|
/merchant/products/batch | POST | 한 요청에서 최대 50개 상품을 생성하거나 완전히 교체 |
/merchant/products | POST | 하나의 상품을 생성하거나 완전히 교체 |
/merchant/products | GET | source와 external_id로 가져온 상품 하나를 다시 조회 |
/merchant/products | PATCH | 상품 하나를 부분 업데이트(read-merge-write) |
/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_platform이 SiteChat). - Shopify 스토어 키(
*.myshopify.com도메인 포함)는 거부됩니다. - 인증은 요청의 정확한
store_key에 대해 유효한 스토어 소유자 API 시크릿 또는 SiteChat 관리자 액세스 토큰을 사용해야 합니다. - Shopify Admin API 토큰으로는 이 라우트를 호출할 수 없습니다.
소유자 시크릿 생성 또는 교체 방법은 다른 Merchant API 연동과 동일합니다: Shoply Merchant API 사용 방법. SiteChat 관리자 콘솔에서는 Product Catalog를 열어 시크릿을 직접 관리하지 않고도 상품, 컬렉션, 재고를 관리하거나 CSV 또는 Excel 파일을 가져올 수 있습니다.
인증은 어떻게 작동하나요?
서버 커넥터에서
신뢰할 수 있는 백엔드에서 HTTPS를 통해 API를 호출하세요. Authorization 헤더에 JSON 문자열을 넣습니다:
{
"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 쿼리 파라미터는 헤더와 일치해야 합니다. 소유자 시크릿은 서버 측 환경 변수에만 보관하세요. 스토어프런트 스크립트, 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로 설정하고 0 이상의quantity를 지정합니다. 그러면 Shoply는 재고(quantity > 0)로부터 판매 가능 여부를 도출하고 관리자 목록용total_inventory를 저장합니다. source는 카탈로그 연결 이름을 의미합니다(반드시 플랫폼일 필요는 없음).woocommerce-main과 같은 안정적인 이름을 사용하세요. 허용 문자: 소문자, 숫자, 밑줄, 하이픈, 최대 64자. 관리자에서 폼으로 생성된 상품의 기본 source는admin입니다.- 상품 식별자는 스토어, source, external ID의 조합입니다. 배치 및 단일
POST업서트는 전체 교체이며 패치가 아닙니다. 생략된 선택 필드는 지워집니다. 부분 업데이트에는PATCH를 사용하세요. - 배치에는 1~50개 상품을 포함할 수 있으며 요청 크기는 최대 2,000,000바이트입니다. 각 상품의 검증된 JSON은 최대 128,000바이트이며 변형은 최대 250개까지 가능합니다.
- 가격은 가능한 한 십진수 문자열을 사용하세요. 통화는 3글자의 대문자 코드입니다.
- 상품 및 이미지 URL은 HTTP(S)여야 합니다. 가져오기는 해당 URL을 자동으로 가져오지 않습니다.
- 검색 가능한 상품 사양에는 공개
metafields를 사용하세요(SiteChat의 Shopify 상품 metafield에 해당하는 기능). 값은 일반 문자열이어야 합니다. 기존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"])상품 이미지를 업로드할 수 있나요?
네. 이미지가 이미 오래 유지되는 공개 HTTPS URL에서 사용 가능하다면, 해당 URL을 상품의 images 목록이나 변형의 image 필드에 넣으세요. 공개 S3 HTTPS URL은 작동합니다. 원시 s3:// 경로와 수명이 짧은 서명 URL은 지원되지 않습니다.
Shoply가 파일을 호스팅하게 하려면, 백엔드에서 원본 이미지 바이트를 업로드하세요:
POST https://api.shoplyai.ai/merchant/products/images?store_key=YOUR_SITECHAT_STORE_KEY
Content-Type: image/pngJSON, base64 또는 multipart form data가 아니라 원본 파일 바이트를 전송하세요. JPEG, PNG, WebP를 지원하며 최대 10 MiB 및 2천만 픽셀까지 가능합니다. 애니메이션 이미지는 지원되지 않습니다. 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"를 보고합니다. 완료 시간에 대한 고정 보장은 없습니다.
- 게시된 상품은 상품 검색과 SiteChat 채팅에서 사용하는 지식 모두에 들어갑니다.
- 초안 및 아카이브 상품은 다음 재빌드에서 제외됩니다.
- 인덱싱이 예약되지 않았다면(
index_status: "request_failed"), 이미 성공적으로 저장된 상품에 대해 배치를 다시 시도하세요.
어떤 오류를 예상해야 하나요?
| HTTP status | 의미 |
|---|---|
403 | 시크릿이 없거나, 유효하지 않거나, 만료되었거나, 취소되었거나, 잘못된 스토어이거나, SiteChat 계정이 아님 |
404 | 요청한 가져온 상품이 존재하지 않음 |
413 | 요청 또는 이미지가 크기 제한을 초과함 |
415 | 이미지 업로드에 지원되지 않는 Content-Type이 사용됨 |
422 | 잘못된 필드, 중복 ID, 애니메이션 또는 과대 이미지, 또는 모델 제한 초과 |
503 | 일시적인 저장소 실패 |
시크릿은 90일 후 만료됩니다. 만료 전에 Settings → Store owner API secret에서 대체 시크릿을 만들고, 더 이상 필요하지 않은 시크릿은 취소하세요. 동일한 시크릿으로 Merchant API 가이드에 문서화된 분석, 대화, 지식 엔드포인트도 호출할 수 있습니다.
연동 관련 도움이 필요하면 Shoply AI에 문의하세요.
