웹훅 이벤트
1. 이벤트 종류
이벤트 타입 | 의미 |
|---|---|
| 일반결제 완료 |
| 정기결제 완료 |
| 일반결제 취소 요청 |
| 정기결제 해지 신청 |
공통 규칙
공통 필드
id,type,version,occurredAt에 대한 설명은 연동 가이드를 확인해 주세요표의 타입은
string,number, boolean, object, array만 사용해요.options[]는 단일 옵션이어도 항상 배열로 반환돼요.id와 시각 값은 발송 시점마다 달라져요.시각 정보는 ISO-8601 KST(+09:00) 표준을 따라요.
금액은 long 타입, KRW예요.
enum값은 실제 payload 원문을 그대로 적고, 필요한 곳에는 한글 의미를 함께 풀어 적었어요.
팁
아래
payment.completed를 기준 스키마로 확인해 주세요.나머지 3개 이벤트는
payment.completed스키마와 거의 유사합니다. 다른 필드 몇가지만 확인해 주세요.JSON 예시는 테스트 발송 형식 기준으로 작성했어요.
2. payment.completed (일반결제 완료)
필드 명세
최상위
경로 | 타입 | 의미 |
|---|---|---|
| string | 그로블이 발급한 결제 식별자 |
buyer
경로 | 타입 | 의미 |
|---|---|---|
| string |
|
| string | 구매자 표시 이름 |
| string | 구매자 이메일 |
| string |
|
content
경로 | 타입 | 의미 |
|---|---|---|
| string | 상품 ID |
| string | 구매 시점 상품명 |
| string |
|
| string | 항상 |
options[]
경로 | 타입 | 의미 |
|---|---|---|
| string | 옵션 ID |
| string | 옵션명 |
| string | 옵션 설명 |
| number | 구매 수량 |
| number | 할인 전 단가 |
| number | 할인 후 단가 |
| object | 옵션 할인 블록 |
| string |
|
| number | 할인 값 |
| object | 타임딜 할인일 때만 포함 |
| string | 타임딜 라벨 |
| array | 추가 옵션 배열. 없으면 |
| string | 추가 옵션 ID |
| string | 추가 옵션명 |
| number | 추가 옵션 수량 |
| number | 추가 옵션 단가 |
| number | 옵션 소계 |
pricing
경로 | 타입 | 의미 |
|---|---|---|
| string | 항상 |
| number | 할인 전 총액 |
| number | 옵션/타임딜 할인 합계이며, 쿠폰 할인 미포함 |
| number | 실제 결제 금액 |
| number | 쿠폰 할인 금액 |
| object | 쿠폰 블록. 없으면 생략 |
| string | 쿠폰 코드 |
| string | 쿠폰 이름 |
| string | 쿠폰 할인 유형 |
| number | 쿠폰 할인 금액 |
paymentMethod
경로 | 타입 | 의미 |
|---|---|---|
| string |
|
| string | 카드사명 |
| string | 마스킹된 카드번호 |
shipping
content.type == GOODS일 때만 포함됩니다.
경로 | 타입 | 의미 |
|---|---|---|
| string | 주소 |
| string | 도로명/지번 주소 |
| string | 상세 주소 |
| string | 배송 요청 사항 |
questionAnswers[]
경로 | 타입 | 의미 |
|---|---|---|
| string | 질문 제목 |
| string | 질문 유형 |
| boolean | 응답 필수 여부 |
| string | 구매자 응답 |
| number | 질문 표시 순서 |
payment
경로 | 타입 | 의미 |
|---|---|---|
| string | 구매 완료 시각 |
JSON 예시 👀
{
"id": "evt_test_a1b2c3d4e5f60718293a4b5c",
"type": "payment.completed",
"version": "2026-04-21",
"occurredAt": "2026-04-20T14:22:11+09:00",
"data": {
"object": {
"merchantUid": "test_merchant_0001",
"buyer": {
"type": "MEMBER",
"displayName": "테스트 구매자",
"email": "test@buyer.example"
},
"content": {
"id": "test_content_0001",
"title": "테스트 상품",
"type": "DOCUMENT",
"paymentType": "ONE_TIME"
},
"options": [
{
"optionId": "test_option_0001",
"name": "기본 옵션",
"description": "테스트용 기본 옵션",
"quantity": 1,
"unitOriginalPrice": 10000,
"unitDiscountedPrice": 10000,
"additionalOptions": [],
"subtotal": 10000
}
],
"pricing": {
"currency": "KRW",
"originalAmount": 10000,
"optionDiscountAmount": 0,
"finalAmount": 10000,
"couponDiscountAmount": 0
},
"paymentMethod": {
"type": "CARD",
"cardName": "테스트카드",
"maskedCardNumber": "1234-****-****-5678"
},
"questionAnswers": [],
"payment": {
"purchasedAt": "2026-04-20T14:22:11+09:00"
}
}
}
}3. subscription_payment.completed (정기결제 완료)
payment.completed와 거의 같은 구조에 subscription 블록이 추가됩니다.
payment.completed 대비 차이
경로 | 타입 | 의미 |
|---|---|---|
| string | 회원 구독은 |
| string | 항상 |
| array | 항상 길이 1 |
| number | 항상 1 |
| array | 항상 |
| object |
|
| array |
|
subscription
경로 | 타입 | 의미 |
|---|---|---|
| string |
|
| number | 현재 결제 회차 |
| string |
|
| string | 항상 |
| string | 최초 정기결제 활성화 시각 |
| string | 마지막 정기결제 성공 시각 |
JSON 예시 👀
{
"id": "evt_test_b1c2d3e4f5a60718293b4c5d",
"type": "subscription_payment.completed",
"version": "2026-04-21",
"occurredAt": "2026-04-20T14:22:11+09:00",
"data": {
"object": {
"merchantUid": "test_merchant_0001",
"buyer": {
"type": "MEMBER",
"displayName": "테스트 구매자",
"email": "test@buyer.example"
},
"content": {
"id": "test_content_0001",
"title": "테스트 구독 상품",
"type": "DOCUMENT",
"paymentType": "SUBSCRIPTION"
},
"options": [
{
"optionId": "test_option_0001",
"name": "월간 플랜",
"description": "테스트용 월간 구독 옵션",
"quantity": 1,
"unitOriginalPrice": 9900,
"unitDiscountedPrice": 9900,
"additionalOptions": [],
"subtotal": 9900
}
],
"pricing": {
"currency": "KRW",
"originalAmount": 9900,
"optionDiscountAmount": 0,
"finalAmount": 9900,
"couponDiscountAmount": 0
},
"paymentMethod": {
"type": "CARD",
"cardName": "테스트카드",
"maskedCardNumber": "1234-****-****-5678"
},
"questionAnswers": [],
"payment": {
"purchasedAt": "2026-04-20T14:22:11+09:00"
},
"subscription": {
"billingReason": "INITIAL",
"currentRound": 1,
"nextBillingDate": "2026-05-20",
"status": "ACTIVE",
"activatedAt": "2026-04-20T14:22:11+09:00",
"lastBillingSucceededAt": "2026-04-20T14:22:11+09:00"
}
}
}
}4. payment.cancel_requested (일반결제 취소 요청)
payment.completed 대비 차이
경로 | 타입 | 의미 |
|---|---|---|
| string | 원 결제와 동일한 값 |
| string |
|
| object | 포함되지 않음 |
| string |
|
| string | PG 조회 실패 시 |
| string | PG 조회 실패 시 |
cancelRequest
경로 | 타입 | 의미 |
|---|---|---|
| object | 사유 블록 |
| string | 취소 요청 사유 |
| string | 사유 한글 라벨 |
| string | 상세 사유. 없으면 생략 |
| string | 현재 |
| string | 취소 요청 시각 |
참고
buyer.phoneNumber와shipping은content.type == GOODS일 때만 포함됩니다.
JSON 예시 👀
{
"id": "evt_test_c1d2e3f4a5b60718293c4d5e",
"type": "payment.cancel_requested",
"version": "2026-04-21",
"occurredAt": "2026-04-20T14:22:11+09:00",
"data": {
"object": {
"merchantUid": "test_merchant_0001",
"buyer": {
"type": "MEMBER",
"displayName": "테스트 구매자",
"email": "test@buyer.example",
"phoneNumber": "01012345678"
},
"content": {
"id": "test_content_0001",
"title": "테스트 실물 상품",
"type": "GOODS",
"paymentType": "ONE_TIME"
},
"options": [
{
"optionId": "test_option_0001",
"name": "기본 옵션",
"description": "테스트용 기본 옵션",
"quantity": 1,
"unitOriginalPrice": 10000,
"unitDiscountedPrice": 10000,
"additionalOptions": [],
"subtotal": 10000
}
],
"pricing": {
"currency": "KRW",
"originalAmount": 10000,
"optionDiscountAmount": 0,
"finalAmount": 10000,
"couponDiscountAmount": 0
},
"paymentMethod": {
"type": "CARD",
"cardName": "테스트카드",
"maskedCardNumber": "1234-****-****-5678"
},
"shipping": {
"address": "서울시 강남구 테헤란로 123",
"streetAddress": "서울시 강남구 테헤란로 123",
"detailAddress": "101동 202호",
"deliveryRequest": "문 앞에 놓아주세요"
},
"questionAnswers": [],
"cancelRequest": {
"reason": {
"code": "CHANGED_MIND",
"label": "마음이 바뀌었어요"
},
"detailReason": "색상이 마음에 들지 않아요",
"requestedBy": "BUYER",
"requestedAt": "2026-04-20T14:22:11+09:00"
},
"payment": {
"purchasedAt": "2026-04-19T14:22:11+09:00"
}
}
}
}5. subscription.cancel_requested (정기결제 해지 신청)
subscription_payment.completed 대비 차이
경로 | 타입 | 의미 |
|---|---|---|
| object | 포함되지 않음 |
| array | 포함되지 않음 |
| object | 포함되지 않음 |
subscription
경로 | 타입 | 의미 |
|---|---|---|
| string | 항상 |
| number | 해지 시점의 누적 결제 회차 |
| string |
|
| string | 최초 정기결제 활성화 시각 |
| string | 해지 신청 시각 |
| number | 직전 결제 금액 |
| string | 항상 |
| string | 직전 실패 사유. 없으면 생략 |
cancelRequest
경로 | 타입 | 의미 |
|---|---|---|
| object | 해지 신청 사유 블록 |
| string | 해지 신청 사유 |
| string | 해지 신청 사유 한글 라벨 |
| string | 상세 사유. 값이 있으면 포함 |
| string | 현재 |
| string | 해지 신청 시각 |
JSON 예시 👀
{
"id": "evt_test_d1e2f3a4b5c60718293d4e5f",
"type": "subscription.cancel_requested",
"version": "2026-04-21",
"occurredAt": "2026-04-20T14:22:11+09:00",
"data": {
"object": {
"merchantUid": "test_merchant_0001",
"buyer": {
"type": "MEMBER",
"displayName": "테스트 구매자",
"email": "test@buyer.example"
},
"content": {
"id": "test_content_0001",
"title": "테스트 구독 상품",
"type": "DOCUMENT",
"paymentType": "SUBSCRIPTION"
},
"options": [
{
"optionId": "test_option_0001",
"name": "월간 플랜",
"description": "테스트용 월간 구독 옵션",
"quantity": 1,
"unitOriginalPrice": 9900,
"unitDiscountedPrice": 9900,
"additionalOptions": [],
"subtotal": 9900
}
],
"pricing": {
"currency": "KRW",
"originalAmount": 9900,
"optionDiscountAmount": 0,
"finalAmount": 9900,
"couponDiscountAmount": 0
},
"payment": {
"purchasedAt": "2026-01-20T14:22:11+09:00"
},
"subscription": {
"status": "CANCELLED",
"currentRound": 3,
"nextBillingDate": "2026-05-05",
"activatedAt": "2026-01-20T14:22:11+09:00",
"cancelledAt": "2026-04-20T14:22:11+09:00",
"price": 9900,
"currency": "KRW"
},
"cancelRequest": {
"reason": {
"code": "ETC",
"label": "기타"
},
"detailReason": "지금은 더 이상 사용하지 않아요",
"requestedBy": "BUYER",
"requestedAt": "2026-04-20T14:22:11+09:00"
}
}
}
}