상품 등록
상품을 등록합니다. 필드는 관리자 상품 등록 화면의 섹션 차례로 정리했습니다.
업데이트됨 10.26 — 직접 입력 옵션에서 템플릿 색상 · 사이즈 자리를 1 · 2 · 3차 어디든 둘 수 있습니다AI 에이전트용 마크다운 원문 — /docs/products-create.md요청
https://api.mallstory.kr/v1/shop/{shop_unique}/products필수는 name · sale_price 둘이고, 배송하는 상품이면 delivery(배송수단)를 하나 이상 넣습니다 — 비우면 배송없음 상품으로 등록됩니다. 관리자 상품 등록 화면이 저장 전에 막는 것을 API 도 똑같이 막고, 보내지 않은 필드는 그 화면의 기본값으로 저장됩니다. 조건부 필수 · 상한 · 서버가 바꿔 저장하는 값은 맨 아래 구현 규칙에 모았습니다.
/docs/products-create.md. 구현 규칙 · 필드 · 코드값 · 예시가 한 파일에 들어 있습니다. → AI 에이전트로 개발하기탭은 상황별 본문입니다(응답 예시도 같은 탭으로 바뀝니다). 옵션 없음은 stock_quantity 를 바로 적고, 옵션 1~3개는 option_info.names 와 행의 option_name1 ~ option_name3 을 같은 차례로 채웁니다. 덧붙여 사는 것은 extra_options(추가상품), 손님이 적어 내는 것은 custom_options(주문 요청사항)이고 주문옵션과 함께 써도 됩니다.
curl -X POST 'https://api.mallstory.kr/v1/shop/{shop_unique}/products' \
-H 'Authorization: Bearer msat_8Hk2wQ7...' \
-H 'Content-Type: application/json' \
-d '{
"name": "무지 에코백",
"sale_price": 15000,
"list_price": 18000,
"cost_price": 6000,
"stock_quantity": 30,
"status_type": "SALE",
"tax_type": "TAX",
"category_id": "6aab6a9ddd8941ed187ffe4b",
"display_status": "DISPLAY",
"stock_unlimited": false,
"search_keywords": [
"에코백"
],
"management_code": "BG-ECO-001",
"delivery": [
{
"method": "PARCEL",
"template_id": "6a9fa2affc6e77ca0e475e4c"
}
]
}'응답
{
"product_unique": "6acd9ad3c2ca90eedea62185",
"product_no": 66,
"name": "무지 에코백",
"sale_price": 15000,
"list_price": 18000,
"cost_price": 6000,
"stock_quantity": 30,
"status_type": "SALE",
"display_status": "DISPLAY",
"category_id": "6aab6a9ddd8941ed187ffe4b",
"option_info": {
"names": [],
"pick_types": [],
"manage_fields": [
"price",
"stockQuantity"
],
"size_template_id": null
},
"delivery": [
{
"method": "PARCEL",
"template_id": "6a9fa2affc6e77ca0e475e4c"
}
],
"created": "2026-10-13T02:43:31.155Z",
"updated": "2026-10-13T02:43:31.155Z"
}만든 상품 전체(상품 상세의 product 와 같은 모양, 원가 포함)를 돌려줍니다. 옵션이 있으면 stock_quantity 는 옵션 재고의 합입니다(옵션 1개 예시는 20 + 15 + 0 = 35). 옵션 행은 상세로 읽습니다.
본문 필드
관리자 상품 등록 화면의 섹션 차례입니다. 응답에만 있는 값(상품 키 · 번호 · 시각)은 보내지 않습니다.
상품 이미지
| 필드 | 형식 | 설명 |
|---|---|---|
images | string[] | object[] | 상품 이미지(첫 장이 대표, 차례 그대로). 키만 보냅니다 — 이미지 업로드(?usage=product.image)로 받은 file_id 를 ["6acc…", "6acc…"] 처럼 문자열 배열로 넣고, [{"file_id": "…"}] 도 같습니다. 보내면 이미지 전체를 이것으로 바꾸고, 빠진 이미지 파일은 지웁니다 |
images[].file_id | string | 이미지 업로드로 받은 키. 보낼 때는 이것만 — 저장소 · 경로 · 크기는 서버가 채웁니다 |
상품 카테고리
| 필드 | 형식 | 설명 |
|---|---|---|
category_id | string | null | 대표 카테고리 키(상품 카테고리의 category_unique). 전체 카테고리는 걸 수 없습니다 |
display_category_ids | string[] | 대표 외에 함께 진열할 카테고리 키 |
상품명
| 필드 | 형식 | 설명 |
|---|---|---|
name필수 | string | 상품명 |
promotion_text | string | 간략소개(상품명 위 작은 글자) |
search_keywords | string[] | 검색어 |
brand | string | 브랜드 |
management_code | string | 판매자 관리 코드(손님에게 보이지 않음) |
supplier | string | 공급사(손님에게 보이지 않음) |
판매가
| 필드 | 형식 | 설명 |
|---|---|---|
sale_price필수 | number | 판매가(원). 최소 금액보다 작으면 거절됩니다 |
list_price | number | null | 정가(원). 손님 화면에 취소선으로 |
cost_price | number | null | 원가(원). 손님에게 보이지 않고 목록 응답에도 없음 |
tax_type | string | 상품의 과세 구분 코드값 |
sale_type | string | 새 상품인지 중고인지 코드값 |
재고수량
| 필드 | 형식 | 설명 |
|---|---|---|
stock_quantity | number | 재고. 옵션이 있으면 옵션 재고의 합으로 저장됩니다. 판매중 상품은 재고가 0 이면 품절, 다시 생기면 판매중으로 돌아옵니다(판매중지는 그대로) |
stock_unlimited | boolean | 재고 무제한 |
restock_alert_excluded | boolean | 재입고 알림 대상에서 제외하는가(true 면 품절 때 재입고 알림 신청을 받지 않음) |
할인 · 적립금
| 필드 | 형식 | 설명 |
|---|---|---|
discount.immediate.enabled | boolean | 즉시 할인을 쓰는가 |
discount.immediate.value | number | 즉시 할인 값(unit 에 따라 원 또는 %) |
discount.immediate.unit | string | 할인 단위. 율이면 0.01 ~ 99.99 코드값 |
discount.period.enabled | boolean | 기간 할인을 쓰는가 |
discount.period.value | number | 기간 할인 값 |
discount.period.unit | string | 할인 단위. 율이면 0.01 ~ 99.99 코드값 |
discount.period.start_at | ISO | null | 기간 할인 시작 |
discount.period.end_at | ISO | null | 기간 할인 끝 |
discount.bulk.enabled | boolean | 대량구매 할인을 쓰는가 |
discount.bulk.rules[].basis | string | 조건(threshold)을 무엇으로 재는가 코드값 |
discount.bulk.rules[].apply_to | string | 할인액을 주문 합계에서 한 번 빼는가, 개마다 빼는가 코드값 |
discount.bulk.rules[].conditions[].threshold | number | 이 값(수량 · 금액) 이상이면 |
discount.bulk.rules[].conditions[].value | number | 할인 값 |
discount.bulk.rules[].conditions[].unit | string | 할인 단위. 율이면 0.01 ~ 99.99 코드값 |
benefit_limit.coupon | boolean | true 면 쿠폰을 쓸 수 없음 |
benefit_limit.level_discount | boolean | true 면 회원 등급 할인을 하지 않음 |
benefit_limit.point | boolean | true 면 적립금을 쓸 수 없음 |
reward.enabled | boolean | 상품 적립금을 주는가 |
reward.value | number | 적립 값 |
reward.unit | string | 적립 단위 코드값 |
reward.basis | string | 율로 적립할 때 어느 금액에 율을 곱하는가 코드값 |
주문옵션
| 필드 | 형식 | 설명 |
|---|---|---|
option_info.names | string[] | 옵션명(예: ["색상", "사이즈"]). 최대 3개. 비우면 옵션 없는 상품 |
option_info.pick_types | string[] | 옵션명마다 손님이 값을 고르는 모양. names 와 같은 자리끼리 짝이고, 모자라면 셀렉트 박스로 채웁니다. TEMPLATE_COLOR · TEMPLATE_SIZE 는 각각 한 자리에만 쓸 수 있습니다(둘 이상이면 400) — 직접 입력 옵션에서도 1 · 2 · 3차 어디든 둘 수 있고, 그 자리가 색상 · 사이즈 자리가 됩니다 코드값 |
option_info.manage_fields | string[] | 옵션별로 따로 관리할 항목 — 관리자 옵션 목록에 그 열이 섭니다 코드값 |
options | array | 옵션 행. 보내면 옵션 전체를 이것으로 바꿉니다 |
options[].option_type필수 | string | 옵션 행의 종류. 선택형 옵션 행은 COMBINATION 입니다 — 주문 요청사항은 이 배열이 아니라 custom_options 로 보냅니다 코드값 |
options[].option_name1 | string | 1단계 옵션값(option_info.names[0] 의 값, 예: 화이트) |
options[].option_name2 | string | 2단계 옵션값(예: M) |
options[].option_name3 | string | 3단계 옵션값 |
options[].price | number | 옵션 가산액(원, 음수 가능) |
options[].stock_quantity | number | 옵션 재고 |
options[].cost_price | number | null | 옵션 원가 |
options[].usable | boolean | 판매하는 옵션인가(false 면 손님 화면에 없음) |
options[].seller_manager_code | string | 판매자 관리 코드 |
options[].image | string | object | null | 옵션 이미지 — 키 문자열 "…" 또는 {"file_id": "…"}(?usage=product.option 으로 올린 것). null 이면 빼기 |
custom_options[].name | string | 입력 칸 이름(예: 각인 문구). 비우면 400 |
custom_options[].input_type | string | 손님이 값을 내는 방식. 셀렉트 박스면 values 가, 텍스트폼 · 첨부파일이면 guide 가 쓰입니다 코드값 |
custom_options[].required | boolean | 손님이 꼭 채워야 하는가 |
custom_options[].values | string[] | SELECT 일 때 고를 값 |
custom_options[].guide | string | 칸 안내 문구 |
custom_options[].fixed_guide | boolean | TEXT 에서만. 켜면 guide 가 자리표시자가 아니라 칸에 미리 채워 둔 글이 됩니다(예: “- 기업/단체명:”) |
custom_scope | string | 주문 요청사항을 주문에 한 번 받는가, 고른 옵션마다 따로 받는가(각인 문구처럼 물건마다 다를 때). 항목마다가 아니라 상품 전체의 설정입니다 코드값 |
extra_options[].name | string | 추가 상품 묶음 이름(예: 쇼핑백) |
extra_options[].required | boolean | 꼭 골라야 하는가 |
extra_options[].use_stock | boolean | 재고를 쓰는가 |
extra_options[].values[].value | string | 고를 값(예: 소형) |
extra_options[].values[].price | number | 그 값의 추가 상품가(원). 0 이상 — 음수는 받지 않습니다 |
extra_options[].values[].stock_quantity | number | 그 값의 재고(use_stock 일 때) |
color_ids | string[] | 쓰는 색상 키(색상) |
size_template_id | string | null | 쓰는 사이즈 템플릿(사이즈) |
sizes | string[] | 고른 사이즈 |
배송설정
| 필드 | 형식 | 설명 |
|---|---|---|
delivery필수 | array | 배송 방식 목록. 같은 방식은 한 번만 넣습니다. 배송 상품이면 하나 이상 — 비우면 배송없음 상품입니다(배송여부는 수단으로 정합니다) |
delivery[].method | string | 배송 방식. 같은 방식은 한 번만, 미배송(NONE)은 다른 방식과 함께 쓸 수 없습니다 코드값 |
delivery[].template_id | string | 그 방식의 배송 템플릿 키(택배배송 등). NONE 을 뺀 방식은 필수 — 없으면 "택배배송의 템플릿이 지정되지 않았습니다" |
shippable | boolean | 배송하는 상품인가. 보내지 않으면 delivery 로 정합니다 — 수단이 있으면 true, 없으면 false. true 로 보내고 수단이 없으면 400 |
bundle_shipping | string | 다른 상품과 한 상자로 묶어 보낼 수 있는가. 대량구매 할인을 켜면 가능으로 둘 수 없어 부분가능으로 낮춰 저장합니다 코드값 |
collect_clearance_code | boolean | 주문 때 통관고유부호를 받는가 |
상세설명
| 필드 | 형식 | 설명 |
|---|---|---|
detail_content_body | string | 상세 설명 HTML. 이미지는 이미지 업로드(?usage=product.detail)의 url 을 <img src> 에 넣습니다 — 이 쇼핑몰 파일이면 상품에 붙고, 빼면 지워집니다 |
video_url | string | 동영상 주소 |
상품정보제공고시
| 필드 | 형식 | 설명 |
|---|---|---|
product_info_provided_notice | object | null | 상품정보제공고시. null 이면 등록하지 않음 |
product_info_provided_notice.mode | string | 고시를 서식 항목(fields)으로 적는가, 이미지(image) 한 장으로 넣는가. 고르지 않은 쪽 값은 버립니다 코드값 |
product_info_provided_notice.product_info_provided_notice_type | string | 서식 코드(의류 · 식품 …). FORM 일 때. IMAGE 면 빈 글자 |
product_info_provided_notice.fields | object | 항목 이름 → 값(예: {"소재": "린넨 100%", "제조국": "대한민국"}). FORM 일 때 |
product_info_provided_notice.image | string | object | null | 이미지 한 장 — 키 문자열 "…" 또는 {"file_id": "…"}, IMAGE 일 때(?usage=product.notice) |
공통정보 템플릿
| 필드 | 형식 | 설명 |
|---|---|---|
top_template_ids | string[] | 상세 위에 붙일 공통정보 키 |
bottom_template_ids | string[] | 상세 아래에 붙일 공통정보 키 |
전시 설정
| 필드 | 형식 | 설명 |
|---|---|---|
display_status | string | 쇼핑몰 화면에 보이는가. 기간 전시면 display_start_at · display_end_at 가 필수입니다 코드값 |
display_start_at | ISO | null | 기간 전시 시작(PERIOD) |
display_end_at | ISO | null | 기간 전시 끝(PERIOD) |
display_order | number | 기본 전시순(작을수록 앞) |
badge_ids | string[] | 상품명 앞 배지 키(상품 배지의 badge_unique). 5개까지 — 쇼핑몰 관리자 화면은 2개까지 보여 주고, 관리자에서 다시 저장하면 앞의 2개만 남습니다 |
icon_id | string | null | 상품 이미지 우측 상단 아이콘 키(상품 아이콘의 icon_unique). 하나. null 이면 없음 |
view_permission | string | 누가 상품을 볼 수 있나. 회원으로 좁히면 view_level 로 등급까지 거를 수 있습니다 코드값 |
view_level | number | MEMBER 일 때 최소 등급 레벨 |
판매 설정
| 필드 | 형식 | 설명 |
|---|---|---|
status_type | string | 판매 상태 — 보낼 때는 SALE · SUSPENSION 만(관리자 판매상태 탭과 같음). 판매자가 고른 값이 최우선이라 재고는 판매중 상품에만 품절을 덧씌웁니다 코드값 |
sale_start_at | ISO | null | 판매 시작 |
sale_end_at | ISO | null | 판매 끝 |
order_permission | string | 누가 주문할 수 있나. 회원으로 좁히면 order_level 로 등급까지 거를 수 있습니다 코드값 |
order_level | number | MEMBER 일 때 최소 등급 레벨 |
order_limit.enabled | boolean | 주문 수량을 제한하는가 |
order_limit.basis | string | 수량 제한을 옵션마다 따로 세는가, 옵션을 합쳐 세는가 코드값 |
order_limit.min | number | 최소 주문 수량(0 이면 없음) |
order_limit.max | number | 최대 주문 수량(0 이면 없음) |
order_limit.max_check | string | 최대 수량을 어느 기간 동안 세는가 — 한 주문 안에서만인지, 지난 며칠의 주문까지 합쳐서인지 코드값 |
adult_only | boolean | 성인 인증 상품 |
기타 설정
오류
{
"code": "InvalidParameterValue",
"message": "판매가를 입력하세요."
}| 상태 | code | 언제 |
|---|---|---|
| 400 | InvalidParameterValue | 필수 값이 없거나 값이 올바르지 않음(판매가를 입력하세요 · 판매가가 최소 금액보다 작음 · 배송(shippable: true)인데 배송수단이 아무것도 지정되어 있지 않습니다 · 전시기간 · 판매기간 누락 등) |
| 400 | OptionEmpty | 옵션명을 넣었는데 옵션 행이 없음(주문옵션이 입력되지 않았습니다) |
| 400 | ReferenceNotFound | 키가 이 쇼핑몰에 없음(이 쇼핑몰에 없는 상품 카테고리 키입니다 · 택배배송 템플릿 등) |
| 400 | InvalidParameterValue | 배송 방식에 템플릿이 없음 · 같은 배송 방식을 두 번 넣음 · 미배송과 다른 방식을 함께 넣음 |
| 400 | InvalidParameterValue | 이미지의 file_id 가 올바르지 않거나 이 쇼핑몰에 올린 이미지가 아님 · 지워진 이미지(상품 이미지 1번째: 이 쇼핑몰에 올린 이미지가 아니거나 지워진 이미지입니다) |
| 400 | InvalidRequestBody | 본문이 JSON 이 아님 |
| 401 | MissingLoginSession | Authorization 헤더에 Bearer 토큰이 없음 |
| 401 | InvalidAccessToken | 토큰이 틀리거나 만료 · 폐기됨 |
| 403 | InsufficientScope | 토큰에 products:read · products:write 가 없음 |
구현 규칙
관리자 상품 등록 화면과 서버가 저장 전에 보는 규칙 전부입니다. 이 규칙을 지키면 400 없이 한 번에 등록됩니다. 같은 내용을 마크다운 원문으로도 받을 수 있습니다.
호출 순서
- 1이미지 올리기이미지가 있으면 먼저 올린다 —
POST /v1/shop/{shop_unique}/files/images?usage=product.image(옵션 이미지product.option· 상품정보제공고시product.notice· 상세 본문product.detail). 응답의file_id만 본문에 넣는다. - 2키 모으기넣을 키를 이 쇼핑몰에서 읽는다 — 카테고리
GET /v1/shop/{shop_unique}/categories, 배송 템플릿GET /v1/shop/{shop_unique}/templates/delivery?method=PARCEL(DIRECT · QUICK · PICKUP), 공통정보 · 색상 · 사이즈 · 맞춤형 리뷰GET /v1/shop/{shop_unique}/templates/{common|colors|sizes|reviews}. 다른 쇼핑몰 키 · 지어낸 키는 400. - 3등록등록한다 —
POST /v1/shop/{shop_unique}/products. 응답은 저장된 상품 전체다. - 4확인저장 결과를 확인한다 —
GET /v1/shop/{shop_unique}/products/{product_unique}. 서버가 바꿔 저장한 값(아래 "서버가 바꿔 저장하는 값")과 옵션 행은 상세에서 읽는다.
언제나 필수
| 필드 | 규칙 |
|---|---|
name | 1 ~ 255자. |
sale_price | 정수 1,000 ~ 99,999,999(원). |
조건부 필수 · 값끼리 맞물리는 규칙
| 이러면 | 이것이 필요 |
|---|---|
status_type 을 보냄 | SALE(판매중) · SUSPENSION(판매중지)만 — 관리자 판매상태 탭과 같다. 품절은 재고가 정하고, 판매기간은 sale_start_at · sale_end_at 로 넣는다. 다른 값은 400 |
shippable: true 를 보냄 | delivery 에 배송 방식 하나 이상. shippable 을 보내지 않으면 delivery 로 정해진다(아래 "서버가 바꿔 저장하는 값") |
delivery[].method 가 NONE 이 아님 | delivery[].template_id — 같은 방식의 이 쇼핑몰 배송 템플릿. 같은 방식은 한 번만, NONE 은 다른 방식과 함께 쓸 수 없음 |
display_status: "PERIOD" | display_start_at · display_end_at(ISO 8601), 종료 > 시작 |
sale_start_at · sale_end_at 중 하나라도 | 둘 다, 종료 > 시작 |
option_info.names 가 비어 있지 않음 | options 에 option_type: "COMBINATION" 행 하나 이상. 행의 option_name1 ~ option_name3 은 names 와 같은 차례 |
| 옵션 행이 있음 | 판매가 + 행의 price(음수 가능) ≥ 1원 |
custom_options[] 항목 | name 필수. input_type: "SELECT" 면 values 하나 이상 |
extra_options[] 항목 | name 필수, values[].value 하나 이상. values[].price ≥ 0(음수 불가) |
discount.immediate.enabled · discount.period.enabled | value > 0. unit: "PERCENT" 면 0.01 ~ 99.99(소수 둘째 자리까지), WON 이면 판매가보다 작게 |
discount.period.enabled | start_at · end_at, 종료 > 시작 |
discount.bulk.enabled | rules[0].conditions 1 ~ 10개, 각 threshold > 0 · value > 0 |
| 할인을 켬 | 모든 할인을 적용한 뒤 판매가 ≥ 1원 |
reward.enabled | value > 0 |
order_limit.enabled | min ≥ 1, max ≥ 1, max ≥ min(같으면 그 수량으로 고정) |
product_info_provided_notice.mode: "IMAGE" | image.file_id(usage product.notice) |
video_url 을 넣음 | 재생할 수 있는 주소 — 유튜브 · 쇼츠 · 비메오 · 틱톡 · 동영상 파일 |
view_permission · order_permission 이 MEMBER | view_level · order_level 로 등급을 거를 수 있음(0 ~ 999) |
| 키 필드를 넣음 | category_id · display_category_ids · badge_ids · color_ids · size_template_id · review_template_id · top_template_ids · bottom_template_ids 가 이 쇼핑몰에 있는 (지우지 않은) 키. 없으면 ReferenceNotFound |
서버가 바꿔 저장하는 값
오류 없이 저장되지만 보낸 값과 달라지는 것입니다. 등록 응답 · 상세로 확인합니다.
- 판매 상태는 판매자가 고른 값이 최우선이다. 재고는
SALE(판매중) 상품에만 품절을 덧씌운다 — 재고가 0 이면OUTOFSTOCK, 다시 생기면SALE로 돌아간다.SUSPENSION(판매중지)은 재고를 채워도 그대로다. 무제한 재고는 품절이 되지 않는다. - 옵션 행이 있으면 상품
stock_quantity는 옵션 재고의 합이고, 판매 상태는 위 규칙대로 그 합으로 맞춘다. shippable을 보내지 않으면delivery로 정한다 — 배송 방식이 하나라도 있으면true, 없으면false(배송없음). 수정에서delivery만 보내도 다시 정한다. 옛 표시NONE은 방식으로 세지 않는다.- 대량구매 할인이 켜져 있고
bundle_shipping이POSSIBLE(없으면 POSSIBLE 로 봄)이면PARTIAL로 낮춰 저장된다 — 할인만 보낸 수정도 저장된 값과 합쳐 본다. 할인을 꺼도POSSIBLE로 되돌리지 않는다. view_permission·order_permission이GUEST면view_level·order_level은 0 이 된다.product_info_provided_notice는 고른mode의 값만 남는다(FORM 이면image를, IMAGE 면fields를 버림).search_keywords는 빈 값 · 중복을 걷어 낸다.option_info.pick_types가names보다 모자라면SELECT로 채운다. 옵션명은 3개까지만 남긴다.size_template_id가 null 이면sizes는 비운다.detail_content_body는 허용한 태그 · 속성만 남기고 씻는다.top_template_ids·bottom_template_ids의 공통정보는 저장하지 않고 손님 화면이 열 때 본문 위 · 아래에 붙인다 — 템플릿을 고치면 그 템플릿을 쓰는 상품에 바로 반영된다. 관리자 상세 응답에는 본문(detail_content_body)만 온다.- 개수 상한을 넘는 일부 목록은 오류 없이 잘라 저장한다 —
badge_ids5 ·color_ids200 ·custom_options5 ·extra_options20 · 항목당 선택값 20. 넘게 보내지 않는다.
상한 · 범위
| 필드 | 상한 |
|---|---|
name | 255자 |
promotion_text | 90자 |
brand · supplier · management_code | 각 50자 |
search_keywords | 30개, 하나에 30자 |
seo.page_title / seo.meta_description · seo.target_keywords | 100자 / 300자 |
images | 10장 |
display_category_ids | 10개 |
sizes | 50개, 하나에 30자 |
options | 1,000행. option_name1 ~ 3 · 옵션값 각 100자 |
options[].price | -999,999,990 ~ 999,999,990 |
options[].stock_quantity · stock_quantity | 0 ~ 999,999 |
list_price · cost_price · options[].cost_price | 0 ~ 99,999,999 |
custom_options[].guide | 500자 |
discount.bulk.rules[0].conditions | 10개. threshold — 수량 기준 9,999 · 금액 기준 99,999,999 |
display_order | -999,999 ~ 999,999 |
view_level · order_level | 0 ~ 999 |
video_url | 1,000자 |
detail_content_body | 500,000자(씻기 전 길이) |
보내지 않으면
| 필드 | 저장되는 값 |
|---|---|
status_type | SALE(재고 0 이면 품절 OUTOFSTOCK 으로 보임) |
sale_type · tax_type | NEW · TAX |
display_status · display_order | DISPLAY · 0 |
view_permission · order_permission | GUEST(레벨 0) |
stock_quantity · stock_unlimited | 0 · false |
list_price · cost_price · category_id | null |
shippable | delivery 로 정함(방식이 있으면 true, 없으면 false) |
bundle_shipping | POSSIBLE(대량구매 할인을 켜면 PARTIAL) |
option_info | names: [] · manage_fields: ["price", "stockQuantity"](옵션 없음) |
custom_options · extra_options · images · delivery | [] |
custom_scope | ONCE |
discount · reward · order_limit | 모두 꺼짐(enabled: false), order_limit.max_check: "ORDER" |
seo | mode: "AUTO" |
benefit_limit · adult_only · restock_alert_excluded | 모두 false |
수정(PATCH)이 다른 점
- 보낸 필드만 바뀐다. 등록의 필수 조건은 보낸 칸과 이어진 것만 수정 뒤 값으로 다시 본다 —
display_status·display_start_at·display_end_at을 보내면 전시기간,sale_start_at·sale_end_at이면 판매기간,shippable·delivery면 배송수단,options없이option_info면 저장된 옵션 행. 보내지 않은 칸의 옛 빈칸으로는 막지 않는다. delivery만 보내면 배송여부(shippable)를 남은 방식으로 다시 정한다(모두 지우거나NONE이면 배송없음).shippable: true를 보냈는데 수정 뒤 배송 방식이 하나도 없으면 400.options·images는 통째로 바꾼다. 일부만 고치려 해도 남길 것까지 모두 보낸다. 빠진 이미지 파일은 바로 지워진다.expected_updated에 상세에서 읽은updated를 넣으면 그 사이 다른 곳에서 고쳤을 때 409 로 막힌다(덮어쓰기 방지).
오류 코드
| 상태 | code | 원인 |
|---|---|---|
| 400 | InvalidParameterValue | 필수 값 없음 · 형식 · 범위 · 조건부 필수 위반(메시지가 어느 칸인지 말한다) |
| 400 | OptionEmpty | 옵션명을 넣었는데 옵션 행이 없음 |
| 400 | OptionBelowFloor | 옵션가(차감)를 적용하면 결제금액이 1원 미만이 되는 행 — 할인을 켰으면 할인 적용 후 판매가에 옵션가를 더해 본다. 메시지는 할인 유무로 둘: "판매가에 옵션가(차감) 적용 시 …" · "판매가에서 할인 적용 후 옵션가(차감) 적용 시 결제금액이 0 또는 마이너스 되는 옵션은 등록할 수 없습니다." |
| 400 | DiscountBelowFloor | 켠 할인을 모두 더하면 판매가 이상 — 할인 하나면 "{할인} 금액은 판매가를 초과할 수 없습니다.", 둘 이상이면 "할인 합계가 판매가와 같거나 초과하였습니다." |
| 400 | ReferenceNotFound | 이 쇼핑몰에 없는 키(카테고리 · 배송 템플릿 · 배지 · 아이콘 · 색상 · 사이즈 · 리뷰 · 공통정보) |
| 400 | InvalidRequestBody | 본문이 JSON 이 아님 |
| 401 | InvalidAccessToken | 토큰 없음 · 만료 · 폐기 |
| 403 | InsufficientScope | 토큰에 products:write 가 없음 |
| 409 | ProductModified | 수정에서 expected_updated 가 지금 updated 와 다름 |