쿠폰
주문 쿠폰·상품 쿠폰 만들기, 코드 입력·셀러 지급·다운로드·회원가입 지급, 주문서 적용, 부분 취소의 환불
쿠폰을 만들어 구매자에게 코드를 알리거나, 직접 지급하거나, 스토어프론트에서 받게 하거나, 회원가입 때 자동으로 지급합니다. 구매자는 주문서에서 쿠폰을 고르고, 결제 금액에서 할인됩니다. 취소·반품의 환불 금액은 쿠폰 할인을 뺀 실제 결제 금액을 기준으로 나눕니다.
준비
- 쿠폰 보기: 소유자·관리자·스태프 또는
promotion:r - 쿠폰 만들기·수정·지급·중지: 소유자·관리자 또는
promotion:rw - 에이전트 토큰의 쿠폰 만들기·규칙 수정·지급·재개는 승인을 거칩니다
1. 쿠폰 종류
종류 (kind) | 할인 대상 | 한 주문에 |
|---|---|---|
주문 쿠폰 (ORDER) | 대상 상품의 할인 반영 합계 | 1장 |
상품 쿠폰 (PRODUCT) | 주문 상품 한 줄 | 줄마다 1장 |
한 주문에 주문 쿠폰 1장과 상품 쿠폰(줄마다 1장)을 함께 쓸 수 있습니다. 상품 쿠폰을 먼저 빼고 남은 금액에 주문 쿠폰을 적용합니다.
혜택 (benefit) | 계산 |
|---|---|
정액 (AMOUNT) | value원. 대상 금액을 넘지 않습니다 |
정률 (RATE) | 대상 금액 × value%를 10원 단위로 내립니다. maxDiscountAmount가 있으면 그 금액까지입니다 |
예: 15% 쿠폰을 33,333원에 적용하면 4,990원(4,999.95원을 10원 단위로 내림)입니다.
2. 쿠폰 만들기
상점 플랫폼에서 **마케팅 › 쿠폰 › [쿠폰 만들기]**로 이동합니다.
- 기본 정보: 쿠폰 이름(구매자에게 보입니다), 설명, 종류
- 혜택: 정액·정률과 금액. 화면 위에 예시 금액이 보입니다
- 조건: 최소 주문 금액(대상 상품 합계, 배송비 제외), 즉시할인 상품에도 적용할지
- 대상: 상품·카테고리를 고르거나 비워서 모든 상품. 제외 상품은 대상에 들어도 할인하지 않습니다
- 발급 방식과 기간·한도를 정하고 **[쿠폰 만들기]**를 누릅니다
API: POST /v1/coupons (Idempotency-Key 권장)
발급 방식 (issueMethod) | 구매자가 쓰는 방법 | 한도 |
|---|---|---|
코드 입력 (CODE) | 주문서에서 코드(영문·숫자·-·_ 6~30자, 대소문자 구분 없음)를 입력. 기본은 회원 전용이고, 비회원에게 열려면 conditions.memberOnly를 false로 둡니다 | 총 사용 한도, 회원 전용일 때 1인 사용 한도 |
셀러 지급 (MANUAL) | 셀러가 지급한 내 쿠폰에서 고름. 회원 전용 | 총 발급 한도, 1인 발급 한도, 총 사용 한도 |
다운로드 (DOWNLOAD) | 스토어프론트의 쿠폰 목록·상품 상세에서 받은 뒤 내 쿠폰에서 고름. 회원 전용 | 총 발급 한도, 1인 발급 한도(기본 1장), 총 사용 한도 |
회원가입 (SIGNUP) | 회원가입하면 1장이 자동으로 들어옴. 회원 전용 | 총 발급 한도, 총 사용 한도. 1인 1장 고정 |
코드 입력이 아닌 방식에는 code·perMemberUseLimit을 넣지 않습니다(400 VALIDATION_FAILED). 발급 한 장이 한 번 쓰입니다.
- 사용 기간은
startsAt부터endsAt전까지입니다. 상점 플랫폼에서 종료일을 10월 31일로 고르면 11월 1일 0시(한국 시간)부터 쓸 수 없습니다. - 셀러 지급·다운로드·회원가입 쿠폰에
validDaysAfterIssue를 두면 받은 날부터 그 일수 동안만 씁니다(쿠폰 종료일이 먼저 오면 종료일까지). - 다운로드·회원가입 쿠폰은 사용 기간 안에만 발급됩니다. 시작일 전이거나 종료일이 지났거나 총 발급 한도가 찼으면 더 발급하지 않습니다.
3. 셀러 지급
쿠폰 상세의 **[구매자에게 지급]**에서 구매자를 찾아 고릅니다. 한 번에 1,000명까지입니다.
API: POST /v1/coupons/{couponId}/issues 본문 { "customerIds": ["…"] }
- 한도에 걸린 구매자는 응답의
failed에 담기고 나머지는 지급됩니다. - 같은
Idempotency-Key로 다시 보내면 첫 결과를 돌려줍니다. - 쓰지 않은 쿠폰은 발급 내역의 **[회수]**로 거둡니다(
POST /v1/coupon-issues/{issueId}/revoke). 결제 중이거나 쓴 쿠폰은 회수하지 않습니다. - 구매자별 보유 쿠폰은
GET /v1/customers/{customerId}/coupons입니다(customer:r).
4. 다운로드 쿠폰 (스토어프론트에서 받기)
발급 방식을 다운로드로 만든 쿠폰은 구매자가 스토어프론트에서 직접 받습니다. 받은 쿠폰은 내 쿠폰과 주문서의 쓸 수 있는 쿠폰에 그대로 뜹니다.
| 단계 | API | SDK |
|---|---|---|
| 받을 수 있는 쿠폰 목록 | GET /storefront/v1/coupons (productId·page·size) | catalog.listCoupons({ productId }) |
| 쿠폰 받기 (회원) | POST /storefront/v1/coupons/{couponId}/download | me.downloadCoupon(couponId) |
// 상품 상세 — 이 상품에 쓸 수 있는 쿠폰
const { contents } = await sdk.catalog.listCoupons({ productId });
for (const coupon of contents) {
if (coupon.loginRequired) {
// 로그인 후 받을 수 있습니다
} else if (coupon.downloadable) {
// [쿠폰 받기] 버튼
} else if (coupon.downloaded) {
// 받은 쿠폰
}
}
const mine = await sdk.me.downloadCoupon(couponId); // 내 쿠폰 한 장(issueId)- 목록에는 사용 중이고, 기간 안이고, 총 발급 한도가 남은 다운로드 쿠폰만 나옵니다. 최근 만든 순입니다.
productId를 주면 그 상품이 대상(대상 상품·카테고리, 제외 목록 반영)인 쿠폰만 나옵니다. 최소 주문 금액과 즉시할인 중복 조건은 주문서에서 판단합니다.- 회원 토큰과 함께 부르면 항목마다
downloaded(이미 받음)·downloadable(더 받을 수 있음)이 실립니다. 토큰이 없으면 둘 다null이고loginRequired가true입니다. - 받은 쿠폰의 유효 기간은 받은 시각부터입니다. 받은 쿠폰을 쓰거나 기간이 지나도 1인 발급 한도에 셉니다. 셀러가 회수한 쿠폰은 세지 않습니다.
- 쿠폰 받기는 회원당 분당 30회까지입니다(
429 TOO_MANY_REQUESTS).
| 쿠폰 받기 오류 | 뜻 |
|---|---|
401 UNAUTHORIZED | 로그인이 필요합니다 |
404 COUPON_NOT_FOUND | 없거나, 중지·종료됐거나, 다운로드 쿠폰이 아님 |
409 COUPON_ALREADY_DOWNLOADED | 1인 발급 한도만큼 이미 받음 |
409 COUPON_SOLD_OUT | 총 발급 한도가 소진됨 |
409 COUPON_NOT_STARTED · COUPON_EXPIRED | 사용 시작 전 · 종료일 지남 |
409 COUPONS_UNAVAILABLE | 지금은 쿠폰을 쓸 수 없음. 이때 목록은 비어 있습니다 |
5. 회원가입 쿠폰
발급 방식을 회원가입으로 만든 쿠폰은 구매자가 회원가입할 때 1장씩 자동으로 지급됩니다. 이메일 가입과 소셜 로그인 첫 가입이 모두 받습니다.
- 가입 시점에 사용 중이고, 기간 안이고, 총 발급 한도가 남은 회원가입 쿠폰을 모두 지급합니다. 한도가 찼으면 건너뛰고 가입은 그대로 됩니다.
- 이미 가입한 구매자의 다음 로그인에는 다시 지급하지 않습니다.
- 회원가입 쿠폰은 스토어프론트 쿠폰 목록에 나오지 않고 받기·셀러 지급도 되지 않습니다.
- 내 쿠폰(
GET /storefront/v1/me/coupons)의source가SIGNUP이면 회원가입으로 받은 쿠폰입니다(DOWNLOAD는 직접 받음,MANUAL은 셀러 지급).
6. 수정·중지·종료
발급이나 사용이 한 번이라도 시작되면 쿠폰이 잠깁니다(locked: true). 이미 받은 구매자와 다른 규칙이 생기지 않게 하기 위해서입니다.
| 항목 | 잠기기 전 | 잠긴 뒤 |
|---|---|---|
| 이름·설명 | 수정 | 수정 |
| 혜택·조건·대상·사용 시작일 | 수정 | 409 COUPON_LOCKED |
| 종료일 | 수정 | 늦추기만 |
| 한도 | 수정 | 늘리기만 |
| 종류·발급 방식 | 바꿀 수 없음 | 바꿀 수 없음 |
API: PATCH /v1/coupons/{couponId} (준 항목만 바뀜)
| 동작 | API | 결과 |
|---|---|---|
| 중지 | POST /v1/coupons/{couponId}/pause | 새 결제에서 쓸 수 없습니다. 결제 중인 예약은 그대로 끝납니다 |
| 재개 | POST /v1/coupons/{couponId}/resume | 다시 쓸 수 있습니다 |
| 종료 | POST /v1/coupons/{couponId}/end | 되돌릴 수 없습니다. 지급한 쿠폰도 못 쓰고, 전량 취소돼도 복원하지 않습니다 |
7. 주문서에서 적용 (스토어프론트)
쿠폰은 { issueId }(내 쿠폰) 또는 { code }로 보냅니다. 상품 쿠폰은 optionId로 적용할 주문 상품을 고를 수 있고, 생략하면 아직 상품 쿠폰이 없는 대상 줄 중 할인이 가장 큰 줄에 적용합니다.
| 단계 | API |
|---|---|
| 내 쿠폰 목록 | GET /storefront/v1/me/coupons (status: available·used·expired) |
| 이 주문서에 쓸 수 있는 쿠폰 | GET /storefront/v1/checkout/{checkoutId}/coupons (회원) |
| 금액 미리보기 | POST /storefront/v1/checkout/{checkoutId}/pricing — 주문서를 바꾸지 않고 예약하지 않습니다 |
| 결제 시작 | POST /storefront/v1/checkout/{checkoutId}/payment의 coupons — 금액을 확정하고 쿠폰을 예약합니다 |
const preview = await sdk.checkout.pricing(checkoutId, {
coupons: [{ code: "FALL-10" }],
zipCode: "63000",
});
if (!preview.payable) {
// preview.coupons[].rejectReason으로 적용하지 못한 이유를 보여 줍니다
}- 결제를 시작하면 쿠폰이 그 결제에 예약됩니다. 결제가 승인되면 사용으로 확정되고, 결제가 실패로 끝나거나 결제 시간(10분)이 지나면 예약이 풀립니다.
- 결제창을 닫거나 카드가 거절돼도 결제는 결제 시간 동안 살아 있고 쿠폰도 예약된 채입니다. 다시 결제할 때는 새로 결제를 시작하지 말고
payments.retry(paymentId, { option })로 같은 결제를 이어 갑니다. 새로 시작하면 앞 결제의 예약이 1인 사용 한도·총 사용 한도에 세어져409 COUPON_LIMIT_REACHED·COUPON_EXHAUSTED가 날 수 있습니다. - 예약된 발급 쿠폰으로 다른 결제를 시작하면
409 COUPON_IN_USE이고error.details.reservedUntil이 풀리는 시각입니다. - 쿠폰을 적용한 뒤 결제 금액이 100원 미만이면
400 PAYMENT_AMOUNT_TOO_LOW입니다. - 코드 입력은 구매자당 분당 10회까지입니다(
429 TOO_MANY_REQUESTS).
적용하지 못한 이유 (rejectReason) | 뜻 |
|---|---|
MIN_ORDER_AMOUNT | 최소 주문 금액 미달 |
NO_ELIGIBLE_ITEMS · LINE_NOT_ELIGIBLE | 대상 상품이 주문에 없음 · 고른 줄이 대상이 아님 |
NO_DISCOUNT | 할인할 금액이 없음 |
MEMBER_ONLY | 회원 전용 쿠폰 |
NOT_STARTED · EXPIRED | 사용 기간 전 · 지남 |
DUPLICATE_COUPON · STACK_LIMIT | 같은 쿠폰을 두 번 넣음 · 같은 종류의 쿠폰이 이미 적용됨(주문 쿠폰은 주문당 1장, 상품 쿠폰은 줄마다 1장) |
IN_USE · LIMIT_REACHED · EXHAUSTED · INACTIVE | 다른 결제에서 쓰는 중 · 1인 사용 한도 · 총 사용 한도 · 중지된 쿠폰 |
값은 늘 수 있으니 모르는 값은 "쓸 수 없는 쿠폰"으로 보여 줍니다.
| 결제 시작 오류 | 뜻 |
|---|---|
400 COUPON_NOT_APPLICABLE | 적용하지 못한 쿠폰이 있음(error.details.coupons). 그 쿠폰을 빼고 다시 시작합니다 |
404 COUPON_NOT_FOUND | 없는 코드, 중지·종료된 코드, 내 쿠폰이 아님, 이미 쓰거나 회수된 쿠폰 |
409 COUPON_LIMIT_REACHED · COUPON_EXHAUSTED | 1인 사용 한도 · 총 사용 한도. 진행 중인 결제의 예약도 셉니다 |
409 COUPON_CHANGED | 금액을 계산한 뒤 쿠폰이 바뀌거나 중지됨. 미리보기부터 다시 합니다 |
409 COUPONS_UNAVAILABLE | 지금은 쿠폰을 쓸 수 없음. 쿠폰 없이 결제할 수 있습니다 |
8. 주문에 남는 값
payment.couponDiscountAmount는 쿠폰 할인 합계이고payment.discounts에 쿠폰마다 이름·할인액이 남습니다.payment.totalAmount=productAmount + deliveryFee − couponDiscountAmount − deliveryDiscountAmount입니다.- 주문 상품마다
couponDiscountAmount가 있습니다. 주문 쿠폰은 대상 줄에 금액 비율로 나눠 담기고, 합은 쿠폰 할인액과 같습니다. 그 줄의 실제 결제 금액은totalPrice − couponDiscountAmount입니다. - 쿠폰 규칙은 주문 시점 값으로 고정됩니다. 나중에 쿠폰을 고쳐도 이미 받은 주문의 환불 계산은 바뀌지 않습니다.
9. 취소·반품의 환불
환불할 상품 금액은 그 주문 상품의 실제 결제 금액을 수량 비율로 나눈 값입니다. 쿠폰 할인을 받은 만큼 적게 환불됩니다.
- 전량 취소·전량 반품이면 쓴 쿠폰을 돌려줍니다. 셀러 지급·다운로드·회원가입 쿠폰은 다시 사용 가능, 코드 쿠폰은 사용 수가 줄어듭니다. 사용 기간이 지났거나 셀러가 종료한 쿠폰은 돌려주지 않습니다.
- 부분 취소로는 쿠폰을 돌려주지 않습니다.
- 부분 취소로 남은 주문 상품이 쿠폰 조건(최소 주문 금액 등)을 잃으면, 환불 정책
couponShortfallCharge(기본true)에 따라 남은 상품이 받던 쿠폰 할인을 환불액에서 뺍니다(couponChargeAmount). 판매자 귀책(판매자 취소, 불량·오배송 반품)이면 빼지 않습니다. 나중에 남은 상품까지 취소되면 앞에서 뺀 금액을 돌려줍니다(couponChargeRefundAmount). couponShortfallCharge는 상점 단위입니다. 설정 › 상점 정보 › 환불 정책이나PATCH /v1/store의refundPolicy로 바꿉니다.- 교환은 금액이 움직이지 않아 쿠폰도 그대로입니다.
환불 금액 = 실제 결제 금액의 수량 비율 + 배송비 환불 − 배송비 차감 − 쿠폰 차감 + 쿠폰 차감 되돌림 − 추가 차감입니다.
클레임 처리의 표와 같은 순서로 계산합니다.
자주 막히는 문제
| 증상 | 원인·해결 |
|---|---|
쿠폰 규칙을 못 바꿉니다(409 COUPON_LOCKED) | 발급·사용이 시작된 쿠폰입니다. 새 쿠폰을 만들고 옛 쿠폰은 중지합니다 |
| 지급했는데 구매자가 못 씁니다 | 비회원이거나, 유효 기간이 지났거나, 쿠폰이 중지됐습니다. 내 쿠폰의 status를 봅니다 |
| 결제창을 닫았는데 쿠폰을 다시 못 씁니다 | 앞 결제가 쿠폰을 예약하고 있습니다. payments.retry로 같은 결제를 이어 가거나 결제 시간(10분)이 지난 뒤 씁니다. 발급 쿠폰의 409 COUPON_IN_USE에는 풀리는 시각(error.details.reservedUntil)이 옵니다 |