입점 신청하기내 파트너센터 바로가기
개발가이드

클레임·문의 처리하기

취소·반품·교환의 모든 단계와 예외 상황, 그리고 상품 문의 답변까지 다뤄요.

클레임은 취소(cancel)·반품(return)·교환(exchange) 세 종류이고 상태 그래프가 각각 달라요. 이 문서는 연동 중에 마주칠 수 있는 케이스를 단계별로 모아 정리했어요.

지금 무엇을 할 수 있는지는 available_actions가 알려줘요
클레임 조회 응답의 available_actions 배열이 지금 호출할 수 있는 처리를 알려줘요. 서버가 신청 종류와 현재 상태를 보고 계산한 값이니, 상태 문자열로 직접 추론하지 말고 이 배열을 그대로 쓰세요.
이 배열은 "지금 새로 실행할 수 있는 처리"를 뜻해요. 빈 배열은 새로 실행할 처리가 없다는 뜻이지 모든 호출이 거절된다는 뜻은 아니에요 — 이미 수행된 처리를 같은 값으로 재전송하는 것은 배열이 비어 있어도 200이에요(재시도 판정 참고).

케이스 빠른 찾기

클레임 수집하기

GET /open/v1/claims로 수집해요(claims:read 스코프). 페이지 넘김은 주문과 같은 커서 방식이에요.

파라미터용도
typecancel·return·exchange 중 하나로 종류를 걸러요
status진행 상태가 정확히 그 값인 건만 가져와요. 처리 대기 건만 뽑으려면 requested, 검수 대기 건만 뽑으려면 collected
requested_at_gte / requested_at_lte신청 시각 기준 조회. "어제 접수된 반품" 같은 업무 단위 집계에 써요
updated_at_gte / updated_at_lte변경 시각 기준 조회. 정기 증분 수집의 기준이에요

증분 수집 주기·겹침 구간은 주문과 동일해요 — 주문 연동하기의 증분 수집 절을 참고해 주세요.

취소 (cancel)

취소 클레임 상태 그래프 — requested에서 approve 또는 reject로 갈리고, 승인 시 refund_processing을 거쳐 completed로 종결되는 흐름
상태설명available_actions
requested취소 신청 접수approve(승인), reject(거부)
그 외 전부없음

취소는 수거·검수 단계가 없어요. 승인(approve)하면 그 자리에서 환불이 걸리고 refund_processingcompleted로 이어져요. 그 구간은 뷰리티가 진행해요. 환불이 곧바로 끝나면 approve 응답의 status가 이미 completed일 수도 있어요.

세 종류 중 승인 시점에 환불이 걸리는 건 취소뿐이에요. 반품·교환은 환불 진행의 타입별 표를 봐 주세요.

취소를 신청할 수 있는 주문 상품 상태는 paid·preparing이에요. 이미 발송된 건은 취소가 아니라 반품으로 들어와요.

반품 (return)

반품 클레임 상태 그래프 — requested에서 승인 후 collecting·collected·inspecting을 거쳐 refund_processing과 completed로 이어지는 흐름
상태설명available_actions엔드포인트
requested반품 신청 접수approve(승인), reject(거부)/approve · /reject
approved승인됨 — 수거 준비pickup(수거 송장 등록)/pickup
collecting수거 중collect-done(수거 완료 처리)/collect-done
collected수거 완료 — 검수 대기inspect(검수 결과 등록)/inspect
inspecting검수 중reject(검수 불합격 거부)/reject
그 외없음

반품·교환은 배송완료(delivered)된 주문 상품에만 신청할 수 있어요.

교환 (exchange)

교환 클레임 상태 그래프 — requested에서 승인 후 수거·검수를 거쳐 reshipping과 completed로 이어지고, 각 단계에서 converted_to_return으로 빠질 수 있는 흐름
상태설명available_actions엔드포인트
requested교환 신청 접수approve(승인), reject(거부)/approve · /reject
approved승인됨 — 수거 준비pickup(수거 송장 등록)/pickup
collecting수거 중collect-done(수거 완료 처리)/collect-done
collected수거 완료 — 검수 대기inspect(검수 결과 등록)/inspect
inspecting검수 중reject(검수 불합격 거부)/reject
reshipping재출고 대기 — 검수 통과reship(재발송 송장 등록)/reship
그 외없음

교환은 requested부터 reshipping까지 어느 단계에서든 converted_to_return(반품 전환)으로 빠질 수 있어요. 아래 관측 전용 상태에서 자세히 다뤄요.

처리 호출 순서와 요청 본문

반품 처리 호출 순서 — 클레임 수집 후 approve, pickup, collect-done, inspect를 차례로 호출하고, inspect 응답이 환불 즉시 완료면 completed, 진행 중이면 refund_processing으로 갈리며 완료는 조회로 확인하는 흐름

모든 처리 요청에 Idempotency-Key 헤더가 필수예요. 경로는 POST /open/v1/claims/{claim_no}/{액션} 형태이고, {액션}available_actions의 값과 그대로 같아요.

액션본문결과
approve없음취소는 refund_processing(환불 시작)으로, 반품·교환은 approved로 — 반품·교환은 승인만으로 환불도 수거도 시작되지 않아요. 수거를 시작하려면 이어서 pickup을 호출해야 해요
rejectmemo(거부 사유, 필수 · 1자 이상)rejected로 종결
pickupcarrier_name, tracking_no(수거 송장)collecting으로
collect-done없음collected
inspectresult(pass 또는 fail), memo아래 검수 분기 참고
reshipcarrier_name, tracking_no(재발송 송장)교환이 completed
  • 택배사명은 주문 발송과 같은 허용 5종 표기를 그대로 보내요: CJ대한통운 · 우체국택배 · 한진택배 · 롯데택배 · 로젠택배. 목록 밖 값은 422 SHIPMENT_CARRIER_NOT_ALLOWED예요.
  • reject를 이미 거부된 신청에 다시 호출하면 사유 문구가 달라도 성공으로 응답해요. 저장되는 사유는 처음 성공한 요청의 값이고 재시도로 덮어써지지 않아요.
  • inspectmemoresultfail일 때 필수예요. 비워 보내면 400으로 거절돼요.

관측 전용 상태

아래 상태에서는 연동사가 호출할 처리가 없어요(available_actions가 빈 배열이에요). 수집해서 status를 그대로 반영하기만 하면 돼요.

상태설명다음에 올 수 있는 상태연동사가 할 일
payment_pending고객이 부담할 금액(반품·교환 배송비, 교환 차액)이 환불액보다 커서 부족분을 먼저 결제해야 하는 상태예요. 반품·교환에만 있어요requested(결제 완료) · expired · withdrawn없음 — requested가 될 때까지 대기
withdrawn고객이 신청을 철회했어요. approved까지의 단계에서 발생할 수 있어요없음(종결)없음 — 진행 중이던 수거가 있으면 중단
expired부족분 결제 기한이 지나 신청이 자동으로 만료됐어요없음(종결)없음
converted_to_return교환이 반품으로 전환됐어요. 고객·운영자 요청으로만 발생하고 API로는 만들 수 없어요없음(종결)없음 — 별도의 반품 클레임이 새로 조회되므로 그쪽을 처리
refund_processing환불이 진행 중이에요. 가상계좌 건은 고객의 환불계좌 입력을 기다리는 구간도 여기 포함돼요completed없음 — 환불 진행 참고
completed환불·교환이 끝났어요없음(종결)없음 — 정산·재고 대사 반영
rejected거부로 종결됐어요. 명시적 거부(reject)와 검수 불합격 둘 다 이 상태예요없음(종결)없음 — 어느 쪽인지는 inspect_result로 구분
종결 상태에서 나가는 전이는 없어요
completed·rejected·withdrawn·converted_to_return·expired 다섯은 종결이에요. 새로 실행할 수 있는 처리가 없으니 available_actions도 빈 배열이에요.
다만 종결 상태라고 해서 모든 호출이 409는 아니에요과거에 실제로 수행된 처리를 같은 값으로 다시 보내면 종결 상태에서도 200이에요(재시도로 간주해 아무것도 바꾸지 않고 현재 상태를 돌려줘요). 판정 규칙은 재시도와 409 IDEMPOTENCY_UNRESOLVED가 정본이에요.

검수 분기

inspectresult에 따라 이후 흐름이 완전히 갈려요.

종류result전이이후
반품passcollectedinspectingrefund_processing 또는 completed이 시점에 환불이 걸려요. 환불이 그 자리에서 끝나면 inspect 응답의 status가 이미 completed이고, 아니면 refund_processing으로 왔다가 completed가 돼요
failcollectedinspectingrejected신청이 거부로 종결돼요. 회수한 상품을 고객에게 돌려보내는 절차는 파트너센터 안내를 따라 주세요
교환passcollectedinspectingreshipping재발송 송장을 /reship으로 등록하면 completed가 돼요. 돌려줄 차액이 있으면 이 시점에 차액 환불도 함께 걸려요(refund_processing은 거치지 않아요)
failcollectedinspectingrejected반품과 같아요. 고객이 선결제한 부족분이 있으면 함께 정리돼요
  • fail일 때 memo(불합격 사유)는 필수예요.
  • inspectcollected에서만 호출할 수 있어요. 이미 inspecting인 클레임에 다시 호출하면 409예요. inspecting에서 남는 선택지는 reject뿐이에요.
  • 검수를 생략하고 collected에서 곧바로 refund_processing으로 가는 경우도 있어요 — 수거완료 후 일정 기간 검수가 없으면 검수 통과로 간주해 뷰리티가 환불을 걸어요. API로 만들 수는 없지만 수집 중에 관측될 수 있으니 그 전이를 오류로 다루지 마세요.

환불 진행

별도의 환불 실행 호출은 없어요. 다만 환불이 시작되는 시점은 클레임 종류마다 달라요 — "승인하면 자동"은 취소에만 해당해요.

타입환불이 시작되는 시점비고
취소
(cancel)
approve 승인 시수거·검수가 없어요. 승인 즉시 refund_processing으로 넘어가요
반품
(return)
inspect 검수 통과 시(result=pass)approverequestedapproved까지만 옮겨요 — 환불도, 수거도 시작되지 않아요. 수거는 pickup(수거 송장 등록)을 호출해야 비로소 시작돼요(approvedcollecting). 승인 뒤 pickup을 빠뜨리면 클레임이 approved에 멈춰 있어요. 수거완료 뒤 일정 기간 검수가 없으면 뷰리티가 검수 통과로 간주해 환불을 걸기도 해요(collectedrefund_processing 직행)
교환
(exchange)
검수 통과 시 재출고(reshipping)로 가고, 환불은 고객에게 돌려줄 차액이 있을 때만 그 시점에 걸려요교환은 refund_processing을 거치지 않아요. 차액은 price_difference음수일 때 생겨요(양수는 고객이 추가 결제한 금액이라 환불이 없어요)

진행 상황은 클레임 상세의 status로 확인하면 돼요. 취소·반품은 refund_processingcompleted로 이어지고, 처리 응답을 받는 순간 이미 completed일 수도 있어요.

refund_processing이 예상보다 길어지는 경우가 있는데 대부분 아래 두 가지예요. 어느 쪽이든 연동사가 따로 할 일은 없어요.

  • 가상계좌·무통장 결제 건 — 고객이 환불받을 계좌를 입력해야 이체가 진행돼요. 입력은 고객이 앱에서 직접 해요.
  • PG 환불이 실패한 건 — 뷰리티가 확인해 수동으로 처리해요.

금액 필드 읽는 법

필드설명언제 채워지나
refund_amount고객에게 환불되는 금액(원). 배송비 부담분까지 반영한 최종 금액이에요금액이 확정된 뒤. 확정 전이거나 환불이 없는 신청이면 null
claim_shipping_fee이 신청에 부과된 반품·교환 배송비(원)산정 후. faultbuyer면 환불액에서 차감되고, seller면 0이에요
price_difference교환 시 발생한 상품 가격 차액(원). 양수면 고객이 추가 결제한 금액, 음수면 고객에게 돌려주는 금액이에요교환에서 산정 후. 취소·반품은 0
fault귀책 주체. buyer(고객 사유 — 배송비 고객 부담) 또는 seller(판매자 사유 — 배송비 판매자 부담)신청 사유에서 자동으로 결정돼요
reason_code신청 사유. change_of_mind(단순변심) · defective(하자·파손) · wrong_delivery(오배송) · out_of_stock(품절) · delayed_by_seller(발송지연) · etc신청 시점부터
청구액이 있는 신청은 결제가 끝나야 처리할 수 있어요
고객 부담액이 환불액보다 큰 반품·교환은 payment_pending으로 생성돼요. 고객이 부족분을 결제해 requested가 되기 전까지는 available_actions가 비어 있어요 — 승인·거부도 그때부터 가능해요.

동시 처리 충돌

같은 클레임을 파트너센터(사람)와 API(연동 시스템)가 동시에 처리할 수 있어요. 셀러가 파트너센터에서 먼저 승인해 버린 뒤 연동 시스템이 approve를 보내는 상황이 대표적이에요.

상황응답
같은 처리를 같은 값으로 보냄(이미 수행된 처리)200 — 아무것도 바꾸지 않고 현재 상태를 돌려줘요. 클레임이 이미 다음 단계로 갔거나 종결됐어도 마찬가지예요
같은 처리를 다른 값으로 보냄(다른 송장·다른 검수 결과)409 IDEMPOTENCY_UNRESOLVED
수행된 적 없는 처리를 보냄(건너뛴 단계·해당 없는 액션)409 IDEMPOTENCY_UNRESOLVED

누가 처리했는지는 판정에 쓰지 않아요. 파트너센터에서 사람이 대신 승인했어도 연동사가 원한 처리가 수행됐다면 200이에요.

권장 패턴
처리를 호출하기 직전에 클레임 상세를 다시 조회해 available_actions를 확인하고, 그 배열에 있는 액션만 보내세요. 수집 시점의 상태를 그대로 믿고 호출하면 그 사이 파트너센터에서 처리된 건이 409로 돌아와요.

재시도와 409 IDEMPOTENCY_UNRESOLVED

클레임 처리는 주문 전이와 달리 "한 방향으로 계속 전진"해요. 그래서 서버는 세 갈래로 판정해요.

  1. 지금 상태가 그 액션의 시작 상태그대로 실행해요.
  2. 이미 그 액션이 수행된 증거가 있음아무것도 바꾸지 않고 현재 상태로 200을 돌려줘요. 상태가 이미 종결이어도 마찬가지예요.
  3. 둘 다 아님409 IDEMPOTENCY_UNRESOLVED예요.

3번은 "지금 상태에서는 그 처리를 확정할 수 없다"는 뜻이에요. 서버가 추측으로 재실행하면 이중 환불이 될 수 있어 거절해요. 클레임 상세를 조회해 현재 상태와 available_actions를 확인한 뒤 판단해 주세요.

값이 있는 액션(pickup·inspect·reship)은 값까지 같아야 2번으로 접혀요. 같은 액션을 다른 송장번호·다른 검수 결과로 다시 보내면 409예요.

판정은 현재 상태가 아니라 "그 처리가 실제로 수행됐는가"를 봐요. 그래서 같은 종결 상태라도 어느 액션을 보냈는지에 따라 답이 갈려요.

현재 상태보낸 처리응답
completed(반품 환불 완료)approve200 — 그 클레임은 실제로 승인을 거쳤어요(2번)
pickup다른 송장으로409 — 저장된 값과 달라요(3번)
rejectedreject(사유가 달라도)200 — 명시적 거부를 거친 건이면 재시도로 접혀요. 저장되는 사유는 처음 성공한 값이에요
검수 불합격으로 rejected가 된 건에 reject409 — 그 건은 reject 처리를 거친 적이 없어요
withdrawn·expired(고객 철회·기한 만료)승인 전에 끝난 건에 approve409 — 그 건은 승인을 거친 적이 없어요

누가 처리했는지는 판정에 쓰지 않아요 — 파트너센터에서 사람이 대신 승인했어도 원하는 처리가 수행됐다면 200이에요.

교환 재발송 상품

교환이 승인되어 재출고 단계에 오면 새 주문 상품이 생성돼요(is_exchange: true). 이 상품은 일반 주문 상품과 처리 조건이 달라요.

시도결과
교환 신청이 reshipping이 되기 전에 발주확인409 EXCHANGE_ITEM_NOT_PREPARABLE
교환 신청이 reshipping이 아닐 때 송장 등록409 EXCHANGE_ITEM_NOT_RESHIPPING
교환 신청이 reshipping일 때 POST /open/v1/claims/{claim_no}/reship정상. 클레임이 completed가 되고 새 상품이 shipping으로 전환
재발송 송장은 클레임 API로
교환 재발송 송장은 주문 API가 아니라 클레임 API(/reship)로 등록해요. 주문 쪽 송장 등록으로는 교환 클레임이 종결되지 않아요.

reship 호출 후 409 EXCHANGE_ITEM_SHIP_FAILED를 받으면 재출고는 등록됐지만 새 상품의 출고 처리가 확정되지 않은 상태예요. 클레임 상세로 현재 상태를 확인한 뒤 다시 시도해 주세요.

부분 클레임과 라인 분할

한 클레임에 여러 상품이 담길 수 있고, 한 상품의 수량 일부만 신청될 수도 있어요. 클레임 응답의 items[]에는 신청 대상이 된 상품과 quantity(신청 수량)가 담겨요.

부분 클레임이 완결되면 원래 주문 상품 1줄이 「신청 수량」 줄과 「남은 수량」 줄로 나뉘어요. 신청 수량 쪽은 새 item_id를 가진 종료 상태 줄로 분리되고, 남은 수량은 원래 줄에 그대로 남아요. 주문 조회 응답에서도 두 줄이 각각 별도 항목으로 나타나요.

식별자성질용도
item_id (UUID)줄마다 하나씩, 그 줄에 고정연동사 시스템의 저장·갱신(upsert) 키. 처리 API의 item_ids에 넣는 값
item_code ({order_no}-{NN})어느 응답에 담겼느냐에 따라 가리키는 줄이 달라져요 — 주문 응답에서는 분할된 줄이 새 라인 번호를 부여받아 다음 순번의 새 item_code를 갖고, 원본 라인 번호를 그대로 유지하는 건 클레임 응답의 item_code이에요원본 주문 라인 단위로 묶어 대사할 때 쓰는 기준. 다만 다리로 삼을 값은 클레임 응답의 item_code예요
item_code는 줄의 고유 키가 아니에요
주문 조회 응답에서는 분리된 줄이 새 item_code(다음 순번)를 받아요. 반면 클레임 조회 응답의 item_code는 언제나 원본 라인 번호를 가리켜요(item_id는 분리된 줄을 가리키므로 두 값이 서로 다른 줄을 말할 수 있어요). 저장 키로는 item_id를, 원본 라인 묶음용으로는 item_code를 쓰세요.

권장 처리

  • 행 단위 저장·중복 판정은 item_id로 해요. 줄마다 고유하고 그 줄에 고정된 값이라 upsert 키로 안전해요.
  • 원본 라인 묶음·대사는 item_code로 해요. 라인 -01(수량 3) 중 1개가 취소되면 주문 응답의 -01 남은 수량 2 + item_code-01인 클레임의 신청 수량 1 = 원래 수량 3이에요. 주문 응답 안에서만 같은 코드끼리 더하면 분리된 줄이 새 코드를 받아 빠지니 주의해 주세요.
  • 처리 API 호출 직전에는 주문 상세를 다시 조회해 그 시점의 item_id를 써요. 오래된 item_id를 들고 있으면 404 ORDER_ITEM_NOT_FOUND가 나요.
  • 클레임이 진행 중인 라인은 주문 처리 API가 409 ORDER_ITEM_HAS_ACTIVE_CLAIM으로 거절해요. 주문 조회의 has_active_claim으로 미리 걸러내면 불필요한 호출을 줄일 수 있어요.

클레임 응답에서 채워지는 데이터

필드채워지는 시점
claim_no·order_no·type·status·requested_at·items[]항상
available_actions항상(호출 가능한 처리가 없으면 빈 배열)
fault·reason_code신청 시점부터
refund_amount·claim_shipping_fee·price_difference산정된 뒤. 산정 전이면 null
collect_carrier_name·collect_tracking_nopickup 등록 후
inspect_resultinspect 등록 후
reship_carrier_name·reship_tracking_noreship 등록 후
completed_at종결(completed) 시점

items[]의 각 항목에는 item_code·item_id·quantity·product_name·option_name이 담기고, 교환이면 고객이 원하는 옵션이 exchange_option_name에 담겨요. 클레임 응답에는 수취인·주소 같은 개인정보가 들어가지 않아요.

상품 문의(QnA) 처리

수집

GET /open/v1/qna로 자기 상품에 달린 문의를 수집해요(qna:read 스코프). 필터는 statusupdated_at_gte/updated_at_lte이고, 페이지 넘김은 주문·클레임과 같은 커서 방식이에요. 증분 수집 주기도 동일하게 잡으면 돼요.

비밀글로 등록된 문의도 자기 상품에 달린 것이라면 원문을 볼 수 있어요(파트너센터와 같은 기준). 다만 반출 기록이 문의 단위로 남으니 필요 이상으로 반복 수집하지 말아 주세요.

답변 등록

POST /open/v1/qna/{qna_id}/answer로 답변을 등록해요(qna:write 스코프, Idempotency-Key 필수). qna_id는 문의 조회 응답의 고유 ID(UUID)예요.

답변은 덮어쓸 수 없어요
이미 답변이 등록된 문의에 다른 내용을 보내면 409 QNA_ALREADY_ANSWERED예요. 같은 내용을 다시 보내는 건 재시도로 보고 성공 처리되지만, 내용 수정은 파트너센터에서만 할 수 있어요.