Mall StoryDevelopers
관리자 API상품 관리소유자 토큰

상품 등록

상품을 등록합니다. 필드는 관리자 상품 등록 화면의 섹션 차례로 정리했습니다.

업데이트됨 10.26 — 직접 입력 옵션에서 템플릿 색상 · 사이즈 자리를 1 · 2 · 3차 어디든 둘 수 있습니다AI 에이전트용 마크다운 원문 — /docs/products-create.md

요청

POSThttps://api.mallstory.kr/v1/shop/{shop_unique}/products

필수는 name · sale_price 둘이고, 배송하는 상품이면 delivery(배송수단)를 하나 이상 넣습니다 — 비우면 배송없음 상품으로 등록됩니다. 관리자 상품 등록 화면이 저장 전에 막는 것을 API 도 똑같이 막고, 보내지 않은 필드는 그 화면의 기본값으로 저장됩니다. 조건부 필수 · 상한 · 서버가 바꿔 저장하는 값은 맨 아래 구현 규칙에 모았습니다.

AI 에이전트로 개발한다면
이 쪽을 마크다운으로 그대로 읽을 수 있습니다 — /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). 옵션 행은 상세로 읽습니다.

본문 필드

관리자 상품 등록 화면의 섹션 차례입니다. 응답에만 있는 값(상품 키 · 번호 · 시각)은 보내지 않습니다.

상품 이미지

필드형식설명
imagesstring[] | object[]상품 이미지(첫 장이 대표, 차례 그대로). 키만 보냅니다 — 이미지 업로드(?usage=product.image)로 받은 file_id 를 ["6acc…", "6acc…"] 처럼 문자열 배열로 넣고, [{"file_id": "…"}] 도 같습니다. 보내면 이미지 전체를 이것으로 바꾸고, 빠진 이미지 파일은 지웁니다
images[].file_idstring이미지 업로드로 받은 키. 보낼 때는 이것만 — 저장소 · 경로 · 크기는 서버가 채웁니다

상품 카테고리

필드형식설명
category_idstring | null대표 카테고리 키(상품 카테고리의 category_unique). 전체 카테고리는 걸 수 없습니다
display_category_idsstring[]대표 외에 함께 진열할 카테고리 키

상품명

필드형식설명
name필수string상품명
promotion_textstring간략소개(상품명 위 작은 글자)
search_keywordsstring[]검색어
brandstring브랜드
management_codestring판매자 관리 코드(손님에게 보이지 않음)
supplierstring공급사(손님에게 보이지 않음)

판매가

필드형식설명
sale_price필수number판매가(원). 최소 금액보다 작으면 거절됩니다
list_pricenumber | null정가(원). 손님 화면에 취소선으로
cost_pricenumber | null원가(원). 손님에게 보이지 않고 목록 응답에도 없음
tax_typestring상품의 과세 구분 코드값
sale_typestring새 상품인지 중고인지 코드값

재고수량

필드형식설명
stock_quantitynumber재고. 옵션이 있으면 옵션 재고의 합으로 저장됩니다. 판매중 상품은 재고가 0 이면 품절, 다시 생기면 판매중으로 돌아옵니다(판매중지는 그대로)
stock_unlimitedboolean재고 무제한
restock_alert_excludedboolean재입고 알림 대상에서 제외하는가(true 면 품절 때 재입고 알림 신청을 받지 않음)

할인 · 적립금

필드형식설명
discount.immediate.enabledboolean즉시 할인을 쓰는가
discount.immediate.valuenumber즉시 할인 값(unit 에 따라 원 또는 %)
discount.immediate.unitstring할인 단위. 율이면 0.01 ~ 99.99 코드값
discount.period.enabledboolean기간 할인을 쓰는가
discount.period.valuenumber기간 할인 값
discount.period.unitstring할인 단위. 율이면 0.01 ~ 99.99 코드값
discount.period.start_atISO | null기간 할인 시작
discount.period.end_atISO | null기간 할인 끝
discount.bulk.enabledboolean대량구매 할인을 쓰는가
discount.bulk.rules[].basisstring조건(threshold)을 무엇으로 재는가 코드값
discount.bulk.rules[].apply_tostring할인액을 주문 합계에서 한 번 빼는가, 개마다 빼는가 코드값
discount.bulk.rules[].conditions[].thresholdnumber이 값(수량 · 금액) 이상이면
discount.bulk.rules[].conditions[].valuenumber할인 값
discount.bulk.rules[].conditions[].unitstring할인 단위. 율이면 0.01 ~ 99.99 코드값
benefit_limit.couponbooleantrue 면 쿠폰을 쓸 수 없음
benefit_limit.level_discountbooleantrue 면 회원 등급 할인을 하지 않음
benefit_limit.pointbooleantrue 면 적립금을 쓸 수 없음
reward.enabledboolean상품 적립금을 주는가
reward.valuenumber적립 값
reward.unitstring적립 단위 코드값
reward.basisstring율로 적립할 때 어느 금액에 율을 곱하는가 코드값

주문옵션

필드형식설명
option_info.namesstring[]옵션명(예: ["색상", "사이즈"]). 최대 3개. 비우면 옵션 없는 상품
option_info.pick_typesstring[]옵션명마다 손님이 값을 고르는 모양. names 와 같은 자리끼리 짝이고, 모자라면 셀렉트 박스로 채웁니다. TEMPLATE_COLOR · TEMPLATE_SIZE 는 각각 한 자리에만 쓸 수 있습니다(둘 이상이면 400) — 직접 입력 옵션에서도 1 · 2 · 3차 어디든 둘 수 있고, 그 자리가 색상 · 사이즈 자리가 됩니다 코드값
option_info.manage_fieldsstring[]옵션별로 따로 관리할 항목 — 관리자 옵션 목록에 그 열이 섭니다 코드값
optionsarray옵션 행. 보내면 옵션 전체를 이것으로 바꿉니다
options[].option_type필수string옵션 행의 종류. 선택형 옵션 행은 COMBINATION 입니다 — 주문 요청사항은 이 배열이 아니라 custom_options 로 보냅니다 코드값
options[].option_name1string1단계 옵션값(option_info.names[0] 의 값, 예: 화이트)
options[].option_name2string2단계 옵션값(예: M)
options[].option_name3string3단계 옵션값
options[].pricenumber옵션 가산액(원, 음수 가능)
options[].stock_quantitynumber옵션 재고
options[].cost_pricenumber | null옵션 원가
options[].usableboolean판매하는 옵션인가(false 면 손님 화면에 없음)
options[].seller_manager_codestring판매자 관리 코드
options[].imagestring | object | null옵션 이미지 — 키 문자열 "…" 또는 {"file_id": "…"}(?usage=product.option 으로 올린 것). null 이면 빼기
custom_options[].namestring입력 칸 이름(예: 각인 문구). 비우면 400
custom_options[].input_typestring손님이 값을 내는 방식. 셀렉트 박스면 values 가, 텍스트폼 · 첨부파일이면 guide 가 쓰입니다 코드값
custom_options[].requiredboolean손님이 꼭 채워야 하는가
custom_options[].valuesstring[]SELECT 일 때 고를 값
custom_options[].guidestring칸 안내 문구
custom_options[].fixed_guidebooleanTEXT 에서만. 켜면 guide 가 자리표시자가 아니라 칸에 미리 채워 둔 글이 됩니다(예: “- 기업/단체명:”)
custom_scopestring주문 요청사항을 주문에 한 번 받는가, 고른 옵션마다 따로 받는가(각인 문구처럼 물건마다 다를 때). 항목마다가 아니라 상품 전체의 설정입니다 코드값
extra_options[].namestring추가 상품 묶음 이름(예: 쇼핑백)
extra_options[].requiredboolean꼭 골라야 하는가
extra_options[].use_stockboolean재고를 쓰는가
extra_options[].values[].valuestring고를 값(예: 소형)
extra_options[].values[].pricenumber그 값의 추가 상품가(원). 0 이상 — 음수는 받지 않습니다
extra_options[].values[].stock_quantitynumber그 값의 재고(use_stock 일 때)
color_idsstring[]쓰는 색상 키(색상)
size_template_idstring | null쓰는 사이즈 템플릿(사이즈)
sizesstring[]고른 사이즈

배송설정

필드형식설명
delivery필수array배송 방식 목록. 같은 방식은 한 번만 넣습니다. 배송 상품이면 하나 이상 — 비우면 배송없음 상품입니다(배송여부는 수단으로 정합니다)
delivery[].methodstring배송 방식. 같은 방식은 한 번만, 미배송(NONE)은 다른 방식과 함께 쓸 수 없습니다 코드값
delivery[].template_idstring그 방식의 배송 템플릿 키(택배배송 등). NONE 을 뺀 방식은 필수 — 없으면 "택배배송의 템플릿이 지정되지 않았습니다"
shippableboolean배송하는 상품인가. 보내지 않으면 delivery 로 정합니다 — 수단이 있으면 true, 없으면 false. true 로 보내고 수단이 없으면 400
bundle_shippingstring다른 상품과 한 상자로 묶어 보낼 수 있는가. 대량구매 할인을 켜면 가능으로 둘 수 없어 부분가능으로 낮춰 저장합니다 코드값
collect_clearance_codeboolean주문 때 통관고유부호를 받는가

상세설명

필드형식설명
detail_content_bodystring상세 설명 HTML. 이미지는 이미지 업로드(?usage=product.detail)의 url 을 <img src> 에 넣습니다 — 이 쇼핑몰 파일이면 상품에 붙고, 빼면 지워집니다
video_urlstring동영상 주소

상품정보제공고시

필드형식설명
product_info_provided_noticeobject | null상품정보제공고시. null 이면 등록하지 않음
product_info_provided_notice.modestring고시를 서식 항목(fields)으로 적는가, 이미지(image) 한 장으로 넣는가. 고르지 않은 쪽 값은 버립니다 코드값
product_info_provided_notice.product_info_provided_notice_typestring서식 코드(의류 · 식품 …). FORM 일 때. IMAGE 면 빈 글자
product_info_provided_notice.fieldsobject항목 이름 → 값(예: {"소재": "린넨 100%", "제조국": "대한민국"}). FORM 일 때
product_info_provided_notice.imagestring | object | null이미지 한 장 — 키 문자열 "…" 또는 {"file_id": "…"}, IMAGE 일 때(?usage=product.notice)

공통정보 템플릿

필드형식설명
top_template_idsstring[]상세 위에 붙일 공통정보 키
bottom_template_idsstring[]상세 아래에 붙일 공통정보 키

전시 설정

필드형식설명
display_statusstring쇼핑몰 화면에 보이는가. 기간 전시면 display_start_at · display_end_at 가 필수입니다 코드값
display_start_atISO | null기간 전시 시작(PERIOD)
display_end_atISO | null기간 전시 끝(PERIOD)
display_ordernumber기본 전시순(작을수록 앞)
badge_idsstring[]상품명 앞 배지 키(상품 배지의 badge_unique). 5개까지 — 쇼핑몰 관리자 화면은 2개까지 보여 주고, 관리자에서 다시 저장하면 앞의 2개만 남습니다
icon_idstring | null상품 이미지 우측 상단 아이콘 키(상품 아이콘의 icon_unique). 하나. null 이면 없음
view_permissionstring누가 상품을 볼 수 있나. 회원으로 좁히면 view_level 로 등급까지 거를 수 있습니다 코드값
view_levelnumberMEMBER 일 때 최소 등급 레벨

판매 설정

필드형식설명
status_typestring판매 상태 — 보낼 때는 SALE · SUSPENSION 만(관리자 판매상태 탭과 같음). 판매자가 고른 값이 최우선이라 재고는 판매중 상품에만 품절을 덧씌웁니다 코드값
sale_start_atISO | null판매 시작
sale_end_atISO | null판매 끝
order_permissionstring누가 주문할 수 있나. 회원으로 좁히면 order_level 로 등급까지 거를 수 있습니다 코드값
order_levelnumberMEMBER 일 때 최소 등급 레벨
order_limit.enabledboolean주문 수량을 제한하는가
order_limit.basisstring수량 제한을 옵션마다 따로 세는가, 옵션을 합쳐 세는가 코드값
order_limit.minnumber최소 주문 수량(0 이면 없음)
order_limit.maxnumber최대 주문 수량(0 이면 없음)
order_limit.max_checkstring최대 수량을 어느 기간 동안 세는가 — 한 주문 안에서만인지, 지난 며칠의 주문까지 합쳐서인지 코드값
adult_onlyboolean성인 인증 상품

기타 설정

필드형식설명
review_template_idstring | null맞춤형 리뷰 키. null 이면 기본 리뷰
seo.modestring검색엔진 문구를 쇼핑몰 기본값으로 둘지, 아래 page_title · meta_description 를 쓸지 코드값
seo.page_titlestring검색 결과 · 브라우저 탭 제목(MANUAL)
seo.meta_descriptionstring검색 결과 설명(MANUAL)
seo.target_keywordsstring검색 키워드(쉼표로 구분, MANUAL)

오류

json400 — 판매가 없이 보냄
{
  "code": "InvalidParameterValue",
  "message": "판매가를 입력하세요."
}
상태code언제
400InvalidParameterValue필수 값이 없거나 값이 올바르지 않음(판매가를 입력하세요 · 판매가가 최소 금액보다 작음 · 배송(shippable: true)인데 배송수단이 아무것도 지정되어 있지 않습니다 · 전시기간 · 판매기간 누락 등)
400OptionEmpty옵션명을 넣었는데 옵션 행이 없음(주문옵션이 입력되지 않았습니다)
400ReferenceNotFound키가 이 쇼핑몰에 없음(이 쇼핑몰에 없는 상품 카테고리 키입니다 · 택배배송 템플릿 등)
400InvalidParameterValue배송 방식에 템플릿이 없음 · 같은 배송 방식을 두 번 넣음 · 미배송과 다른 방식을 함께 넣음
400InvalidParameterValue이미지의 file_id 가 올바르지 않거나 이 쇼핑몰에 올린 이미지가 아님 · 지워진 이미지(상품 이미지 1번째: 이 쇼핑몰에 올린 이미지가 아니거나 지워진 이미지입니다)
400InvalidRequestBody본문이 JSON 이 아님
401MissingLoginSessionAuthorization 헤더에 Bearer 토큰이 없음
401InvalidAccessToken토큰이 틀리거나 만료 · 폐기됨
403InsufficientScope토큰에 products:read · products:write 가 없음

구현 규칙

관리자 상품 등록 화면과 서버가 저장 전에 보는 규칙 전부입니다. 이 규칙을 지키면 400 없이 한 번에 등록됩니다. 같은 내용을 마크다운 원문으로도 받을 수 있습니다.

호출 순서

  1. 1
    이미지 올리기
    이미지가 있으면 먼저 올린다 — POST /v1/shop/{shop_unique}/files/images?usage=product.image(옵션 이미지 product.option · 상품정보제공고시 product.notice · 상세 본문 product.detail). 응답의 file_id 만 본문에 넣는다.
  2. 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. 3
    등록
    등록한다 — POST /v1/shop/{shop_unique}/products. 응답은 저장된 상품 전체다.
  4. 4
    확인
    저장 결과를 확인한다 — GET /v1/shop/{shop_unique}/products/{product_unique}. 서버가 바꿔 저장한 값(아래 "서버가 바꿔 저장하는 값")과 옵션 행은 상세에서 읽는다.

언제나 필수

필드규칙
name1 ~ 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.enabledvalue > 0. unit: "PERCENT" 면 0.01 ~ 99.99(소수 둘째 자리까지), WON 이면 판매가보다 작게
discount.period.enabledstart_at · end_at, 종료 > 시작
discount.bulk.enabledrules[0].conditions 1 ~ 10개, 각 threshold > 0 · value > 0
할인을 켬모든 할인을 적용한 뒤 판매가 ≥ 1원
reward.enabledvalue > 0
order_limit.enabledmin ≥ 1, max ≥ 1, max ≥ min(같으면 그 수량으로 고정)
product_info_provided_notice.mode: "IMAGE"image.file_id(usage product.notice)
video_url 을 넣음재생할 수 있는 주소 — 유튜브 · 쇼츠 · 비메오 · 틱톡 · 동영상 파일
view_permission · order_permission 이 MEMBERview_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_ids 5 · color_ids 200 · custom_options 5 · extra_options 20 · 항목당 선택값 20. 넘게 보내지 않는다.

상한 · 범위

필드상한
name255자
promotion_text90자
brand · supplier · management_code각 50자
search_keywords30개, 하나에 30자
seo.page_title / seo.meta_description · seo.target_keywords100자 / 300자
images10장
display_category_ids10개
sizes50개, 하나에 30자
options1,000행. option_name1 ~ 3 · 옵션값 각 100자
options[].price-999,999,990 ~ 999,999,990
options[].stock_quantity · stock_quantity0 ~ 999,999
list_price · cost_price · options[].cost_price0 ~ 99,999,999
custom_options[].guide500자
discount.bulk.rules[0].conditions10개. threshold — 수량 기준 9,999 · 금액 기준 99,999,999
display_order-999,999 ~ 999,999
view_level · order_level0 ~ 999
video_url1,000자
detail_content_body500,000자(씻기 전 길이)

보내지 않으면

필드저장되는 값
status_typeSALE(재고 0 이면 품절 OUTOFSTOCK 으로 보임)
sale_type · tax_typeNEW · TAX
display_status · display_orderDISPLAY · 0
view_permission · order_permissionGUEST(레벨 0)
stock_quantity · stock_unlimited0 · false
list_price · cost_price · category_idnull
shippabledelivery 로 정함(방식이 있으면 true, 없으면 false)
bundle_shippingPOSSIBLE(대량구매 할인을 켜면 PARTIAL)
option_infonames: [] · manage_fields: ["price", "stockQuantity"](옵션 없음)
custom_options · extra_options · images · delivery[]
custom_scopeONCE
discount · reward · order_limit모두 꺼짐(enabled: false), order_limit.max_check: "ORDER"
seomode: "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원인
400InvalidParameterValue필수 값 없음 · 형식 · 범위 · 조건부 필수 위반(메시지가 어느 칸인지 말한다)
400OptionEmpty옵션명을 넣었는데 옵션 행이 없음
400OptionBelowFloor옵션가(차감)를 적용하면 결제금액이 1원 미만이 되는 행 — 할인을 켰으면 할인 적용 후 판매가에 옵션가를 더해 본다. 메시지는 할인 유무로 둘: "판매가에 옵션가(차감) 적용 시 …" · "판매가에서 할인 적용 후 옵션가(차감) 적용 시 결제금액이 0 또는 마이너스 되는 옵션은 등록할 수 없습니다."
400DiscountBelowFloor켠 할인을 모두 더하면 판매가 이상 — 할인 하나면 "{할인} 금액은 판매가를 초과할 수 없습니다.", 둘 이상이면 "할인 합계가 판매가와 같거나 초과하였습니다."
400ReferenceNotFound이 쇼핑몰에 없는 키(카테고리 · 배송 템플릿 · 배지 · 아이콘 · 색상 · 사이즈 · 리뷰 · 공통정보)
400InvalidRequestBody본문이 JSON 이 아님
401InvalidAccessToken토큰 없음 · 만료 · 폐기
403InsufficientScope토큰에 products:write 가 없음
409ProductModified수정에서 expected_updated 가 지금 updated 와 다름