Webhook - 결제 환불 요청 완료 #
1. Webhook Overview #
Purpose #
매입(Capture)이 완료된 결제 건에 대해 상점에서 환불(Refund) 요청을 접수했을 때 EBP 시스템에서 상점으로 전송하는 Webhook 이벤트입니다.
이 이벤트를 통해 상점은 환불 요청이 시스템에 정상적으로 접수되었음을 실시간으로 확인하고, 환불 진행 중 상태로 주문 정보를 업데이트하는 등 후속 처리를 진행할 수 있습니다.
참고: Webhook 수신을 위해 URL 등록이 필요합니다. (문의: ebp-server@lge.com)
Details #
| 항목 | 값 |
|---|---|
| Webhook Name | 결제 환불 요청 완료 |
| Event Type | PAYMENT_REFUND_REQUESTED |
| HTTP Method | POST |
| Region | Global |
2. Authentication #
EBP 시스템에서 전송하는 모든 Webhook 요청은 무결성 검증을 위해 다음 헤더를 포함합니다. 상점은 해당 값을 확인하여 요청의 유효성을 반드시 검증해야 합니다.
| 헤더명 | 설명 |
|---|---|
x-webhook-signature | Webhook 메시지의 무결성을 검증하기 위한 HMAC-SHA256 시그니처 |
x-webhook-signature-timestamp | Webhook 이벤트가 전송된 시점의 타임스탬프 (Unix Epoch, seconds) |
Signature 생성 및 검증 규칙 #
상점은 수신한 Webhook의 바디(Body) 데이터와 타임스탬프 헤더 값을 조합하여 직접 시그니처를 생성한 뒤, 전송받은 x-webhook-signature 값과 일치하는지 비교해야 합니다.
- Input Message 구성:
x-webhook-signature-timestamp 헤더 값 + "." + 원본 Request Body (JSON String) - 해싱 (Hashing): 구성된 메시지를 HMAC-SHA256 알고리즘과 EBP에서 발급받은 Webhook Secret Key를 사용하여 해싱합니다.
- 인코딩 (Encoding): 해싱 결과를 **Hex 문자열(Hexadecimal)**로 변환합니다.
- 검증: 생성한 Hex 문자열과
x-webhook-signature헤더 값이 동일한지 확인합니다.
검증 예제 (Java) #
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
public class WebhookVerifier {
private static final String HMAC_SHA256 = "HmacSHA256";
/**
* Webhook 시그니처 검증 메서드
*
* @param secretKey EBP에서 발급받은 Webhook Secret Key
* @param timestamp x-webhook-signature-timestamp 헤더 값
* @param requestBody 수신한 HTTP Request Body (JSON 문자열)
* @param receivedSig x-webhook-signature 헤더 값
* @return 검증 성공 여부
*/
public boolean verifySignature(String secretKey, String timestamp, String requestBody, String receivedSig) {
if (timestamp == null || receivedSig == null || secretKey == null || secretKey.isEmpty()) {
return false;
}
try {
String inputMessage = timestamp + "." + requestBody;
Mac mac = Mac.getInstance(HMAC_SHA256);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), HMAC_SHA256);
mac.init(secretKeySpec);
byte[] hashBytes = mac.doFinal(inputMessage.getBytes(StandardCharsets.UTF_8));
String generatedSig = HexFormat.of().formatHex(hashBytes);
return generatedSig.equalsIgnoreCase(receivedSig);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
// log.error("Failed to verify EBP webhook signature", e);
return false;
}
}
}
[!IMPORTANT]
Webhook Secret Key는 EBP를 통해 발급받아야 하며, 관련 문의는 ebp-server@lge.com으로 연락 주시기 바랍니다. 시그니처 검증이 실패할 경우 해당 요청은 신뢰할 수 없는 요청으로 간주하고 무시해야 합니다.
3. Data Schema #
3.1. Payload Data Schema #
| depth | Field | Details & Description |
|---|---|---|
| -1 | eventType |
🔴 Required 이벤트 유형 e.g., PAYMENT_REFUND_REQUESTED |
| -1 | eventTime |
🔴 Required 이벤트 발생 시각 e.g., 2025-12-30T10:00:00Z |
| -1 | data |
🔴 Required 환불 요청 상세 데이터 |
| 0 | orderNo |
🔴 Required EBP 주문 번호 e.g., ORD_7202603277730794 |
| 0 | paymentStatus |
🔴 Required 결제 상태 코드 e.g., REFUND_REQUESTED |
| 0 | refundRequestedAmount |
🔴 Required 환불 요청 금액 e.g., 50000 |
| 0 | currencyCode |
🔴 Required 통화 코드. ISO 4217 e.g., KRW |
| 0 | exponent |
🔴 Required 통화 소수점 자리수 e.g., 0 |
| 0 | resultCode |
🔴 Required EBP 결과 코드 ('0': 성공) e.g., 0 |
| 0 | resultMessage |
⚪ Optional 결과 메시지 e.g., SUCCESS |
| 0 | refundRequestedAt |
🔴 Required EBP 환불 요청 접수 일시 e.g., 2025-12-30T10:00:00Z |
| 0 | pgProvider |
🔴 Required 결제 PG사 코드 e.g., WORLDPAY, OMISE |
3.2. Payload 예시 #
HTTP Request #
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
x-webhook-signature: 25f0e... (HMAC-SHA256 Hex String)
x-webhook-signature-timestamp: 1735552800 (Unix Epoch Seconds)
{
"eventType": "PAYMENT_REFUND_REQUESTED",
"eventTime": "2025-12-30T10:00:00Z",
"data": {
"orderNo": "ORD_7202603277730794",
"paymentStatus": "REFUND_REQUESTED",
"refundRequestedAmount": 50000,
"currencyCode": "KRW",
"exponent": 0,
"resultCode": "0",
"resultMessage": "SUCCESS",
"refundRequestedAt": "2025-12-30T10:00:00Z",
"pgProvider": "WORLDPAY"
}
}