특정 상품의 옵션 등록/수정 시에 사용합니다.
옵션 등록/수정 시에는 본 상품이 이미 등록되어 있어야 하며, 본 상품을 찾을 수 없는 경우 에러가 발생됩니다.
각 옵션의 id값은 등록시에 자동으로 생성되며, 옵션 조회 api를 통해 확인할 수 있습니다.
상품 하위에 옵션을 신규 등록하는 경우에는 옵션 리스트 내 id 필드는 빈 값으로 입력하시고, 수정일 경우에는 옵션 id 값을 입력하시면 됩니다. 입력된 옵션 id 값이 존재하지 않는 경우 ‘옵션을 찾을 수 없습니다.’ 에러가 발생됩니다.
일정형 옵션은 신규 등록(일반 상품을 일정형으로 바꾸는 경우 포함) 시 일정(prices)의 scheduleOptionId 와 schedule.baseModifiedAt 을 넣지 않고, 수정할 때는 옵션 조회 응답의 값을 그대로 넣습니다. 기존 일정과 맞추는 규칙은 아래 '일정형 옵션 등록 및 수정 시 주의사항'을 참고해 주세요.
상품 등록시 옵션의 type 필드는 필수 값입니다. 옵션이 없는 상품인 경우 type 필드에 “NONE” 값을 입력해 주세요.
옵션 type은 크게 선택형, 구매자 작성형, 일정형으로 구분됩니다.
- 선택형: 주문시 판매자가 미리 설정해 둔 옵션 리스트 중에서 구매자가 옵션값을 선택하도록 하는 옵션 형태로, 상품 옵션 설정시 다시 독립형(Simple)과 조합형(Combination)으로 구분해서 설정할 수 있습니다.
선택형 중에서는 조합형만 옵션 가격, 옵션별 재고수량, 옵션별 발송예정일 및 옵션 바로구매 설정을 할 수 있습니다. - 구매자 작성형(Custom): 주문시 구매자가 주문하려는 옵션 내용을 직접 작성할 수 있는 옵션 형태 입니다. 판매자가 상품 옵션 설정시 옵션명만 설정합니다.
- 일정형(Schedule): 날짜(체크인·이용일)와 추가 옵션(객실 타입 등, 조합형처럼 옵션명·옵션값으로 정함)을 조합하는 옵션 형태로, 조합별로 옵션가·재고를 설정할 수 있습니다. 여행·숙박 등 일정형 옵션을 사용할 수 있는 카테고리에서만 쓸 수 있습니다. 일정은 option.schedule 에 담습니다.
조합형 옵션인 경우 옵션별 재고수량(Combinations.stockQuantity)을 입력해야 하며, 본상품 재고수량(OptionRequest.stockQuantity)은 빈 값으로 요청되어야 합니다.
일정형 옵션은 일정별 재고(SchedulePrice.availableQuantity)를 입력해야 하며, 본상품 재고수량(OptionRequest.stockQuantity)은 입력되어도 무시됩니다.
조합형·일정형 옵션이 아닌 경우에는 본상품 재고수량(OptionRequest.stockQuantity)을 입력해 주세요.
일정형 옵션 등록 및 수정 시 주의사항
- 일반 상품을 일정형으로 바꿀 때는 option.schedule(일정 설정과 prices 전체)이 필수입니다.
- 이미 일정형인 상품은 option.schedule 이 없으면 일정을 바꾸지 않고 옵션 설정만 저장합니다. schedule 이 있으면 부분 수정이 아니라 전체 저장입니다. 보낸 prices 가 그 상품의 일정 전체가 되며, 포함되지 않은 기존 일정은 삭제됩니다. 특정 날짜만 판매를 멈출 때는 지우지 말고 usable=false 로 보내 주세요. 이미 발생한 주문에는 영향이 없습니다.
- schedule 에서 prices 를 생략하면 일정가격은 그대로 두고 일정 설정(dateSelectionType 등)만 저장합니다. prices 를 빈 배열로 보내면 오류(scheduleOption.empty)가 납니다.
- 기존 일정과는 다음 순서로 맞춰 저장합니다. scheduleOptionId 가 있으면 그 일정을 수정합니다(추가 옵션값은 바꿀 수 있고 날짜는 바꿀 수 없음). scheduleOptionId 가 없으면 날짜·추가 옵션값이 같은 기존 일정을 수정하고, 같은 일정이 없으면 새로 등록합니다.
- baseModifiedAt(선택)은 조회 이후 일정가격이 바뀌었는지 확인하는 기준 시각입니다. 옵션 조회 응답의 schedule.baseModifiedAt 값을 그대로 보내 주세요. 조회 이후 다른 수정이나 주문 재고 차감, 자정 자동 사용안함 등으로 일정가격이 바뀌었다면 저장이 거절되므로(scheduleOption.baseModifiedAt.stale), 다시 조회해 변경 내용을 반영한 뒤 요청해 주세요. 생략하면 조회 이후 주문으로 줄어든 재고를 조회 당시 수량으로 덮어쓸 수 있으므로, 주문이 들어오는 상품은 함께 보내 주세요.
- 저장 결과 판매 가능한 일정(사용여부가 true 이고 재고가 1 이상)이 하나도 없으면 판매중인 상품은 품절로 바뀌고, 판매 가능한 일정이 다시 생기면 판매중으로 돌아갑니다. 판매중지 등 판매자·관리자가 정한 상태는 바뀌지 않습니다. 날짜가 지난 일정의 자동 사용안함 처리와 그에 따른 품절은 판매상태변경 API 문서를 참고해 주세요.
- 지난 날짜의 일정은 조회 응답의 usable 값을 그대로 보내 주세요. usable 을 생략하면 true 로 처리되어, 사용안함인 지난 일정은 오류(scheduleOption.usable.pastReactivation)가 납니다.
- 일정형 상품을 다른 옵션 타입으로 바꾸면 등록된 일정가격과 일정 설정이 모두 초기화 됩니다. (이미 발생한 주문에는 영향없음)
- 일정 필드와 제약사항은 OptionRequest 의 Schedule·SchedulePrice 를, 오류는 아래 '일정형 옵션 오류'를 참고해 주세요.
요청
<Content-type: application/x-www-form-urlencoded 요청>
POST /v1/store/product/option/update?productId={}&option={} HTTP/1.1
Content-type: application/x-www-form-urlencoded;charset=utf-8
| 키 | 타입 | 필수여부 | 설명 |
|---|---|---|---|
| productId | Long | 필수 | 상품번호 |
| option | OptionRequest json object기반 String | 필수 | 옵션 정보 |
<Content-type: application/json 요청>
POST /v1/store/product/option/update?productId={} HTTP/1.1
Content-type: application/json
$RequestBody
| RequestBody |
|---|
| OptionRequest json object |
아래 샘플은 option 파라미터의 값이자 JSON 요청 본문(OptionRequest)입니다.
< option json 샘플>
- 옵션 없는 상품으로 등록 / 수정
{
"stockQuantity":10,
"option":{
"type":"NONE"
}
}
- 독립형 상품으로 등록 / 수정
{
"stockQuantity":10,
"option":{
"type":"SIMPLE",
"simpleSortType":"CREATE",
"simples":[
{
"id":1,
"name":"string",
"value":"string",
"usable":true
}
]
}
}
- 조합형 상품으로 등록 / 수정
{
"option":{
"type":"COMBINATION",
"combinationSortType":"CREATE",
"combinationAttributes":[
{
"id":1,
"name":"사이즈",
"value":"M"
},
{
"id":2,
"name":"컬러",
"value":"RED"
}
],
"combinations":[
{
"id":1,
"name":[
{
"key":"사이즈",
"value":"M"
},
{
"key":"컬러",
"value":"RED"
}
],
"usable":true,
"price":2000,
"stockQuantity":10,
"managedCode":"string"
}
],
"optionDisplay": {
"useInstantOrder": true,
"instantOrderTemplateType": "TYPE_1"
}
}
}
- 작성형 상품으로 등록 / 수정
{
"stockQuantity":10,
"option":{
"type":"CUSTOM",
"customs":[
{
"id":1,
"name":"길이를 입력해 주세요.",
"usable":true
}
]
}
}
- 일정형 옵션 등록(일반 상품을 일정형으로 바꿀 때)
{
"option": {
"type": "SCHEDULE",
"schedule": {
"dateSelectionType": "RANGE",
"prices": [
{
"scheduleDate": "20261105000000",
"axes": [
{
"key": "객실타입",
"value": "스탠다드"
}
],
"price": 0,
"availableQuantity": 5,
"usable": true
},
{
"scheduleDate": "20261105000000",
"axes": [
{
"key": "객실타입",
"value": "디럭스"
}
],
"price": 30000,
"availableQuantity": 3,
"usable": true,
"managedCode": "DLX"
},
{
"scheduleDate": "20261106000000",
"axes": [
{
"key": "객실타입",
"value": "스탠다드"
}
],
"price": 20000,
"availableQuantity": 5,
"usable": true
}
]
}
}
}
- 일정형 옵션 수정(이미 일정형인 상품)
{
"option": {
"type": "SCHEDULE",
"schedule": {
"dateSelectionType": "RANGE",
"baseModifiedAt": "20261002101530123456",
"prices": [
{
"scheduleOptionId": 17331,
"scheduleDate": "20261105000000",
"axes": [
{
"key": "객실타입",
"value": "스탠다드"
}
],
"price": 0,
"availableQuantity": 5,
"usable": true
},
{
"scheduleOptionId": 17332,
"scheduleDate": "20261105000000",
"axes": [
{
"key": "객실타입",
"value": "디럭스"
}
],
"price": 30000,
"availableQuantity": 3,
"usable": true,
"managedCode": "DLX"
},
{
"scheduleDate": "20261106000000",
"axes": [
{
"key": "객실타입",
"value": "스탠다드"
}
],
"price": 20000,
"availableQuantity": 5,
"usable": true
}
]
}
}
}
샘플의 날짜와 번호는 예시입니다. 새로 등록하는 일정의 날짜는 오늘 이후(1년 이내)로 바꿔 사용해 주세요.
- 일정 설정만 수정(일정가격은 그대로)
{
"option": {
"type": "SCHEDULE",
"schedule": {
"dateSelectionType": "SINGLE",
"dateInputType": "PERIOD"
}
}
}
응답
<응답 바디>
| 필드명 | 타입 | 필수여부 | 설명 |
|---|---|---|---|
| productId | Long | 필수 | 상품번호 |
| option | Option | 필수 | 옵션 정보 목록 |
<응답 바디 샘플>
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
{
"productId":1,
"option":{
"type":"COMBINATION",
"combinations":[
{
"id":1,
"name":[
{
"key":"사이즈",
"value":"M"
},
{
"key":"컬러",
"value":"RED"
}
],
"price":"300",
"stockQuantity":50,
"managedCode":"SY",
"usable":true
}
],
"combinationAttributes":[
{
"id":1,
"name":"사이즈",
"value":"M"
},
{
"id":2,
"name":"컬러",
"value":"RED"
}
],
"optionDisplay": {
"useInstantOrder": true,
"instantOrderTemplateType": "TYPE_1"
}
}
}
일정형 상품이면 응답의 option 에 옵션 조회와 같은 형식의 schedule 이 포함됩니다.
일정형 옵션 오류
검증에 실패하면 400 응답의 validation 에 필드별 문구(필드와 무관한 사유는 _global)가, reason_code 에 그중 대표 사유 하나의 코드가 담깁니다. 오류가 여러 개면 reason_code 는 validation 의 첫 항목과 다를 수 있으니, 전체 사유는 validation 으로 확인해 주세요.
일정 항목 오류는 validation 에 option.schedule.prices[0].price 처럼 option.schedule.prices 목록의 위치로 표시됩니다.
| reason_code | 상황 |
|---|---|
| scheduleOption.inline.requiredOnTransition | 일정형으로 바꾸면서 option.schedule 이 없음 |
| scheduleOption.inline.notScheduleProduct | 일정형이 아닌 옵션 타입에 option.schedule 을 넣음 |
| scheduleConfig.dateSelectionType.rangeRequiresAccommodation | 숙소상품 카테고리가 아닌 상품에 RANGE 설정 |
| scheduleOption.inline.concurrentModification | 저장 중 같은 상품이 동시에 수정됨 — 다시 조회한 뒤 요청 |
| scheduleOption.empty | option.schedule.prices 가 빈 배열이거나, 일정형으로 바꾸면서 prices 가 없음 |
| scheduleOption.count.over | 일정가격이 3,000개를 넘음 |
| scheduleOption.row.null | prices 에 빈 항목(null)이 있음 |
| scheduleOption.scheduleDate.blank | scheduleDate 누락 |
| scheduleOption.scheduleDate.invalid | scheduleDate 가 yyyyMMddHHmmss 형식이 아니거나 달력에 없는 날짜(예: 20261131000000) |
| scheduleOption.scheduleDate.past | 새 일정의 날짜가 오늘보다 이전임 |
| scheduleOption.scheduleDate.over | 새 일정의 날짜가 오늘부터 1년 뒤 같은 날보다 늦음 |
| scheduleOption.scheduleDate.beforeSaleStart | 판매기간을 설정한 상품에서 새 일정의 날짜가 판매 시작일보다 앞섬 |
| scheduleOption.axes.over | 한 일정의 추가 옵션이 3개를 넘음 |
| scheduleOption.axes.invalid | 추가 옵션의 key 또는 value 가 비어 있음 |
| scheduleOption.axes.keyOversize | 추가 옵션명(key)이 25자를 넘음 |
| scheduleOption.axes.valueOversize | 추가 옵션값(value)이 25자를 넘음 |
| scheduleOption.axes.duplicateKey | 한 일정 안에서 추가 옵션명이 중복됨 |
| scheduleOption.axes.mixed | 날짜만 있는 일정과 추가 옵션이 있는 일정이 섞임 |
| scheduleOption.axes.schemaMismatch | 일정마다 추가 옵션명 구성이 다름 |
| scheduleOption.duplicate | 같은 날짜·추가 옵션 조합이 중복됨 |
| scheduleOption.price.blank | price 누락 |
| scheduleOption.price.range | 옵션가가 판매가 기준 허용 범위를 벗어남(OptionRequest 의 SchedulePrice 참고) |
| option.negative | 마이너스 옵션가 일정에서 판매가 + 옵션가 - 할인 금액이 100원 미만 |
| scheduleOption.quantity.invalid | availableQuantity 가 없거나 0보다 작음 |
| quantity.max | availableQuantity 가 99,999,999 를 넘음 |
| scheduleOption.managedCode.oversize | managedCode 가 20자를 넘음 |
| option.no_free | 사용여부가 true 이면서 옵션가가 0원인 일정이 없음 |
| scheduleOption.id.notFound | 이 상품에 없는 scheduleOptionId (상품 등록·일정형 전환 때 scheduleOptionId 를 넣은 경우 포함) |
| scheduleOption.id.dateImmutable | scheduleOptionId 로 지정한 일정의 날짜를 바꿈 |
| scheduleOption.id.duplicate | 같은 scheduleOptionId 를 두 번 보냄 |
| scheduleOption.usable.pastReactivation | 지난 날짜이면서 사용안함인 일정을 usable=true 로 보내거나 usable 을 생략함 |
| scheduleOption.baseModifiedAt.invalid | baseModifiedAt 이 yyyyMMddHHmmssSSSSSS 형식이 아님 |
| scheduleOption.baseModifiedAt.stale | 조회 이후 일정가격이 바뀜(주문 재고 차감 포함) — 옵션 조회로 다시 조회해 반영한 뒤 요청 |
| scheduleOption.baseModifiedAt.mismatch | baseModifiedAt 이 서버의 마지막 변경 시각보다 늦음(조회 응답이 아닌 값을 보냄) |
<오류 응답 샘플>
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
{
"error_code": -10001,
"error_message": "유효하지 않은 요청입니다.",
"reason_code": "scheduleOption.baseModifiedAt.stale",
"validation": {
"_global": [
"조회 이후 다른 변경(주문 차감 포함)이 있어 저장할 수 없습니다. 새로고침 후 다시 시도해주세요."
]
}
}