SiteChat용 카탈로그를 업로드하는 방법

A secure merchant key unlocks catalog upload APIs that send products and images into SiteChat search and chat

자체 웹사이트에서 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를 사용할 수 있나요?

APIMethod기능
/merchant/products/batchPOST한 요청에서 최대 50개 상품을 생성하거나 완전히 교체
/merchant/productsPOST하나의 상품을 생성하거나 완전히 교체
/merchant/productsGETsourceexternal_id로 가져온 상품 하나를 다시 조회
/merchant/productsPATCH상품 하나를 부분 업데이트(read-merge-write)
/merchant/productsDELETE상품을 소프트 아카이브(status=archived)
/merchant/products/listGET관리자 테이블용으로 가져온 상품을 페이지 단위로 조회
/merchant/products/imagesPOST상품 이미지를 업로드하고 공개 HTTPS URL 수신
/merchant/collectionsGET / POST수동 컬렉션 목록 조회 또는 생성
/merchant/collections/{id}GET / PUT / DELETE컬렉션 하나 조회, 교체 또는 아카이브
/merchant/inventoryGET재고 행(상품 및 변형 수량) 목록 조회
/merchant/inventory/adjustPOST상품 또는 변형의 추적 수량 설정

상품 저장에 성공하면 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 문자열을 넣습니다:

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 페이지는 대신 로그인된 관리자 세션을 전송합니다:

json
{ "store_key": "YOUR_SITECHAT_STORE_KEY", "admin_auth_token": "YOUR_SITECHAT_ACCESS_TOKEN" }

access_tokenadmin_auth_token의 별칭으로 허용됩니다.

store_key 쿼리 파라미터는 헤더와 일치해야 합니다. 소유자 시크릿은 서버 측 환경 변수에만 보관하세요. 스토어프런트 스크립트, URL 또는 공개 저장소에는 절대 넣지 마세요.

bash
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

json
{ "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_inventorytrue로 설정하고 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는 더 이상 지원되지 않습니다.
  • draftarchived 상품은 다음 게시 인덱스에서 제외됩니다. 품절된 게시 상품은 판매 가능 여부 정보가 포함된 채로 계속 인덱싱됩니다.
  • 수동 컬렉션은 제목, 설명, 상태 및 상품 멤버십 목록(source + external_id)을 저장합니다. 스마트/규칙 기반 컬렉션은 이번 릴리스에서 지원되지 않습니다.

성공 응답 예시

json
{ "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_statusrequest_failed인 경우 저장은 성공했지만 인덱싱이 예약되지 않은 것이므로, 저장된 상품도 다시 재시도해야 합니다.

Python 예시

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로 소프트 아카이브하거나(statusarchived / draft로 설정) 하세요. 이번 릴리스에는 하드 삭제가 없습니다.

python
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가 파일을 호스팅하게 하려면, 백엔드에서 원본 이미지 바이트를 업로드하세요:

text
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 MiB2천만 픽셀까지 가능합니다. 애니메이션 이미지는 지원되지 않습니다. Shoply는 이미지를 WebP로 변환하고 포함된 메타데이터를 제거합니다.

python
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 201url, 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에 문의하세요.