# 상품 등록 (Mall Story Open API)

> 원문: https://developers.mallstory.co.kr/docs/products-create · 전체 문서 목록: https://developers.mallstory.co.kr/llms.txt
> 이 파일은 AI 에이전트가 구현에 참고하도록 같은 쪽을 마크다운으로 옮긴 것이다. 규칙은 관리자 상품 등록 화면과 서버의 저장 가드를 그대로 옮겼다.

## 요청

- `POST https://api.mallstory.kr/v1/shop/{shop_unique}/products`
- 인증: `Authorization: Bearer {소유자 access token}` — 권한 `products:write`. 토큰 받기는 https://developers.mallstory.co.kr/docs/authorization
- 본문: JSON, 필드 이름은 snake_case. 응답도 snake_case.
- 성공: `201 Created` — 저장된 상품 전체(상세의 product 와 같은 모양, 원가 포함).

## 구현 규칙

### 호출 순서

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_ids` 5 · `color_ids` 200 · `custom_options` 5 · `extra_options` 20 · 항목당 선택값 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, message, request_id}` — request_id 는 응답 헤더 X-Request-Id 와 같다)

| 상태 | 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` 와 다름 |

## 요청 예시

개발 서버에서 실제로 등록한 본문이다. `category_id` · `delivery[].template_id` 는 그 쇼핑몰의 키라 그대로 쓰면 `ReferenceNotFound` — 자기 쇼핑몰에서 읽은 키로 바꾼다.

### 옵션 없음

```json
{
  "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"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "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"
}
```

### 옵션 1개

```json
{
  "name": "코튼 양말",
  "sale_price": 5000,
  "cost_price": 1500,
  "stock_quantity": 0,
  "status_type": "SALE",
  "tax_type": "TAX",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "display_status": "DISPLAY",
  "stock_unlimited": false,
  "management_code": "SK-CT-001",
  "option_info": {
    "names": [
      "색상"
    ],
    "pick_types": [
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ]
  },
  "options": [
    {
      "option_type": "COMBINATION",
      "option_name1": "블랙",
      "price": 0,
      "stock_quantity": 20,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "화이트",
      "price": 0,
      "stock_quantity": 15,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "그레이",
      "price": 0,
      "stock_quantity": 0,
      "usable": true
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "product_unique": "6acd9ad3c2ca90eedea62188",
  "product_no": 67,
  "name": "코튼 양말",
  "sale_price": 5000,
  "list_price": null,
  "cost_price": 1500,
  "stock_quantity": 35,
  "status_type": "SALE",
  "display_status": "DISPLAY",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "option_info": {
    "names": [
      "색상"
    ],
    "pick_types": [
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ],
    "generation": "DIRECT",
    "size_template_id": null
  },
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ],
  "created": "2026-10-13T02:43:31.282Z",
  "updated": "2026-10-13T02:43:31.282Z"
}
```

### 옵션 2개

```json
{
  "name": "린넨 셔츠",
  "sale_price": 39000,
  "list_price": 49000,
  "cost_price": 18000,
  "stock_quantity": 0,
  "status_type": "SALE",
  "tax_type": "TAX",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "display_status": "DISPLAY",
  "stock_unlimited": false,
  "management_code": "SH-LN-001",
  "option_info": {
    "names": [
      "색상",
      "사이즈"
    ],
    "pick_types": [
      "SELECT",
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ]
  },
  "options": [
    {
      "option_type": "COMBINATION",
      "option_name1": "화이트",
      "option_name2": "M",
      "price": 0,
      "stock_quantity": 10,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "화이트",
      "option_name2": "L",
      "price": 1000,
      "stock_quantity": 5,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "네이비",
      "option_name2": "M",
      "price": 0,
      "stock_quantity": 0,
      "usable": true
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "product_unique": "6acd9ad3c2ca90eedea6218e",
  "product_no": 68,
  "name": "린넨 셔츠",
  "sale_price": 39000,
  "list_price": 49000,
  "cost_price": 18000,
  "stock_quantity": 15,
  "status_type": "SALE",
  "display_status": "DISPLAY",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "option_info": {
    "names": [
      "색상",
      "사이즈"
    ],
    "pick_types": [
      "SELECT",
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ],
    "generation": "DIRECT",
    "size_template_id": null
  },
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ],
  "created": "2026-10-13T02:43:31.377Z",
  "updated": "2026-10-13T02:43:31.377Z"
}
```

### 옵션 3개

```json
{
  "name": "울 니트 가디건",
  "sale_price": 59000,
  "list_price": 69000,
  "cost_price": 25000,
  "stock_quantity": 0,
  "status_type": "SALE",
  "tax_type": "TAX",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "display_status": "DISPLAY",
  "stock_unlimited": false,
  "management_code": "KN-WL-001",
  "option_info": {
    "names": [
      "색상",
      "사이즈",
      "소재"
    ],
    "pick_types": [
      "SELECT",
      "SELECT",
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ]
  },
  "options": [
    {
      "option_type": "COMBINATION",
      "option_name1": "베이지",
      "option_name2": "M",
      "option_name3": "울 100%",
      "price": 0,
      "stock_quantity": 4,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "베이지",
      "option_name2": "L",
      "option_name3": "울 100%",
      "price": 0,
      "stock_quantity": 2,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "차콜",
      "option_name2": "M",
      "option_name3": "울 혼방",
      "price": -5000,
      "stock_quantity": 6,
      "usable": true
    },
    {
      "option_type": "COMBINATION",
      "option_name1": "차콜",
      "option_name2": "L",
      "option_name3": "울 혼방",
      "price": -5000,
      "stock_quantity": 0,
      "usable": true
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "product_unique": "6acd9ad3c2ca90eedea62194",
  "product_no": 69,
  "name": "울 니트 가디건",
  "sale_price": 59000,
  "list_price": 69000,
  "cost_price": 25000,
  "stock_quantity": 12,
  "status_type": "SALE",
  "display_status": "DISPLAY",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "option_info": {
    "names": [
      "색상",
      "사이즈",
      "소재"
    ],
    "pick_types": [
      "SELECT",
      "SELECT",
      "SELECT"
    ],
    "manage_fields": [
      "price",
      "stockQuantity",
      "usable"
    ],
    "generation": "DIRECT",
    "size_template_id": null
  },
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ],
  "created": "2026-10-13T02:43:31.450Z",
  "updated": "2026-10-13T02:43:31.450Z"
}
```

### 추가상품

```json
{
  "name": "가죽 키링",
  "sale_price": 12000,
  "cost_price": 4000,
  "stock_quantity": 50,
  "status_type": "SALE",
  "tax_type": "TAX",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "display_status": "DISPLAY",
  "stock_unlimited": false,
  "management_code": "KR-LT-001",
  "extra_options": [
    {
      "name": "선물포장",
      "required": false,
      "use_stock": true,
      "values": [
        {
          "value": "기본 포장",
          "price": 0,
          "stock_quantity": 100
        },
        {
          "value": "고급 포장",
          "price": 3000,
          "stock_quantity": 20
        }
      ]
    },
    {
      "name": "각인 추가",
      "required": false,
      "use_stock": false,
      "values": [
        {
          "value": "이니셜 각인",
          "price": 2000,
          "stock_quantity": 0
        }
      ]
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "product_unique": "6acd9ad3c2ca90eedea6219b",
  "product_no": 70,
  "name": "가죽 키링",
  "sale_price": 12000,
  "cost_price": 4000,
  "stock_quantity": 50,
  "status_type": "SALE",
  "display_status": "DISPLAY",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "extra_options": [
    {
      "name": "선물포장",
      "required": false,
      "use_stock": true,
      "values": [
        {
          "value": "기본 포장",
          "price": 0,
          "stock_quantity": 100
        },
        {
          "value": "고급 포장",
          "price": 3000,
          "stock_quantity": 20
        }
      ]
    },
    {
      "name": "각인 추가",
      "required": false,
      "use_stock": false,
      "values": [
        {
          "value": "이니셜 각인",
          "price": 2000,
          "stock_quantity": 0
        }
      ]
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ],
  "created": "2026-10-13T02:43:31.543Z",
  "updated": "2026-10-13T02:43:31.543Z"
}
```

### 주문 요청사항

```json
{
  "name": "각인 텀블러",
  "sale_price": 25000,
  "cost_price": 9000,
  "stock_quantity": 40,
  "status_type": "SALE",
  "tax_type": "TAX",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "display_status": "DISPLAY",
  "stock_unlimited": false,
  "management_code": "TB-EN-001",
  "custom_scope": "EACH",
  "custom_options": [
    {
      "name": "각인 문구",
      "input_type": "TEXT",
      "required": true,
      "guide": "한글 10자 · 영문 15자까지",
      "fixed_guide": false
    },
    {
      "name": "각인 서체",
      "input_type": "SELECT",
      "required": true,
      "values": [
        "고딕",
        "명조",
        "손글씨"
      ]
    },
    {
      "name": "로고 파일",
      "input_type": "FILE",
      "required": false,
      "guide": "PNG · JPG 파일을 올려 주세요"
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ]
}
```

응답(201, 주요 필드):

```json
{
  "product_unique": "6acd9ad3c2ca90eedea6219e",
  "product_no": 71,
  "name": "각인 텀블러",
  "sale_price": 25000,
  "cost_price": 9000,
  "stock_quantity": 40,
  "status_type": "SALE",
  "display_status": "DISPLAY",
  "category_id": "6aab6a9ddd8941ed187ffe4b",
  "custom_scope": "EACH",
  "custom_options": [
    {
      "name": "각인 문구",
      "input_type": "TEXT",
      "required": true,
      "values": [],
      "guide": "한글 10자 · 영문 15자까지",
      "fixed_guide": false
    },
    {
      "name": "각인 서체",
      "input_type": "SELECT",
      "required": true,
      "values": [
        "고딕",
        "명조",
        "손글씨"
      ],
      "guide": "",
      "fixed_guide": false
    },
    {
      "name": "로고 파일",
      "input_type": "FILE",
      "required": false,
      "values": [],
      "guide": "PNG · JPG 파일을 올려 주세요",
      "fixed_guide": false
    }
  ],
  "delivery": [
    {
      "method": "PARCEL",
      "template_id": "6a9fa2affc6e77ca0e475e4c"
    }
  ],
  "created": "2026-10-13T02:43:31.631Z",
  "updated": "2026-10-13T02:43:31.631Z"
}
```

## 본문 필드

관리자 상품 등록 화면의 섹션 차례다. `코드값` 열이 있으면 그 필드는 아래 코드값 표의 값만 받는다.

### 상품 이미지

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

### 상품 카테고리

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `category_id` | string \| null |  | 대표 카테고리 키([상품 카테고리](https://developers.mallstory.co.kr/docs/categories)의 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 |  | 상품의 과세 구분 | [tax-type](#code-tax-type) |
| `sale_type` | string |  | 새 상품인지 중고인지 | [sale-type](#code-sale-type) |

### 재고수량

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `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-unit](#code-discount-unit) |
| `discount.period.enabled` | boolean |  | 기간 할인을 쓰는가 |  |
| `discount.period.value` | number |  | 기간 할인 값 |  |
| `discount.period.unit` | string |  | 할인 단위. 율이면 0.01 ~ 99.99 | [discount-unit](#code-discount-unit) |
| `discount.period.start_at` | ISO \| null |  | 기간 할인 시작 |  |
| `discount.period.end_at` | ISO \| null |  | 기간 할인 끝 |  |
| `discount.bulk.enabled` | boolean |  | 대량구매 할인을 쓰는가 |  |
| `discount.bulk.rules[].basis` | string |  | 조건(threshold)을 무엇으로 재는가 | [bulk-basis](#code-bulk-basis) |
| `discount.bulk.rules[].apply_to` | string |  | 할인액을 주문 합계에서 한 번 빼는가, 개마다 빼는가 | [bulk-apply-to](#code-bulk-apply-to) |
| `discount.bulk.rules[].conditions[].threshold` | number |  | 이 값(수량 · 금액) 이상이면 |  |
| `discount.bulk.rules[].conditions[].value` | number |  | 할인 값 |  |
| `discount.bulk.rules[].conditions[].unit` | string |  | 할인 단위. 율이면 0.01 ~ 99.99 | [discount-unit](#code-discount-unit) |
| `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 |  | 적립 단위 | [discount-unit](#code-discount-unit) |
| `reward.basis` | string |  | 율로 적립할 때 어느 금액에 율을 곱하는가 | [reward-basis](#code-reward-basis) |

### 주문옵션

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `option_info.names` | string[] |  | 옵션명(예: ["색상", "사이즈"]). 최대 3개. 비우면 옵션 없는 상품 |  |
| `option_info.pick_types` | string[] |  | 옵션명마다 손님이 값을 고르는 모양. `names` 와 같은 자리끼리 짝이고, 모자라면 셀렉트 박스로 채웁니다. `TEMPLATE_COLOR` · `TEMPLATE_SIZE` 는 각각 **한 자리에만** 쓸 수 있습니다(둘 이상이면 400) — 직접 입력 옵션에서도 1 · 2 · 3차 어디든 둘 수 있고, 그 자리가 색상 · 사이즈 자리가 됩니다 | [pick-type](#code-pick-type) |
| `option_info.manage_fields` | string[] |  | 옵션별로 따로 관리할 항목 — 관리자 옵션 목록에 그 열이 섭니다 | [manage-field](#code-manage-field) |
| `options` | array |  | 옵션 행. 보내면 **옵션 전체를 이것으로 바꿉니다** |  |
| `options[].option_type` | string | 필수 | 옵션 행의 종류. 선택형 옵션 행은 `COMBINATION` 입니다 — 주문 요청사항은 이 배열이 아니라 `custom_options` 로 보냅니다 | [option-type](#code-option-type) |
| `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` 가 쓰입니다 | [input-type](#code-input-type) |
| `custom_options[].required` | boolean |  | 손님이 꼭 채워야 하는가 |  |
| `custom_options[].values` | string[] |  | SELECT 일 때 고를 값 |  |
| `custom_options[].guide` | string |  | 칸 안내 문구 |  |
| `custom_options[].fixed_guide` | boolean |  | TEXT 에서만. 켜면 `guide` 가 자리표시자가 아니라 칸에 미리 채워 둔 글이 됩니다(예: “- 기업/단체명:”) |  |
| `custom_scope` | string |  | 주문 요청사항을 주문에 한 번 받는가, 고른 옵션마다 따로 받는가(각인 문구처럼 물건마다 다를 때). 항목마다가 아니라 상품 전체의 설정입니다 | [custom-scope](#code-custom-scope) |
| `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[] |  | 쓰는 색상 키([색상](https://developers.mallstory.co.kr/docs/templates-colors)) |  |
| `size_template_id` | string \| null |  | 쓰는 사이즈 템플릿([사이즈](https://developers.mallstory.co.kr/docs/templates-sizes)) |  |
| `sizes` | string[] |  | 고른 사이즈 |  |

### 배송설정

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `delivery` | array | 필수 | 배송 방식 목록. 같은 방식은 한 번만 넣습니다. 배송 상품이면 하나 이상 — **비우면 배송없음 상품**입니다(배송여부는 수단으로 정합니다) |  |
| `delivery[].method` | string |  | 배송 방식. 같은 방식은 한 번만, 미배송(`NONE`)은 다른 방식과 함께 쓸 수 없습니다 | [delivery-method](#code-delivery-method) |
| `delivery[].template_id` | string |  | 그 방식의 배송 템플릿 키([택배배송](https://developers.mallstory.co.kr/docs/templates-parcel) 등). **NONE 을 뺀 방식은 필수** — 없으면 "택배배송의 템플릿이 지정되지 않았습니다" |  |
| `shippable` | boolean |  | 배송하는 상품인가. **보내지 않으면 `delivery` 로 정합니다** — 수단이 있으면 true, 없으면 false. `true` 로 보내고 수단이 없으면 400 |  |
| `bundle_shipping` | string |  | 다른 상품과 한 상자로 묶어 보낼 수 있는가. 대량구매 할인을 켜면 가능으로 둘 수 없어 부분가능으로 낮춰 저장합니다 | [bundle-shipping](#code-bundle-shipping) |
| `collect_clearance_code` | boolean |  | 주문 때 통관고유부호를 받는가 |  |

### 상세설명

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `detail_content_body` | string |  | 상세 설명 HTML. 이미지는 [이미지 업로드](https://developers.mallstory.co.kr/docs/files)(`?usage=product.detail`)의 `url` 을 `<img src>` 에 넣습니다 — 이 쇼핑몰 파일이면 상품에 붙고, 빼면 지워집니다 |  |
| `video_url` | string |  | 동영상 주소 |  |

### 상품정보제공고시

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `product_info_provided_notice` | object \| null |  | 상품정보제공고시. null 이면 등록하지 않음 |  |
| `product_info_provided_notice.mode` | string |  | 고시를 서식 항목(`fields`)으로 적는가, 이미지(`image`) 한 장으로 넣는가. 고르지 않은 쪽 값은 버립니다 | [notice-mode](#code-notice-mode) |
| `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[] |  | 상세 위에 붙일 [공통정보](https://developers.mallstory.co.kr/docs/templates-common) 키 |  |
| `bottom_template_ids` | string[] |  | 상세 아래에 붙일 공통정보 키 |  |

### 전시 설정

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `display_status` | string |  | 쇼핑몰 화면에 보이는가. 기간 전시면 `display_start_at` · `display_end_at` 가 필수입니다 | [display-status](#code-display-status) |
| `display_start_at` | ISO \| null |  | 기간 전시 시작(PERIOD) |  |
| `display_end_at` | ISO \| null |  | 기간 전시 끝(PERIOD) |  |
| `display_order` | number |  | 기본 전시순(작을수록 앞) |  |
| `badge_ids` | string[] |  | 상품명 앞 배지 키([상품 배지](https://developers.mallstory.co.kr/docs/badges)의 badge_unique). 5개까지 — 쇼핑몰 관리자 화면은 **2개**까지 보여 주고, 관리자에서 다시 저장하면 앞의 2개만 남습니다 |  |
| `icon_id` | string \| null |  | 상품 이미지 우측 상단 아이콘 키([상품 아이콘](https://developers.mallstory.co.kr/docs/icons)의 icon_unique). 하나. `null` 이면 없음 |  |
| `view_permission` | string |  | 누가 상품을 볼 수 있나. 회원으로 좁히면 `view_level` 로 등급까지 거를 수 있습니다 | [permission](#code-permission) |
| `view_level` | number |  | MEMBER 일 때 최소 등급 레벨 |  |

### 판매 설정

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `status_type` | string |  | 판매 상태 — 보낼 때는 `SALE` · `SUSPENSION` 만(관리자 판매상태 탭과 같음). **판매자가 고른 값이 최우선**이라 재고는 판매중 상품에만 품절을 덧씌웁니다 | [status-type](#code-status-type) |
| `sale_start_at` | ISO \| null |  | 판매 시작 |  |
| `sale_end_at` | ISO \| null |  | 판매 끝 |  |
| `order_permission` | string |  | 누가 주문할 수 있나. 회원으로 좁히면 `order_level` 로 등급까지 거를 수 있습니다 | [permission](#code-permission) |
| `order_level` | number |  | MEMBER 일 때 최소 등급 레벨 |  |
| `order_limit.enabled` | boolean |  | 주문 수량을 제한하는가 |  |
| `order_limit.basis` | string |  | 수량 제한을 옵션마다 따로 세는가, 옵션을 합쳐 세는가 | [order-limit-basis](#code-order-limit-basis) |
| `order_limit.min` | number |  | 최소 주문 수량(0 이면 없음) |  |
| `order_limit.max` | number |  | 최대 주문 수량(0 이면 없음) |  |
| `order_limit.max_check` | string |  | 최대 수량을 어느 기간 동안 세는가 — 한 주문 안에서만인지, 지난 며칠의 주문까지 합쳐서인지 | [max-check](#code-max-check) |
| `adult_only` | boolean |  | 성인 인증 상품 |  |

### 기타 설정

| 필드 | 형식 | 필수 | 설명 | 코드값 |
| --- | --- | --- | --- | --- |
| `review_template_id` | string \| null |  | [맞춤형 리뷰](https://developers.mallstory.co.kr/docs/templates-reviews) 키. null 이면 기본 리뷰 |  |
| `seo.mode` | string |  | 검색엔진 문구를 쇼핑몰 기본값으로 둘지, 아래 `page_title` · `meta_description` 를 쓸지 | [seo-mode](#code-seo-mode) |
| `seo.page_title` | string |  | 검색 결과 · 브라우저 탭 제목(MANUAL) |  |
| `seo.meta_description` | string |  | 검색 결과 설명(MANUAL) |  |
| `seo.target_keywords` | string |  | 검색 키워드(쉼표로 구분, MANUAL) |  |

## 코드값

<a id="code-status-type"></a>
### 판매 상태 — status_type

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `SALE` | 판매중 | 보낼 수 있음. 재고가 0 이면 품절로 바뀌고, 다시 생기면 판매중으로 돌아옴 |
| `SUSPENSION` | 판매중지 | 보낼 수 있음. 판매자가 고른 값이라 재고를 채워도 그대로 |
| `OUTOFSTOCK` | 품절 | 응답에만 — 판매중 상품의 재고가 0 일 때 시스템이 정함 |
| `WAIT` | 판매대기 | 응답에만 — 옛 값. 보낼 수 없음 |
| `CLOSE` | 판매종료 | 응답에만 — 옛 값. 보낼 수 없음 |

<a id="code-sale-type"></a>
### 상품 상태 — sale_type

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `NEW` | 새 상품 |  |
| `OLD` | 중고 |  |

<a id="code-tax-type"></a>
### 과세 구분 — tax_type

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `TAX` | 과세 |  |
| `DUTYFREE` | 면세 |  |
| `SMALL` | 영세 |  |

<a id="code-display-status"></a>
### 전시 상태 — display_status

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `DISPLAY` | 전시 |  |
| `STOP` | 전시중지 |  |
| `PERIOD` | 전시기간 | display_start_at ~ display_end_at 사이에만 전시 |

<a id="code-permission"></a>
### 열람 · 주문 권한 — view_permission · order_permission · access_permission

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `GUEST` | 비회원 이상 | 누구나 |
| `MEMBER` | 일반회원 이상 | 회원만. *_level 로 최소 등급을 정함 |

<a id="code-discount-unit"></a>
### 할인 · 적립 단위 — discount.*.unit · reward.unit

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `WON` | 원 |  |
| `PERCENT` | % | 0.01 ~ 99.99, 소수 둘째 자리까지 |

<a id="code-bulk-basis"></a>
### 대량구매 할인 기준 — discount.bulk.rules[].basis

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `ORDER_QUANTITY` | 주문 수량 |  |
| `ORDER_AMOUNT` | 주문 금액 |  |
| `SALE_PRICE` | 판매가 |  |

<a id="code-bulk-apply-to"></a>
### 대량구매 할인 방식 — discount.bulk.rules[].apply_to

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `TOTAL` | 합계에서 뺌 |  |
| `EACH` | 개당 뺌 |  |

<a id="code-reward-basis"></a>
### 적립금 기준 — reward.basis

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `SALE_PRICE` | 판매가 |  |
| `DISCOUNTED` | 할인 뒤 값 |  |

<a id="code-option-type"></a>
### 옵션 행 방식 — options[].option_type

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `COMBINATION` | 선택형 | 옵션명(option_info.names) 조합마다 한 행. API 로 넣는 옵션은 이것입니다 |
| `CUSTOM` | 추가 입력옵션 | API 에서는 options 가 아니라 custom_options 로 넣습니다 |

<a id="code-pick-type"></a>
### 옵션 고르는 방식 — option_info.pick_types[]

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `SELECT` | 셀렉트 박스 |  |
| `RADIO` | 라디오 버튼 |  |
| `TEXT_BUTTON` | 텍스트 버튼 |  |
| `TEMPLATE_COLOR` | 템플릿 색상 | 색상 템플릿의 색 칩. 옵션 하나에만 |
| `TEMPLATE_SIZE` | 템플릿 사이즈 | 사이즈 템플릿의 사이즈. 옵션 하나에만 |

<a id="code-manage-field"></a>
### 옵션 목록 열 — option_info.manage_fields[]

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `number` | 번호 |  |
| `price` | 옵션가 |  |
| `costPrice` | 원가 |  |
| `stockQuantity` | 재고수량 |  |
| `managerCode` | 관리코드 |  |
| `image` | 옵션 이미지 |  |
| `usable` | 노출여부 |  |

<a id="code-input-type"></a>
### 추가 입력옵션 형식 — custom_options[].input_type

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `TEXT` | 텍스트폼 |  |
| `SELECT` | 셀렉트 박스 | values 에서 고름 |
| `FILE` | 첨부파일 |  |

<a id="code-custom-scope"></a>
### 추가 입력옵션 받는 때 — custom_scope

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `ONCE` | 주문 시 한번 |  |
| `EACH` | 옵션별 각각 |  |

<a id="code-delivery-method"></a>
### 배송 방식 — delivery[].method

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `PARCEL` | 택배배송 |  |
| `DIRECT` | 직접배송 |  |
| `QUICK` | 퀵배송 |  |
| `PICKUP` | 방문수령 |  |
| `NONE` | 미배송 | 다른 방식과 함께 쓸 수 없고 템플릿이 없음 |

<a id="code-bundle-shipping"></a>
### 묶음배송 — bundle_shipping

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `POSSIBLE` | 가능 |  |
| `PARTIAL` | 부분가능 |  |
| `IMPOSSIBLE` | 불가 |  |

<a id="code-notice-mode"></a>
### 상품정보제공고시 방식 — product_info_provided_notice.mode

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `FORM` | 서식 | 서식 코드의 항목을 fields 에 채움 |
| `IMAGE` | 이미지 | image 한 장 |

<a id="code-order-limit-basis"></a>
### 주문 수량을 세는 방식 — order_limit.basis

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `EACH` | 옵션별 개별 수량 |  |
| `TOTAL` | 옵션별 합산 수량 |  |

<a id="code-max-check"></a>
### 최대 수량을 세는 기간 — order_limit.max_check

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `ORDER` | 주문 건당 |  |
| `DAY` | 주문 당일 |  |
| `DAYS_3` | 지난 3일 |  |
| `DAYS_7` | 지난 7일 |  |
| `DAYS_30` | 지난 30일 |  |

<a id="code-seo-mode"></a>
### 검색 노출 설정 — seo.mode

| 값 | 뜻 | 설명 |
| --- | --- | --- |
| `AUTO` | 자동 | 쇼핑몰 기본값을 씀 |
| `MANUAL` | 직접 입력 | page_title · meta_description · target_keywords 를 씀 |
