# 웹훅
# 개요
웹훅은 시스템에서 발생하는 이벤트에 대한 참고입니다. 특정 이벤트가 발생하면 엑솔라는 이벤트 데이터가 송신되는 HTTP 요청을 애플리케이션에
보냅니다. 이는 일반적으로 JSON 형식의 POST 요청입니다.
이벤트 예시:
- 아이템 카탈로그와 사용자 상호 작용
- 주문 결제 또는 취소
설정한 이벤트가 발생하면 엑솔라는 웹훅을 통해 시스템에 해당 이벤트를 알립니다. 그 결과로 다음과 같은 작업을 수행할 수 있습니다.
- 사용자의 잔액 충전
- 결제 대금 환불
- 사용자 계정에서 새 아이템 추가 또는 제거
- 정기 결제 서비스 제공 시작
- 부정 결제가 의심되는 경우 사용자 차단
결제 처리 웹훅 워크플로의 예시:

메모
사용된 솔루션과 통합 유형에 따라 웹훅 세트와 상호작용 순서가 제공된 예시와 다를 수 있습니다.
엑솔라 웹훅 통합을 위한 동영상 가이드:
엑솔라 상품 및 솔루션으로 작업 시 웹훅 설정:
| 상품/솔루션 |
필수/선택 |
웹훅 사용처 |
| 결제 |
필수 |
- 사용자 유효성 검사.
- 결제 성공 또는 결제 환불 시 트랜잭션 세부 정보에 대한 정보 수신.
- 구매한 아이템을 사용자에게 추가하고 주문 취소 시 아이템을 제거.
|
| 스토어 |
필수 |
- 사용자 유효성 검사.
- 결제 성공 또는 결제 환불 시 트랜잭션 세부 정보에 대한 정보 수신.
- 구매한 아이템을 사용자에게 추가하고 주문 취소 시 아이템을 제거.
|
| 게임 판매 |
선택 사항 |
게임 키 판매의 경우 사용자 유효성 검사 및 아이템 추가가 필요하지 않습니다. 결제나 주문 취소 등 이벤트 관련 정보를 수신하기 위해 웹훅을 연결할 수 있습니다. 웹훅을 연결하는 경우 들어오는 모든 필수 웹훅을 처리해야 합니다.
|
| 정기 결제 |
선택 사항 |
정기 결제 생성, 업데이트 또는 취소에 대한 정보를 받습니다. 또는 API를 통해 정보를 요청할 수 있습니다.
|
| 웹샵 |
필수 |
- 사용자 유효성 검사.
- 결제 성공 또는 결제 환불 시 트랜잭션 세부 정보에 대한 정보 수신.
- 구매한 아이템을 사용자에게 추가하고 주문 취소 시 아이템을 제거.
- 사용자 ID를 통한 인증을 사용하는 경우 사용자 인증을 사용합니다. 또는 엑솔라 로그인을 통한 사용자 인증을 사용할 수 있습니다.
|
| 디지털 배포 솔루션 |
필수 |
- 사용자 유효성 검사.
- 엑솔라 측의 트랜잭션 ID와 시스템의 트랜잭션 ID를 연결.
- 주문에서 추가 트랜잭션 매개 변수를 전송.
- 구매한 아이템을 사용자에게 추가하고 주문 취소 시 아이템을 제거.
디지털 배포 솔루션에 대한 웹훅 설정에 대한 자세한 내용은 문서를 참조하세요.
|
| 로그인 |
선택 사항 |
이벤트 정보 수신:
- 사용자 등록/권한 부여
- 사용자 이메일 주소 확인
- 사용자의 소셜 미디어 계정 연결
웹훅 설정 방법에 대한 자세한 정보는 로그인 문서를 참조하십시오.
|
# 필수 웹훅 목록
웹훅 작업이 필요한 상품 및 솔루션을 사용하는 경우 관리자 페이지에서 웹훅을 활성화 및 테스트하고 처리를 설정합니다. 특정 이벤트가 발생하면
웹훅이 순차적으로 전송됩니다. 따라서 웹훅 중 하나를 처리하지 않으면 후속 웹훅이 전송되지 않습니다. 필수 웹훅 목록은 아래에 제시되어
있습니다.
## 스토어 및 결제 솔루션
사이트에서 아이템을 구매하고 반품할 때 엑솔라 측에서 2개의 웹훅 전송 옵션이 설정되었습니다. 결제 및 트랜잭션 데이터가 포함된 정보와 구매한
아이템에 대한 정보는 별도로 제공되거나 하나의 웹훅으로 결합될 수 있습니다.
결합된 웹훅에서 정보 수신:
2025년 1월 22일 이후 관리자 페이지에 등록한 경우, 주문 결제 성공(`order_paid`)
및 주문 취소(`order_canceled`)
웹훅의 모든 정보를 수신하게 됩니다. 이 경우, 결제(`payment`) 및 환불(`refund`) 웹훅을 처리하지 않아도 됩니다.
개별 웹훅에서 정보 수신:
2025년 1월 22일 이후 관리자 페이지에 등록한 경우, 다음
웹훅을 받게 됩니다.
- 결제 데이터 및 트랜잭션 세부 정보가 포함된 결제(`payment`) 및 환불(`refund`).
- 구매한 아이템에 대한 정보가 포함된 주문 결제 성공(`order_paid`) 및 주문 취소(`order_canceled`).
유입되는 모든 웹훅을 처리해야 합니다. 결합된 웹훅을 수신하는 새로운 옵션으로 전환하려면 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일을 보내십시오.
인게임 스토어와 결제 관리를 완벽하게 운영하려면 주요 웹훅을 처리해야 합니다.
결합된 웹훅을 수신하는 경우:
| 웹훅 이름 및 유형 |
설명 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
사용자가 게임에 등록되었는지 확인하기 위해 결제 과정의 여러 단계에서 전송됩니다. |
게임 서비스> 결합된 웹훅 > 주문 결제 성공(order_paid) |
여기에는 결제 데이터, 트랜잭션 세부 정보 및 구매한 아이템에 대한 정보가 포함됩니다. 웹훅의 데이터를 사용하여 사용자에게 아이템을 추가합니다. |
게임 서비스 > 결합된 웹훅 > 주문 취소(order_canceled) |
취소된 결제, 트랜잭션 세부 정보, 구매한 아이템에 대한 정보가 포함되어 있습니다. 웹훅의 데이터를 사용하여 구매한 아이템을 제거합니다. |
개별 웹훅을 수신하는 경우:
| 웹훅 이름 및 유형 |
설명 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
사용자가 게임에 등록되었는지 확인하기 위해 결제 과정의 여러 단계에서 전송됩니다. |
결제 > 지불(payment) |
여기에는 결제 데이터와 트랜잭션 세부 정보가 포함되어 있습니다. |
게임 서비스> 개별 웹훅 > 주문 결제 성공(order_paid) |
여기에는 구매한 아이템에 대한 정보가 포함되어 있습니다. 웹훅의 데이터를 사용하여 사용자에게 아이템을 추가합니다. |
결제 > 환불(refund) |
여기에는 결제 데이터와 트랜잭션 세부 정보가 포함되어 있습니다. |
게임 서비스 > 개별 웹훅 > 주문 취소(order_canceled) |
여기에는 구매한 아이템에 대한 정보와 취소된 트랜잭션 ID가 포함되어 있습니다. 웹훅의 데이터를 사용하여 구매한 아이템을 제거합니다. |
애플리케이션 측에 아이템 카탈로그 개인
설정이 구현된 경우 파트너
측에서 카탈로그 개인화 웹훅을 처리하도록 설정합니다.
## 정기 결제
정기 결제 플랜을 자동으로 관리하려면 기본 웹훅 처리를 구현해야 합니다.
- 사용자 유효성
검사(`user_validation`) - 사용자가 게임에 등록되었는지 확인하기 위해 결제 과정의 여러 단계에서 전송됩니다.
- 결제(`payment`) - 주문이 결제될 때 전송되며 결제
데이터와 트랜잭션 세부 정보가 포함되어 있습니다.
- 생성된 정기
결제(`create_subscription`) - 결제
웹훅이 성공적으로 처리되었거나 사용자가 평가판 사용 기간이 있는 정기 결제 구매했을 때 전송됩니다. 여기에는 구매한 정기 결제의 세부 정보 및
사용자 데이터가 포함되어 있습니다. 웹훅 데이터를 사용하여 사용자에게 정기 결제를 추가할 수 있습니다.
- 업데이트된 정기
결제(`update_subscription`) - 정기 결제가 갱신되거나 변경될 때, 결제 웹훅이
성공적으로 처리되었을 때 전송됩니다. 여기에는 구매한 정기 결제의 세부 정보와 사용자 데이터가 포함되어 있습니다. 웹훅 데이터를 사용하여
사용자의 정기 결제를 연장하거나 정기 결제 매개 변수를 변경할 수 있습니다.
- 환불(`refund`) - 주문이 취소될 때 전송되며 취소된 결제
데이터와 트랜잭션 세부 정보가 포함되어 있습니다.
- 취소된 정기
결제(`cancel_subscription`) - 환불 웹훅이
성공적으로 처리되었거나 다른 사유로 정기 결제가 취소된 경우 전송됩니다. 여기에는 정기 결제 및 사용자 데이터에 대한 정보가 포함되어
있습니다. 웹훅 데이터를 사용하여 구매한 정기 결제를 사용자로부터 제거합니다.
# 관리자 페이지에서 웹훅 설정하기
## 일반 설정
웹훅 수신을 활성화하는 방법:
1. 관리자 페이지의 프로젝트에서 프로젝트 설정>
웹훅 섹션으로 이동합니다.
2. 웹훅 서버 필드에서 웹훅을 수신할 서버의 URL을 `https://example.com` 형식으로 지정합니다. 웹훅 테스트용
도구에서 찾은 URL을 지정할 수도 있습니다.
주의
데이터 전송에는 HTTPS 프로토콜이 사용되며 HTTP 프로토콜은 지원되지 않습니다.
3. 비밀 키를 생성합니다:
- 비밀 키 섹션에서 키 축가를 클릭합니다.
- 모달 창이 열릴 경우 일반 목록에서 해당 키를 식별할 수 있는 키 이름을 입력합니다.
- 키 생성을 클릭합니다.
- 비밀 키 복사를 클릭하고 생성된 키를 사용자 측에 저장하십시오.
- 완료를 클릭합니다.
- 키를 저장했는지 확인하고 확인하고 닫기를 클릭합니다.

주의
주요 권장 사항:
- 생성된 비밀 키를 사용자 측에 저장합니다. 생성된 경우에만 관리자 페이지에서 키가 표시됩니다.
- 비밀 키를 어느 누구와도 공유하지 마십시오.
- 비밀 키를 귀하의 서버에 저장해야 하고 바이너리 또는 프런트 엔드에 저장하지 마십시오.
4. **웹훅 활성화**를 클릭합니다.
참고
웹훅을 동시에 다른 URL로 보낼 수 없습니다. 관리자 페이지에서 할 수 있는 작업은 먼저 테스트용 URL을 지정한 다음 실제 URL로 바꾸는 것입니다.
웹훅 수신을 비활성화하는 방법:
1. 관리자 페이지의 프로젝트에서 프로젝트 설정>
웹훅 섹션으로 이동합니다.
2. 웹훅 비활성화를 클릭합니다.
## 비밀 키 갱신
정기적으로 비밀 키를 업데이트하면 통합의 보안이 강화됩니다. 프로젝트에서 최대 5개의 비밀 키를 생성하여 주기적으로 갱신할 수 있습니다.
방법은 다음과 같습니다.
1. 프로젝트 설정>
웹훅 섹션에서 **키 추가**를 클릭합니다.

2. 모달 창이 열릴 경우 일반 목록에서 해당 키를 식별할 수 있는 키 이름을 입력합니다.
3. **키 생성**을 클릭합니다.
4. **비밀 키 복사**를 클릭하고 생성된 키를 사용자 측에 저장하십시오.
5. **완료**를 클릭합니다.
6. 키를 저장했는지 확인하고 **확인하고 닫기**를 클릭합니다.
주의
주요 권장 사항:
- 생성된 비밀 키를 사용자 측에 저장합니다. 생성된 경우에만 관리자 페이지에서 키가 표시됩니다.
- 비밀 키를 어느 누구와도 공유하지 마십시오.
- 비밀 키를 귀하의 서버에 저장해야 하고 바이너리 또는 프런트 엔드에 저장하지 마십시오.
프로젝트당 하나의 활성 비밀 키만 허용됩니다. 키를 변경하려면 다른 키 행에서 **활성으로 설정**을 클릭하고 작업을 확인하세요. 새 키로
마이그레이션이 완료되면 비활성화된 키를 삭제하는 것이 좋습니다.

## 고급 설정
웹훅의 경우 결제 및 스토어 섹션에서 고급 설정을 사용할 수 있습니다. 이러한 설정은 자동으로 웹훅 수신
버튼을 클릭한 후 일반 설정 블록 아래에 나타납니다.
참고
고급 설정이 표시되지 않으면 일반 설정에서 웹훅 수신이 연결되어 있는지 확인하고 테스트 > 결제 및 스토어 탭에 있어야 합니다.
이 섹션에서는 웹훅에서 추가 정보 수신을 설정할 수 있습니다. 이를 위해 해당 스위치를 활성 위치로 설정합니다. 각 권한의 줄은 설정을
변경하면 영향을 받는 웹훅을 나타냅니다.
| 토글 |
설명 |
| 저장된 결제 계정에 대한 정보를 표시합니다(2025년 1월 22일 이전에 관리자 페이지에 등록하고 별도의 웹훅을 수신하는 경우에만 표시됩니다). |
저장된 결제 방식에 대한 정보는 payment_account 사용자 정의 개체에서 전달됩니다. |
| 저장된 결제 방식을 통해 트랜잭션에 대한 정보 표시 |
정보는 웹훅의 다음 사용자 정의 매개 변수에서 전달됩니다. saved_payment_method:0 - 저장된 결제 방식이 사용되지 않음1 - 현재 결제를 진행할 때 결제 방식이 저장됨2 - 이전에 저장한 결제 방식이 사용됨
payment_type:
|
order 개체를 웹훅에 추가합니다. 2025년 1월 22일 이전에 관리자 페이지에 등록하고 별도의 웹훅을 수신하는 경우에만 표시됩니다). |
주문 관련 정보는 결제 웹훅의 order 개체에서 전달됩니다. |
| 민감한 데이터 없이 필수 사용자 매개 변수만 전송합니다. |
사용자에 대한 다음 정보만 웹훅에서 전달됩니다. |
| 사용자 정의 매개 변수를 전송합니다. |
사용자 정의 토큰 매개 변수 관련 정보가 웹훅에서 전달됩니다. |
| 카드 BIN 및 접미사를 표시합니다. |
은행 카드 번호에 대한 다음 정보가 웹훅에서 전달됩니다. card_bin 매개 변수의 처음 6자리card_suffix의 마지막 4자리
|
| 카드 브랜드를 표시합니다. |
결제에 사용된 카드의 브랜드. 예: Mastercard 또는 Visa. |
| 환불 사유에 대한 정보를 표시합니다. |
환불 사유에 대한 자세한 정보입니다. |
| 국가별 WHC 및 사용자 확보 수수료를 표시합니다. |
payment_details.country_wht 및 payment_details.user_acquisition_fee 개체가 웹훅에 전달됩니다. 이 토글은 기본적으로 켜져 있습니다. |
| 3DS 정보를 전송합니다. |
3D Secure 인증에 대한 데이터를 포함하는 cards 개체가 웹훅을 통해 전달됩니다. |

# 관리자 페이지에서 웹훅 테스트하기
웹훅을 테스트하면 사용자 측과 엑솔라 측 모두에서 프로젝트를 올바르게 설정하는 데 도움이 돕니다.
웹훅을 성공적으로 설정하면 웹훅 설정 섹션 아래에 웹훅 테스트 섹션이 표시됩니다.

관리자 페이지의 테스트 섹션은 웹훅 수신 옵션에 따라 다릅니다.
2025년 1월 22일 이후에 관리자 페이지에 등록한 경우, 통합 웹훅을 수신하게 됩니다.
| 웹훅 테스트를 위한 탭 이름 |
웹훅 이름 및 유형 |
| 결제 및 스토어 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
|
게임 서비스> 결합된 웹훅 > 주문 결제 성공(order_paid) |
|
게임 서비스 > 결합된 웹훅 > 주문 취소(order_canceled) |
| 정기 결제 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
|
결제 > 지불(payment) |
2025년 1월 22일 이전에 관리자 페이지에 등록한 경우, 별도의 웹훅을 받게 됩니다.
| 웹훅 테스트를 위한 탭 이름 |
웹훅 이름 및 유형 |
| 스토어 |
게임 서비스> 개별 웹훅 > 주문 결제 성공(order_paid) |
|
게임 서비스 > 개별 웹훅 > 주문 취소(order_canceled) |
| 결제 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
|
결제 > 지불(payment) |
| 정기 결제 |
사용자 유효성 검사 > 사용자 유효성 검사(user_validation) |
|
결제 > 지불(payment) |
참고
테스트 섹션에 테스트를 통과하지 못했다는 경고가 표시되면 웹훅 리스너에서 웹훅 응답 설정을 확인합니다. 테스트 오류의 원인은 테스트 결과에 표시됩니다.
예:
전문 사이트 webhook.site를 테스트에 사용합니다.
잘못된 서명에 대한 응답 테스트 섹션에 오류가 표시됩니다.
이는 엑솔라가 잘못된 서명이 포함된 웹훅을 전송하고 핸들러가 INVALID_SIGNATURE 오류 코드
를 지정하는
4xx HTTP 코드로 응답할 것으로 예상하기 때문에 발생합니다.
webhook.site는 잘못된 서명이 있는 웹훅을 포함하여 모든 웹훅에 응답으로 200 HTTP 코드를 전송합니다. 예상한 4xx HTTP 코드를 구할 수 없으므로 테스트 결과에 오류가 표시됩니다.
결합된 웹훅이 있는 시나리오를 테스트하는 프로세스는 아래와 같습니다.
## 결제 및 스토어
결제 및 스토어 탭에서 다음 웹훅을 테스트할 수 있습니다.
- 사용자 유효성 검사(`user_validation`)
- 주문 결제
성공(`order_paid`)
- 주문 취소(`order_canceled`)
웹훅 테스트 방법:
1. 웹훅 테스트 섹션에서 결제 및 스토어 탭으로 이동합니다.
2. 드롭다운 목록에서 아이템 유형을 선택합니다. 관리자 페이지에 아직 이 아이템 유형을 설정하지 않았다면 버튼을 클릭하여 구성하세요. 항목을
생성한 후 웹훅 테스트 섹션으로 돌아가 다음 단계로 진행합니다.
3. 필수 입력란을 기입하십시오:
* **사용자 ID** - 테스트 시 문자 및 숫자를 임의로 조합하여 사용할 수 있습니다.
* **엑솔라 주문 ID** 입력란에 아무 값이나 입력합니다.
* **엑솔라 송장 ID** - 엑솔라 측 트랜잭션 ID입니다. 테스트 시 임의의 숫자 값을 사용할 수 있습니다.
* **송장 ID** - 게임 측 트랜잭션 ID입니다. 테스트 시 문자와 숫자를 임의로 조합하여 사용할 수 있습니다. 결제 성공을 위한 필수 매개
변수는 아니지만, 게임 측 거래 ID와 엑솔라 측 거래 ID를 연결하기 위해 전달할 수 있습니다.
* **금액** - 결제 금액입니다. 테스트 시 임의의 숫자 값을 사용할 수 있습니다.
* **통화** - 드롭다운 목록에서 통화를 선택합니다.
* 드롭다운 목록에서 아이템의 SKU를 선택하고 수량을 표시합니다. **+**를 클릭하고 같은 유형의 아이템을 여러 개 선택하고 이를 새 줄에
추가할 수 있습니다.
4. **웹훅 테스트**를 클릭합니다.
사용자 유효성 검사, 주문 결제 성공 및 주문 취소 웹훅은 지정된 데이터가 포함된 웹훅을
제공된 URL로 전송합니다. 각 웹훅 유형의 테스트 결과는 웹훅 테스트 버튼 아래에 표시됩니다.
프로젝트 설정 > 통합
설정 섹션에서 공개 사용자 ID 상자를 체크 표시한 경우, 사용자 검색 웹훅은 사용자의 웹훅 서버 URL로도 전송되며 테스트 결과가 표시됩니다.
각 웹훅에 대해 성공한 시나리오와 오류가 있는 시나리오를 모두 처리하도록 구성해야 합니다.

## 정기 결제
정기 결제 탭에서 다음 웹훅을 테스트할 수 있습니다.
- 사용자 유효성 검사(`user_validation`)
- 결제 (`payment`)
참고:
다른 정기 결제 관리 시나리오 테스트에 대한 자세한 정보는 통합 가이드에서 확인할 수 있습니다.
웹훅 테스트 방법:
1. 테스트 섹션에서 **정기 결제** 탭으로 이동합니다.
2. 필수 입력란을 기입하십시오:
* **사용자 ID** - 테스트 시 문자 및 숫자를 임의로 조합하여 사용할 수 있습니다.
* **엑솔라 송장 ID** - 엑솔라 측 트랜잭션 ID입니다. 테스트 시 임의의 숫자 값을 사용할 수 있습니다.
* **공개 사용자 ID** - 사용자가 알고 있는 ID(예: 이메일 또는 닉네임). 이 입력란은 [프로젝트 설정 > 통합
설정](https://publisher.xsolla.com/0/projects/0/edit/advanced) 섹션의 프로젝트에서 **공개
사용자 ID 사용** 확인란을 선택한 경우에 이 입력란이 표시됩니다.
* **금액** - 결제 금액입니다. 테스트 시 임의의 숫자 값을 사용할 수 있습니다.
* **통화** - 드롭다운 목록에서 통화를 선택합니다.
* **플랜 ID** - 정기 결제 플랜입니다. 드롭다운 목록에서 플랜을 선택합니다.
* **정기 결제 제품** - 드롭다운 목록에서 제품을 선택합니다(선택 사항). [제품](/ko/sell-subscriptions/integration-guide/get-started/#guides_subscriptions_glossary_product)이 프로젝트에 설정되어 있는 경우 해당
목록이 표시됩니다.
* **송장 ID** - 게임 측 트랜잭션 ID입니다. 테스트 시 문자와 숫자를 임의로 조합하여 사용할 수 있습니다. 결제 성공을 위한 필수 매개
변수는 아니지만, 게임 측 거래 ID와 엑솔라 측 거래 ID를 연결하기 위해 전달할 수 있습니다.
* **체험 기간**. [체험 기간 없이 정기 결제 구매](/ko/sell-subscriptions/integration-guide/get-subscription-information/#guides_subscriptions_get_subscription_set_up_webhooks_sandbox)를
테스트하거나 [정기 결제 갱신](/ko/sell-subscriptions/integration-guide/get-subscription-information/#guides_subscriptions_get_subscription_set_up_webhooks_test_renewal)
을 테스트하려면 값을 `0`으로 지정합니다.
3. **테스트**를 클릭합니다.
지정된 URL로 데이터가 채워진 웹훅을 받게 됩니다. 성공적인 시나리오와 오류가 있는 시나리오 모두에 대한 각 웹훅의 테스트 결과가
테스트 버튼 아래에 표시됩니다.
# 웹훅 리스너
웹훅 리스너는 지정된 URL 주소로 들어오는 웹훅을 수신하고, 서명을 생성하며, 엑솔라 웹훅 서버로 응답을 전송하는 프로그램 코드입니다.
애플리케이션 측의 다음 IP 주소에서 웹훅 수신을 구현합니다.
- `185.30.20.0/24`
- `185.30.21.0/24`
- `185.30.22.0/24`
- `185.30.23.0/24`
- `34.102.38.178`
- `34.94.43.207`
- `35.236.73.234`
- `34.94.69.44`
- `34.102.22.197`
로그인 제품을 통합한 경우, 다음 IP 주소에서 처리 웹훅을 추가로 추가합니다:
- `34.94.0.85`
- `34.94.14.95`
- `34.94.25.33`
- `34.94.115.185`
- `34.94.154.26`
- `34.94.173.132`
- `34.102.48.30`
- `35.235.99.248`
- `35.236.32.131`
- `35.236.35.100`
- `35.236.117.164`
제한 사항:
- 애플리케이션의 데이터베이스에 동일한 ID로 성공한 트랜잭션이 있으면 안 됩니다.
- 웹훅 리스너가 데이터베이스에 이미 존재하는 ID로 웹훅을 수신한 경우 이 트랜잭션의 이전 처리 결과를 반환해야 합니다. 사용자에게 중복 구매
항목을 추가하고 데이터베이스에 중복 레코드를 생성하는 것은 좋지 않습니다.
## 서명 생성
데이터의 안전한 전송을 보장하려면 웹훅이 실제로 엑솔라 서버에서 전송되었으며 전송 중에 변경되지 않았는지 확인해야 합니다. 이렇게 하려면,
요청 본문 페이로드를 기반으로 자체 서명을 생성하고 수신 요청의`authorization` 헤더에서 제공된 서명과 비교해야 합니다. 서명이
일치하면 웹훅은 진짜이며 안전하게 처리된 것입니다.
확인 단계:
1. 들어오는 웹훅 요청의`authorization` 헤더에서 서명을 조회합니다. 헤더 형식은 `서명 `입니다.
2. 웹훅 요청 본문을 JSON 형식으로 조회합니다. 알림
수신한
JSON 페이로드를 그대로 사용하세요. 페이로드를 구문 분석하거나 다시 인코딩하면 서식이 변경되어 서명 확인에 실패할 수 있으므로 페이로드를
구문 분석하거나 다시 인코딩해선 안 됩니다.
3. 비교를 위해 자체 서명을 생성합니다. - 문자열 끝에 키를 추가하여 JSON 페이로드를 프로젝트의 비밀 키와
연결합니다.
- 결과 문자열에 SHA-1 암호화 해시 함수를 적용합니다. 결과는 소문자 16진수 문자열이 됩니다.
4. 생성된 서명과 `authorization` 헤더의 서명을 비교합니다. 일치하면 웹훅이 진짜인 것입니다.
아래에서 C#, C++, Go, PHP, Node.js 언어로 서명 생성 구현 예시를 확인할 수 있습니다.
### 웹훅(HTTP) 예시:
```http
POST /your_uri HTTP/1.1
host: your.host
accept: application/json
content-type: application/json
content-length: 165
authorization: Signature 52eac2713985e212351610d008e7e14fae46f902
{
"notification_type":"user_validation",
"user":{
"ip":"127.0.0.1",
"phone":"18777976552",
"email":"email@example.com",
"id":1234567,
"name":"Xsolla User",
"country":"US"
}
}
```
### 웹훅(curl) 예시:
```bash
curl -v 'https://your.hostname/your/uri' \
-X POST \
-H 'authorization: Signature 52eac2713985e212351610d008e7e14fae46f902' \
-d '{
"notification_type":
"user_validation",
"user":
{
"ip": "127.0.0.1",
"phone": "18777976552",
"email": "email@example.com",
"id": 1234567,
"name": "Xsolla User",
"country": "US"
}
}'
```
### 서명 생성을 구현하는 C#의 예시(일반 예시):
참고
이 코드 샘플은 .NET Framework 4.0 이상 버전, .NET Core 및 기타 최신 .NET 버전과 호환됩니다. 서명 검증은 타이밍 공격을 방지하는 데 도움이 되는 ConstantTimeEquals 메서드를 통해 일정 시간 비교 방법을 사용합니다.
```csharp
using System;
using System.Security.Cryptography;
using System.Text;
public static class XsollaWebhookSignature
{
public static string ComputeSha1(string jsonBody, string secretKey)
{
// Concatenation of the JSON from the request body and the project's secret key
string dataToSign = jsonBody + secretKey;
using (SHA1 sha1 = SHA1.Create())
{
byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
// Convert hash bytes to lowercase hexadecimal string
var hexString = new StringBuilder(hashBytes.Length * 2);
foreach (byte b in hashBytes)
{
hexString.Append(b.ToString("x2"));
}
return hexString.ToString();
}
}
public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
{
string computedSignature = ComputeSha1(jsonBody, secretKey);
string receivedSignatureLower = receivedSignature.ToLower();
// Use constant-time comparison to prevent timing attacks
return ConstantTimeEquals(computedSignature, receivedSignatureLower);
}
private static bool ConstantTimeEquals(string a, string b)
{
if (a.Length != b.Length)
{
return false;
}
int result = 0;
for (int i = 0; i < a.Length; i++)
{
result |= a[i] ^ b[i];
}
return result == 0;
}
}
```
### 서명 생성을 구현하는 C# 예시(.NET 5.0 이상 버전):
참고
Convert.ToHexString 메서드를 사용하려면 .NET 5.0 이상 버전이 필요합니다.
.NET 7.0 이상 버전인 경우,
ConstantTimeEquals 대신
CryptographicOperations.FixedTimeEquals 메서드를 사용할 수도 있습니다.
```csharp
// For .NET 5.0 and later, you can use the more concise Convert.ToHexString method:
using System;
using System.Security.Cryptography;
using System.Text;
public static class XsollaWebhookSignature
{
public static string ComputeSha1(string jsonBody, string secretKey)
{
string dataToSign = jsonBody + secretKey;
using var sha1 = SHA1.Create();
byte[] hashBytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(dataToSign));
return Convert.ToHexString(hashBytes).ToLower();
}
public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
{
string computedSignature = ComputeSha1(jsonBody, secretKey);
string receivedSignatureLower = receivedSignature.ToLower();
// Use constant-time comparison to prevent timing attacks
return ConstantTimeEquals(computedSignature, receivedSignatureLower);
}
private static bool ConstantTimeEquals(string a, string b)
{
if (a.Length != b.Length)
{
return false;
}
int result = 0;
for (int i = 0; i < a.Length; i++)
{
result |= a[i] ^ b[i];
}
return result == 0;
}
}
```
### 서명 생성을 구현하는 C# 예시(.NET 7.0 이상 버전):
참고
.NET 7.0 이상 버전인 경우 CryptographicOperations.FixedTimeEquals 메서드를 사용할 수도 있습니다.
```csharp
// For .NET 7.0+, you can use the built-in CryptographicOperations.FixedTimeEquals:
using System.Security.Cryptography;
public static bool VerifySignature(string jsonBody, string secretKey, string receivedSignature)
{
string computedSignature = ComputeSha1(jsonBody, secretKey);
byte[] computedBytes = Encoding.UTF8.GetBytes(computedSignature);
byte[] receivedBytes = Encoding.UTF8.GetBytes(receivedSignature.ToLower());
return CryptographicOperations.FixedTimeEquals(computedBytes, receivedBytes);
}
```
### 서명 생성을 구현하는 C++의 예시:
```c++
#include
#include
#include
#include
class XsollaWebhookSignature {
public:
static std::string computeSha1(const std::string& jsonBody, const std::string& secretKey) {
// Concatenation of the JSON from the request body and the project's secret key
std::string dataToSign = jsonBody + secretKey;
unsigned char digest[SHA_DIGEST_LENGTH];
// Create SHA1 hash
SHA1(reinterpret_cast(dataToSign.c_str()),
dataToSign.length(), digest);
// Convert to lowercase hexadecimal string
std::ostringstream hexStream;
hexStream << std::hex << std::setfill('0');
for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) {
hexStream << std::setw(2) << static_cast(digest[i]);
}
return hexStream.str();
}
static bool verifySignature(const std::string& jsonBody, const std::string& secretKey, const std::string& receivedSignature) {
std::string computedSignature = computeSha1(jsonBody, secretKey);
// Timing-safe comparison
if (computedSignature.length() != receivedSignature.length()) {
return false;
}
volatile unsigned char result = 0;
for (size_t i = 0; i < computedSignature.length(); ++i) {
result |= (computedSignature[i] ^ receivedSignature[i]);
}
return result == 0;
}
};
```
### 서명 생성을 구현하는 Go 예시:
```go
package main
import (
"crypto/sha1"
"crypto/subtle"
"encoding/hex"
"strings"
)
type XsollaWebhookSignature struct{}
func (x *XsollaWebhookSignature) ComputeSha1(jsonBody, secretKey string) string {
// Concatenation of the JSON from the request body and the project's secret key
dataToSign := jsonBody + secretKey
// Create SHA1 hash
h := sha1.New()
h.Write([]byte(dataToSign))
signature := h.Sum(nil)
// Convert to lowercase hexadecimal string
return strings.ToLower(hex.EncodeToString(signature))
}
func (x *XsollaWebhookSignature) VerifySignature(jsonBody, secretKey, receivedSignature string) bool {
computedSignature := x.ComputeSha1(jsonBody, secretKey)
receivedSignatureLower := strings.ToLower(receivedSignature)
// Use constant time comparison to prevent timing attacks
return subtle.ConstantTimeCompare([]byte(computedSignature), []byte(receivedSignatureLower)) == 1
}
```
### 서명 생성을 구현하는 PHP의 예시:
```php
```
### 서명 생성을 구현하는 Node.js의 예시:
```js
const crypto = require('crypto');
class XsollaWebhookSignature {
// IMPORTANT: jsonBody must be the raw JSON string exactly as received from Xsolla
static computeSha1(jsonBody, secretKey) {
// Concatenation of the JSON from the request body and the project's secret key
const dataToSign = jsonBody + secretKey;
// Create SHA1 hash
const hash = crypto.createHash('sha1');
hash.update(dataToSign, 'utf8');
// Convert to lowercase hexadecimal string
return hash.digest('hex').toLowerCase();
}
static verifySignature(jsonBody, secretKey, receivedSignature) {
const computedSignature = this.computeSha1(jsonBody, secretKey);
const cleanReceivedSignature = receivedSignature.toLowerCase();
// Check if signatures have the same length before using timingSafeEqual
if (computedSignature.length !== cleanReceivedSignature.length) {
return false;
}
try {
return crypto.timingSafeEqual(
Buffer.from(computedSignature, 'hex'),
Buffer.from(cleanReceivedSignature, 'hex')
);
} catch (error) {
// Return false if there's any error (e.g., invalid hex characters)
return false;
}
}
}
```
## 웹훅에 응답 보내기
웹훅 수신을 확인하려면 서버가 다음을 반환해야 합니다.
* 성공적인 응답의 경우 `200`, `201` 또는 `204` HTTP 코드.
* 지정한 사용자를 찾을 수 없거나 잘못된 서명이 전달된 경우 문제 설명이 포함된 `400` HTTP 코드. 서버에
일시적인 문제가 발생한 경우 웹훅 핸들러가 `5xx` HTTP 코드를 반환할 수도 있습니다.
엑솔라 서버가 주문 결제 성공 및
주문 취소 웹훅에 대한 응답을 수신하지 않았거나
`5xx` 코드가 포함된 응답을 수신한 경우 다음 일정에 따라 웹훅이 재전송됩니다.
* 5분 간격으로 2번 시도
* 15분 간격으로 7번 시도
* 60분 간격으로 10번 시도
웹훅 전송은 첫 번째 시도 후 12시간 이내에 최대 20회까지 시도할 수 있습니다.
결제 및 환불 웹훅에 대한 재시도 로직은 개별 웹훅 페이지에 설명되어 있습니다.
주의
다음 조건을 모두 충족하는 경우에도 사용자에게 결제가 환불됩니다:
- 환불이 엑솔라 측에서 요청한 경우.
- 웹훅에 대한 응답으로,
4xx 상태 코드가 반환되거나 모든 재시도 후 응답을 받지 않거나 5xx 상태 코드가 반환된 경우.
엑솔라 서버가 사용자 유효성 검사 웹훅에 대한
응답을 수신하지 않았거나 `400` 또는 `5xx` 코드가 있는 응답을 수신한 경우 사용자 유효성 검사 웹훅은 재전송되지 않습니다. 이 경우 사용자에게 오류가 표시되며 결제 및 주문 결제 성공 웹훅이 전송되지 않습니다.
# 오류
HTTP 코드 400에 대한 오류 코드:
| 코드 |
메시지 |
| INVALID_USER |
잘못된 게임유저 |
| INVALID_PARAMETER |
잘못된 매개 변수 |
| INVALID_SIGNATURE |
잘못된 서명 |
| INCORRECT_AMOUNT |
잘못된 금액 |
| INCORRECT_INVOICE |
잘못된 인보이스 |
```
HTTP/1.1 400 Bad Request
{
"error":{
"code":"INVALID_USER",
"message":"Invalid user"
}
}
```
# 모범 사례
## 보안
다음 지침을 따르십시오.
* 유효한 인증서를 사용하여 HTTPS만 사용하십시오.
* 서명은 항상 원본 요청 본문과 대조하여 검증해야 합니다. 데이터를 파싱하거나 다시 인코딩하지 마십시오.
* URL에 민감한 데이터를 전달하지 말고 오류 메시지에 기술적인 세부 정보를 노출하지 마십시오.
* [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) 미들웨어에서 웹훅
엔드포인트를 제외합니다. 엑솔라에서 들어오는 요청에 CSRF 토큰이 포함되어 있지 않고 이 설정이 없는 요청은 거부됩니다.
* 허용 목록 [엑솔라 IP 주소](/ko/webhooks/section/webhook-listener).
## 웹훅 핸들러 아키텍처
다음 지침을 따르십시오.
1. 본문과 머리글이 **수정 없이** 그대로 있는 `POST` 요청을 수락합니다.
2. [웹훅 서명을 확인](/ko/webhooks/section/webhook-listener/generation-of-signature)하고 적절한
상태 코드를 반환합니다.
* 서명이 일치하지 않은 경우 `4xx`가 반환됩니다.
* 성공 시 `2xx`가 반환됩니다. 메인 비즈니스 논리를 실행하기 **전에** `204 No Content`을 반환하는 것이 좋습니다. `200
OK`도 허용됩니다.
3. 페이로드를 추가 처리를 위해 비동기 작업이나 큐로 전달합니다.
4. [항등성](https://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning)을
구현합니다. 시스템이 [두 번 이상 동일한 웹훅을 수신하는 작업을 처리할 수 있는지 확인해야 합니다(/webhooks/section
/webhook-listener/sending-responses-to-webhook).
**절차 예시:**
```http
HTTP POST /webhooks/xsolla
read raw_body, headers
if !verify_signature(raw_body, headers['authorization']):
return 400 {"error":{"code":"INVALID_SIGNATURE","message":"Invalid signature"}}
enqueue(raw_body)
return 204 # or 200
```
## 항등성 및 복제
다음 지침을 따르십시오.
* 거래 ID 및/또는 [외부 ID](/ko/dev-resources/faq/payments/#faq_payments_q_new_transaction_external_id), 주문 ID를 항등성 키로 사용합니다.
* 처리된 ID를 저장하고 복제 ID가 수신되면 이전 결과를 반환합니다.
* 아이템 재부여, 데이터베이스 중복 입력 및 이중 청구를 방지합니다.
* 순차적 전달 방식에서는 이전 이벤트 블록에 오류가 발생하면 이후의 모든 이벤트 처리가 차단된다는 점을 유념하십시오.
## 시스템 복원력
다음 지침을 따르십시오.
* 타사 API 호출, 청구 및 아이템 부여와 같이 리소스 집약적인 작업에는 큐와 비동기 처리를 사용합니다.
* 웹훅 핸들러에 대한 타임아웃(1~3초)을 설정합니다. 일시적인 오류가 발생할 경우 [엑솔라 재시도 메커니즘](/ko/webhooks/section/webhook-listener/sending-responses-to-webhook)을 사용하십시오.
* 웹훅 핸들러에서 재시도 기능을 구현하지 마십시오. 재전송은 엑솔라에서 처리합니다.
* 웹훅 전송 타임스탬프 및 처리 상태를 기록하고, `5xx` 오류 및 재전송 급증에 대한 알림을 설정합니다.
* 웹훅에서 상관 관계 ID를 로그 및 모니터링 시스템(APM)으로 전파합니다.
* 오류 로깅 및 모니터링 시스템을 구축합니다. 복구 불가능한 오류의 경우, 작업을 데드 레터 큐(DLQ)로 이동시킵니다. 항등성 메커니즘으로
보호되는 안전한 이벤트 재생 도구를 개발합니다.
## 구현 예시
**구매 성공 - 첫 시도에 아이템 부여 완료:**

**중복 전송(첫 번째 시도에서 파트너 타임아웃 발생):**

**환불:**

**파트너 서비스 중단**:

# FAQ
## 웹훅 프로토콜에 HTTPS를 사용해야 하나요?
예.
## 여러 URL에서 결제 웹훅을 수신할 수 있나요?
아니요. 결제 웹훅은 서버 간 프로토콜을 사용하며 [프로젝트 설정](/ko/webhooks/section/set-up-webhooks-in-publisher-account)에 지정된 단일 URL로 전송됩니다. 서 웹훅을 설정할 수 있습니다. 게임, 웹 사이트 또는 모바일
애플리케이션에서 알림을 받으려면 서버에서 웹훅을 설정하여 엑솔라와 게임 간에 데이터를 전송하세요. 개발자 콘솔에서도 웹훅을 테스트할 수
있습니다.
참고
로컬에서 통합을 테스트하는 경우, 엑솔라 측에서 보내는 `POST` 요청이 http://localhost:3000/my-webhook-endpoint와 같은 URL로 전달되지 않습니다. Ngrok과 같은 서비스를 사용하여 외부 접속을 위한 터널을 생성하면 로컬에서 엑솔라의 요청을 수신할 수 있습니다. 예를 들어, 이에 대한 자세한 내용은 ngrok 문서에서 확인할 수 있습니다.
## 엑솔라 알림이 웹훅 URL로 전송되지 않은 이유는 무엇입니까?
웹훅 서버가 `POST` 및 `GET` HTTP 요청 유형을 지원하는지 확인하십시오.
## 처리 과정에서 중복된 거래 ID가 발생하지 않도록 어떻게 방지할 수 있나요?
외부 ID를 사용하세요. 이 ID는 게임 내 주문에 할당된 거래 ID입니다. 엑솔라 측에서는 외부 ID를 거래 ID에 연결하여 동일한 거래에
대한 중복 결제를 방지합니다. 구성 세부 정보는 당사의 [documentation](/ko/dev-resources/faq/payments/#faq_payments_q_new_transaction_external_id) 문서를 참조하세요.
## 웹훅을 사용할 때 모범 사례가 있나요?
권장 사항:
* 서명 확인 직후 `204` 또는 `200`을 반환합니다.
* 수정하지 않고 원본 요청 본문과 웹훅 서명을 대조하여 확인합니다.
* 모든 연산에 대해 항등성을 구현합니다.
* 모든 이벤트를 기록하고 오류 모니터링을 설정합니다.
* URL에 민감한 데이터가 포함되지 않도록 하고 오류 메시지에 기술적인 세부 정보를 노출하지 않아야 합니다.
자세한 내용은 [모범 사례](/ko/webhooks/section/best-practices) 섹션을 참조하십시오.
# 웹훅 통합 체크리스트
웹훅이 제대로 작동하려면 서비스 출시 전에 다음 사항이 갖추어져 있는지 확인하십시오:
* HTTPS가 사용되었는지 확인합니다.
* 수정하지 않고 본래의 요청 본문에 대해 웹훅 [서명 확인](/ko/webhooks/section/webhook-listener/generation-of-signature)을 구현합니다.
* 서명이 확인되는 즉시 `204/200` 응답이 반환됩니다.
* 모든 연산에 대한 항등성을 구현합니다.
* 오류 로깅 및 모니터링을 구성합니다.
* 민감한 데이터는 URL을 통해 전달되지 않으며, 기술적인 세부 정보는 오류 메시지에 노출되지 않습니다.
* 웹훅 재시도는 [엑솔라 재시도 논리](/ko/webhooks/section/webhook-listener/sending-responses-to-webhook)에 따라 지원됩니다.
* 전체 통합 과정이 문서화됩니다.
# 웹훅 목록
참고
알림 유형은 notification_type 매개 변수로 전송됩니다.
| 웹훅 |
알림 유형 |
설명 |
| 사용자 유효성 검사 |
user_validation |
게임 시스템 내 유저의 존재를 확인하기 위해 보냅니다. |
| 사용자 검색 |
user_search |
공개 사용자 ID별로 사용자 정보를 가져오기 위해 보냅니다. |
| 결제 |
payment |
유저가 결제 프로세스를 완료했을 때 보냅니다. |
| 환불 |
refund |
알 수 없는 이유로 결제가 취소되었을 때 보냅니다. |
| 부분 환불 |
partial_refund |
어떤 이유로든 결제를 부분적으로 취소해야 할 때 전송됩니다. |
| 거부된 결제 |
ps_declined |
결제 시스템에 의해 결제가 거부되었을 때 전송됩니다. |
| AFS 거부 트랜잭션 |
afs_reject |
AFS 확인 중에 트랜잭션이 거부된 경우 전송. |
| AFS 업데이트된 차단 목록 |
afs_black_list |
AFS 차단 목록이 업데이트될 때 보냅니다. |
| 정기 결제 생성 |
create_subscription |
유저가 정기 결제를 만들면 보냅니다. |
| 업데이트된 정기 결제 |
update_subscription |
정기 결제가 갱신되거나 변경되었을 때 보냅니다. |
| 취소된 정기 결제 |
cancel_subscription |
정기 결제가 취소되었을 때 보냅니다. |
| 비갱신 정기 결제 |
non_renewal_subscription |
상태가 비갱신으로 설정되면 보냅니다. |
| 결제 계정 추가 |
payment_account_add |
사용자가 결제 계정을 추가하거나 저장할 때 보냅니다. |
| 결제 계정 제거 |
payment_account_remove |
사용자가 저장된 계정에서 결제 계정을 제거할 때 보냅니다. |
| 웹 상점에서 사용자 유효성 검사 |
- |
사용자가 게임에 존재하는지 확인하기 위해 웹 상점에서 전송됩니다. |
| 파트너 측의 카탈로그 개인 설정 |
partner_side_catalog |
사용자가 스토어와 상호작용할 때 전송됩니다. |
| 주문 결제 성공 |
order_paid |
주문이 결제되면 전송됩니다. |
| 주문 취소 |
order_canceled |
주문이 취소되면 전송됩니다. |
| 분쟁 |
dispute |
새로운 분쟁이 열리면 전송됩니다. |
Version: 1.0
## Servers
```
https://api.xsolla.com/merchant/v2
```
## Download OpenAPI description
[웹훅](https://xsolla.redocly.app/_bundle/@l10n/ko/webhooks/index.yaml)
## 사용자 유효성 검사
### 사용자 검색
- [POST user-search](https://xsolla.redocly.app/ko/webhooks/user-validation/user-search.md): Public User ID는 User ID와 달리 사용자를 고유하게 식별하고 사용자에게 알려진 매개 변수입니다(Public User ID는 이메일, 화면 이름 등일 수 있음). 엑솔라는 게임 스토어 외부(예: 현금 키오스크를 통한 구매 등)에서 구매가 이루어질 때 user_search 유형이 포함된 웹훅을 전송합니다.
### 사용자 유효성 검사
- [POST user-validation](https://xsolla.redocly.app/ko/webhooks/user-validation/user-validation.md): 엑솔라는 사용자가 게임에 등록되어 있는지 확인하기 위해 user_validation 유형이 포함된 웹훅을 웹훅 URL로 전송합니다. 이
요청은 결제 프로세스의 일부이며 여러 번 전송됩니다.
* 사용자가 결제 UI에서 결제 방법을 선택한 경우
* 사용자가 결제 양식에 데이터를 입력한 경우(예: PayPal을 통해 결제할 경우 은행 카드 데이터 또는 우편번호)
* 사용자가 지금 지불을 클릭하여 결제를 진행하는 경우
* 결제 프로세스가 완료되고 거래 상태가 done로 변경되는 경우
어떤 결제 방법으로 지불을 진행하여도 요청이 전송됩니다.
관리자 페이지에 웹훅 URL을 저장하면 웹훅에서 자세한 정보를 수신할 수 있는 권한을 부여할 수 있습니다. 이렇게 하려면 프로젝트 설정
>웹훅> 고급 설정 섹션의 관리자 페이지에서 필요한 토글을 활성화로 설정하십시오.
참고
2025년 1월 22일 또는 그 이전에 관리자 페이지에 등록한 경우, 프로젝트 설정 >웹훅 > 테스트 > 결제 > 고급 설정 섹션에서 토글을 찾을 수 있습니다.
토글
설명
민감한 데이터 없이 필수 사용자 매개 변수만 전송
사용자에 대한 다음 정보만 웹훅에서 전달됩니다.ID국가
사용자 정의 매개 변수 전송
사용자 정의 토큰 매개 변수 관련 정보가 웹훅에서 전달됩니다.
### 웹 상점에서 사용자 유효성 검사
- [POST user-validation-in-webshop](https://xsolla.redocly.app/ko/webhooks/user-validation/user-validation-in-webshop.md): 엑솔라는 사용자가 게임에 존재하는지 확인하기 위해 웹샵 사이트에서 웹훅을 전송합니다. 웹훅이 다음 IP 주소 '34.102.38.178'로부터 전송되었습니다.
참고
웹훅은 웹샵 솔루션에서 사용자 확인에만 사용됩니다. 웹사이트 빌더에서 웹훅을 구성하는 방법에 대한 자세한 정보는 지침을 참조해 주세요.
## 결제
### 결제 계정 추가
- [POST add-payment-account](https://xsolla.redocly.app/ko/webhooks/payments/add-payment-account.md): 엑솔라는 사용자가 게임 내에서 상품을 구매할 때 결제 계정을 추가하거나 결제 계정을 저장할 때마다 웹훅 URL에 payment_account_add 타입의 웹훅을 전송합니다. 이 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
### 부분 환불
- [POST partial-refund](https://xsolla.redocly.app/ko/webhooks/payments/partial-refund.md): 부분 환불이 이루어지면 엑솔라는 partial_refund 유형이 포함된 웹훅의 취소된 거래에 대한 세부 정보를 웹훅 URL로 전송합니다.
부분 환불 절차에 대한 자세한 내용은 지침을 참조해 주세요.
관리자 페이지에 웹훅 URL을 저장하면 웹훅에서 자세한 정보를 수신할 수 있는 권한을 부여할 수 있습니다. 이렇게 하려면 프로젝트 설정
>웹훅> 고급 설정 섹션의 관리자 페이지에서 다음 토글을 활성화로 설정하십시오.
참고
2025년 1월 22일 또는 그 이전에 관리자 페이지에 등록한 경우, 프로젝트 설정 >웹훅 > 테스트 > 결제 > 고급 설정 섹션에서 토글을 찾을 수 있습니다.
토글
설명
저장된 결제 방식을 사용한 트랜잭션에 대한 정보 표시
정보는 웹훅의 다음 사용자 정의 매개 변수에서 전달됩니다.saved_payment_method:0 - 저장된 결제 방식이 사용되지 않음1 - 현재 결제를 진행할 때 결제 방식이 저장됨2 - 이전에 저장한 결제 방식이 사용됨payment_type:1 - 일회성 결제2 - 반복 결제
환불 코드:
코드
환불 이유
설명
1
사용자 요청/게임 요청에 의한 취소
관리자 페이지에서 취소가 요청된 경우 사용됩니다.
3
연동 오류
엑솔라와 게임 사이의 연동에 문제가 있을 경우 사용됩니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
5
테스트 결제
테스트 트랜잭션인 경우 사용되며 이후 취소로 이어집니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
7
PS에서 전송된 사기 참고
결제 시스템에서 결제가 거부되었습니다. PS에서 잠재적 사기를 감지했습니다.권장 사항: 사용자를 차단 목록에 추가하세요.
9
사용자 요청에 의한 취소
사용자의 요청에 의한 환불 사유입니다. 어떤 이유로 사용자가 게임 또는 구매에 만족하지 못한 못하였음을 의미합니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
10
게임 요청에 의한 취소
게임을 통해 취소를 요청한 경우 사용됩니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
### 결제
- [POST payment](https://xsolla.redocly.app/ko/webhooks/payments/payment.md): 사용자가 결제를 완료하면 엑솔라는 payment 유형이 포함된 웹훅의 결제 세부 정보를 웹훅 URL로 전송합니다.
예상되는 응답 코드는 Responses 섹션에 설명되어 있지만 다른 응답 코드도 사용할 수 있습니다.
응답 코드
설명
200, 201, 204
성공적인 응답입니다.
4xx
오류가 발생했습니다. 예를 들어, 지정된 사용자를 찾을 수 없거나 잘못된 서명이 전달된 경우입니다.
5xx
일시적인 서버 오류입니다. 이 응답이 수신되면 엑솔라는 자동으로 웹훅 전송을 재시도하며, 수신자가 수신을 확인할 때까지 시도 간격을 점차 늘립니다. 최대 재시도 횟수는 48시간 동안 12회입니다.
관리자
페이지에서 웹훅 URL을 저장할 때 웹훅을 통해 추가 정보를 수신하도록 설정할 수도 있습니다.
참고
2025년 1월 22일 또는 그 이전에 관리자 페이지에 등록한 경우, 설정 >웹훅 > 테스트 > 결제 > 고급 설정 섹션에서 토글을 찾을 수 있습니다.
토글
설명
저장된 결제 계정에 대한 정보 표시
저장된 결제 방식에 대한 정보는 payment_account 사용자 정의 개체에서 전달됩니다.
저장된 결제 방식을 사용한 트랜잭션에 대한 정보 표시
정보는 웹훅의 다음 사용자 정의 매개 변수에서 전달됩니다.saved_payment_method:0 - 저장된 결제 방식이 사용되지 않음1 - 현재 결제를 진행할 때 결제 방식이 저장됨2 - 이전에 저장한 결제 방식이 사용됨payment_type:1 - 일회성 결제2 - 반복 결제
주문 개체를 웹훅에 추가
주문 관련 정보는 결제 웹훅의 order 개체에서 전달됩니다.
민감한 데이터 없이 필수 사용자 매개 변수만 전송
사용자에 대한 다음 정보만 웹훅에서 전달됩니다.ID국가
카드 BIN 및 접미사 표시
은행 카드 번호에 대한 다음 정보가 웹훅에서 전달됩니다.card_bin 매개 변수의 처음 6자리card_suffix의 마지막 4자리
카드 브랜드 표시
결제에 사용된 카드의 브랜드. 예: Mastercard 또는 Visa.
국가별 WHC 및 사용자 확보 수수료를 표시합니다.
payment_details.country_wht 및 payment_details.user_acquisition_fee 개체가 웹훅에 전달됩니다. 이 토글은 기본적으로 켜져 있습니다.
3DS 정보를 전송합니다.
3D Secure 인증에 대한 데이터를 포함하는 cards 개체가 웹훅을 통해 전달됩니다.
참고
웹훅으로 전송되는 필드 세트는 관리자 페이지에서 구성한 고급 설정엑솔라 측에 구성한 사용자 지정 설정에 따라 달라집니다. 질문이 있는 경우, 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일을 보내십시오.
### 거부된 결제
- [POST payment-declined](https://xsolla.redocly.app/ko/webhooks/payments/payment-declined.md): 결제 시스템에서 트랜잭션이 거부되면 엑솔라는 구성된 웹훅 URL 측의 ps_declined 유형 웹훅에 트랜잭션 세부 정보를 전송합니다.
웹훅은 승인 또는 결제 처리 단계에서 전송됩니다. 이 경우, payment\
order_paid 웹훅이 전송되지 않았습니다.
결제 시스템이 거부되는 일반적인 이유:
* 카드 승인에 실패(예: 기술적 오류 또는 은행의 응답이 없어 결제 시스템이 승인 절차를 완료하지 못함)했거나 거부되었습니다(예: 은행에서
응답했지만 자금이 부족하거나 카드 정보가 유효하지 않아 트랜잭션을 거부함).
* 3-D Secure 검증에 실패했거나, 완료되지 않았거나, 사용자 확인 시간이 초과되었습니다.
* 계좌 폐쇄 또는 유효하지 않은 카드 번호 등 되돌릴 수 없는 오류로 인해 처리업체 또는 매입 은행이 일시적으로 접속이 불가능하거나 강제 거부
메시지를 반환합니다. 근본적인 문제를 해결하지 않고 재시도하면 트랜잭션이 성공적으로 이루어지지 않습니다.
다음과 혼동되어서는 안 됩니다.
* 사기 방지 거부는 afs_reject 웹훅을 통해 보고됩니다.
* 성공적인 결제 후 환불 및 부분 환불은
환불 및
partial_refund 웹훅을 통해 보고됩니다.
참고
ps_declined 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
### 환불
- [POST refund](https://xsolla.redocly.app/ko/webhooks/payments/refund.md): 결제가 취소되면 엑솔라는 취소된 거래 내역을 refund 유형의 웹훅으로 웹훅 URL로 전송합니다.
웹훅 재시도 메커니즘은 환불을 시작한 사람에 따라 달라집니다:
* 환불이 귀하 측에서 요청된 경우 웹훅은 재전송되지 않습니다. 웹훅에 대한 응답 여부와 관계없이 결제 금액은 사용자에게 환불됩니다.
* 제3자(예: 결제 시스템 또는 엑솔라 고객 지원팀)가 환불을 요청했고 웹훅에 대한 응답으로 5xx 상태 코드가 반환된 경우, 웹훅은 점점
더 빠른 간격으로 재전송됩니다. 재시도 횟수는 첫 번째 시도 후 48시간 이내에 최대 12회입니다.
환불 절차에 대한 자세한 내용은 지침을 참조하세요.
주의
다음 조건을 모두 충족하는 경우에도 사용자에게 결제가 환불됩니다:환불이 엑솔라 측에서 요청한 경우.웹훅에 대한 응답으로, 4xx 상태 코드가 반환되거나 모든 재시도 후 응답을 받지 않거나 5xx 상태 코드가 반환된 경우.
관리자
페이지에서 웹훅 URL을 저장할 때 웹훅을 통해 추가 정보를 수신하도록 설정할 수도 있습니다.
참고
2025년 1월 22일 또는 그 이전에 관리자 페이지에 등록한 경우, 설정 >웹훅 > 테스트 > 결제 > 고급 설정 섹션에서 토글을 찾을 수 있습니다.
토글
설명
저장된 결제 방식을 사용한 트랜잭션에 대한 정보 표시
정보는 웹훅의 다음 사용자 정의 매개 변수에서 전달됩니다.saved_payment_method:0 - 저장된 결제 방식이 사용되지 않음1 - 현재 결제를 진행할 때 결제 방식이 저장됨2 - 이전에 저장한 결제 방식이 사용됨payment_type:1 - 일회성 결제2 - 반복 결제
환불 사유에 대한 정보를 표시합니다.
환불 사유에 대한 자세한 정보입니다.
환불 코드:
코드
환불 이유
설명
1
사용자 요청/게임 요청에 의한 취소
관리자 페이지에서 취소가 요청된 경우 사용됩니다.
2
지불 거절
거래 지불 거절 요청되었습니다.
3
연동 오류
엑솔라와 게임 사이의 연동에 문제가 있을 경우 사용됩니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
4
잠재적 사기
부정 결제가 의심됩니다.권장사항: 사용자를 차단 목록에 추가하세요.
5
테스트 결제
테스트 트랜잭션인 경우 사용되며 이후 취소로 이어집니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
6
사용자 인보이스 만료
후불 결제 방식에 의해 트랜잭션이 이뤄진 경우 사용됩니다.
7
PS에서 전송된 사기 참고
결제 시스템에서 결제가 거부되었습니다. PS에서 잠재적 사기를 감지했습니다.권장 사항: 사용자를 차단 목록에 추가하세요.
8
PS 요청에 의한 취소
결제시스템이 취소를 요청한 경우 사용됩니다.권장사항: 사용자를 차단 목록에 추가하지 마세요.
9
사용자 요청에 의한 취소
사용자의 요청에 의한 환불 사유입니다. 어떤 이유로 사용자가 게임 또는 구매에 만족하지 못한 못하였음을 의미합니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
10
게임 요청에 의한 취소
게임을 통해 취소를 요청한 경우 사용됩니다.권장 사항: 사용자를 차단 목록에 추가하지 마세요.
11
계정 소유자가 사기 신고를 위해 전화한 경우
계정 소유자가 본인 미사용 결제로 신고한 경우입니다.
12
지불 거절 사기
우호적인 부정결제에 대한 메시지를 수신했을 때 사용됩니다.
13
복제
동일 인보이스에 대하여 거래 복제.
### 결제 계정 제거
- [POST remove-payment-account](https://xsolla.redocly.app/ko/webhooks/payments/remove-payment-account.md): 사용자가 저장된 계정에서 결제 계정을 제거하면 엑솔라는 payment_account_remove 유형이 포함된 웹훅을 웹훅 URL로 보냅니다. 이 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
## 결합된 웹훅
### 주문 취소(결제 및 거래 세부 정보 포함)
- [POST order-cancellation](https://xsolla.redocly.app/ko/webhooks/combined-webhooks/order-cancellation.md): 사용자, 파트너 또는 자동으로 결제가 취소된 경우 엑솔라 측에서 지정된 URL로 order_canceled 웹훅을
전송합니다. 웹훅에는 반품된 아이템 정보, 결제 데이터, 취소된 주문의 세부 정보가 포함되어 있습니다.
결제에 실패할 경우 웹훅이 전송되지 않습니다. 예:
* 결제 UI가 열렸지만 사용자가 주문을 결제하지 않은 경우
* 결제 UI가 열렸지만 결제 중 오류가 발생한 경우
권장되는 웹훅 처리 시간은 3초 이내입니다.
### 주문 결제 성공(결제 및 거래 세부 정보 포함)
- [POST successful-order-payment](https://xsolla.redocly.app/ko/webhooks/combined-webhooks/successful-order-payment.md): 엑솔라는 사용자가 주문에 대한 결제를 성공적으로 완료하면 지정된 URL로 order_paid 웹훅을 전송합니다.
order_paid 웹훅에는 구매한 아이템, 결제 데이터 및 거래 세부 정보에 대한 정보가 포함되어 있습니다.
결제가 성공하지 못한 경우 order_paid 웹훅이 전송되지 않습니다. 예:
* 결제 양식이 열렸지만 사용자가 주문을 결제하지 않았습니다.
* 결제창이 열렸으나 결제 중 오류가 발생했습니다.
order_paid 웹훅의 처리 시간은 3초 이내로 하는 것이 좋습니다.
참고
웹훅에 전송되는 필드 세트는 프로젝트 설정 > 웹훅 > 고급 설정 섹션의 관리자 페이지에서 구성한 설정엑솔라 측에서 구성한 설정 설정에 따라 달라집니다.질문이 있을 경우, 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일을 보내십시오.
응답 섹션에서 예상 답변을 볼 수 있습니다. 다른 응답 코드를 사용할 수도 있습니다. 응답 코드 및 자동 결제 환불 기능 연결에
따른 엑솔라 측의 웹훅 처리 로직은 다음과 같습니다.
응답 코드
자동 결제 환불이 비활성화됨(기본값)
자동 결제 환불이 비활성화됨
400, 401, 402, 403, 404, 409, 422, 415
작업 없음
사용자에게 자동 환불
200, 201, 204
작업 없음
작업 없음
웹훅에 다른 코드 또는 응답 없음
5분 간격으로 2번, 15분 간격으로 7번, 60분 간격으로 10번 등 지정한 시간 간격으로 웹훅을 여러 번 전송합니다.
5분 간격으로 2번, 15분 간격으로 7번, 60분 간격으로 10번 등 지정한 시간 간격으로 웹훅을 여러 번 전송합니다. 모든 웹훅을 전송해도 응답을 성공적으로 받지 못하면 사용자에게 환불이 자동으로 이루어집니다.
자동 환불 기능을 연결하려면 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일 전송하십시오.
## 개별 웹훅
### 주문 취소(결제 및 거래 세부 정보 없음)
- [POST order-cancellation-separate](https://xsolla.redocly.app/ko/webhooks/separate-webhooks/order-cancellation-separate.md): 사용자, 파트너 또는 자동으로 결제가 취소된 경우 엑솔라 측에서 지정된 URL로 order_canceled 웹훅을
전송합니다. 웹훅에는 반품된 아이템 정보와 취소된 주문의 세부 정보가 포함되어 있습니다.
결제에 실패할 경우 웹훅이 전송되지 않습니다. 예:
* 결제 UI가 열렸지만 사용자가 주문을 결제하지 않은 경우
* 결제 UI가 열렸지만 결제 중 오류가 발생한 경우
권장되는 웹훅 처리 시간은 3초 이내입니다.
### 주문 결제 성공(결제 및 거래 세부 정보 없음)
- [POST successful-order-payment-separate](https://xsolla.redocly.app/ko/webhooks/separate-webhooks/successful-order-payment-separate.md): 엑솔라는 다음 조건이 충족되면 지정된 URL로 order_paid 웹훅을 전송합니다.
1. 사용자가 주문을 성공적으로 결제했습니다.
2. 엑솔라는 결제 웹훅이 성공적으로 처리되었다는 응답을 받았습니다.
order_paid 웹훅에는 구매한 아이템 및 거래 세부 정보에 대한 정보가 포함되어 있습니다.
다음의 경우 order_paid 웹훅이 전송되지 않습니다.
* 결제에 실패했습니다. 결제 실패 예시:
* 결제 양식이 열렸지만 사용자가 주문을 결제하지 않았습니다.
* 결제창이 열렸으나 결제 중 오류가 발생했습니다.
* 결제 웹훅을 성공적으로 처리했다는 응답을 받지 못했습니다.
order_paid 웹훅의 처리 시간은 3초 이내로 하는 것이 좋습니다.
응답 섹션에서 예상 답변을 볼 수 있습니다. 다른 응답 코드를 사용할 수도 있습니다. 응답 코드 및 자동 결제 환불 기능 연결에
따른 엑솔라 측의 웹훅 처리 로직은 다음과 같습니다.
응답 코드
자동 결제 환불이 비활성화됨(기본값)
자동 결제 환불이 비활성화됨
400, 401, 402, 403, 404, 409, 422, 415
작업 없음
사용자에게 자동 환불
200, 201, 204
작업 없음
작업 없음
웹훅에 다른 코드 또는 응답 없음
5분 간격으로 2번, 15분 간격으로 7번, 60분 간격으로 10번 등 지정한 시간 간격으로 웹훅을 여러 번 전송합니다.
5분 간격으로 2번, 15분 간격으로 7번, 60분 간격으로 10번 등 지정한 시간 간격으로 웹훅을 여러 번 전송합니다. 모든 웹훅을 전송해도 응답을 성공적으로 받지 못하면 사용자에게 환불이 자동으로 이루어집니다.
자동 환불 기능을 연결하려면 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일 전송하십시오.
## 개인화 웹훅
### 파트너 측의 카탈로그 개인 설정
- [POST personalized-partner-catalog](https://xsolla.redocly.app/ko/webhooks/personalization/personalized-partner-catalog.md): 사용자가 스토어와 상호 작용하면 엑솔라는 웹훅 URL로 사용자 및 프로젝트 매개 변수가 포함된
partner_side_catalog 웹훅을 보냅니다.
응답으로 사용자가 사용할 수 있는 item_id 또는 아이템 SKU 목록을 반환합니다. 이 경우 특정 사용자가 특정
제품을 지정된 횟수만큼 구매할 수 있다는 정보도 포함할 수 있습니다. 이 기능을 사용하여 사용자가 장바구니에 추가하고 구매할 수 있는 제품의
수와 유형을 제어할 수 있습니다.
알림
웹훅 처리 시 다음 제한 사항을 고려하세요.웹훅은 3초 이내에 처리되어야 합니다. 처리 시간이 3초를 초과하면 가상 아이템 목록 가져오기, 결제 토큰 생성,주문 생성 API 호출 시 오류를 반환합니다.웹훅 응답 크기는 64KB를 초과하지 않아야 합니다. 이 제한을 초과하는 응답은 처리되지 않으며, 사용자는 빈 카탈로그만 보게 되고 아이템을 구매할 수 없습니다. 최대 응답 크기를 변경하려면 계정 관리자에게 문의하거나 다음 이메일 주소로 연락하십시오csm@xsolla.com.
## 부정 결제 방지
### 부정 결제 방지 차단 목록 업데이트
- [POST afs-rejected-blocklist](https://xsolla.redocly.app/ko/webhooks/anti-fraud/afs-rejected-blocklist.md): 부정 결제 방지 시스템 차단 목록이 업데이트되면(매개 변수 추가 또는 제거) 엑솔라는 웹훅 URL로 afs_black_list 유형의 웹훅을 전송합니다. 매개 변수 추가는 엑솔라 측에서 자동으로 또는 요청 시 수행됩니다. 매개 변수 제거는 요청 시에만 가능합니다. 이 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
### 부정 결제 방지 시스템에서 거부한 트랜잭션
- [POST afs-rejected-transaction](https://xsolla.redocly.app/ko/webhooks/anti-fraud/afs-rejected-transaction.md): 부정 결제 방지 시스템 검사 중에 트랜잭션이 거부되면 엑솔라는 afs_reject 유형이 포함된 웹훅의 트랜잭션 세부 정보를 웹훅 URL로
보냅니다. 이 웹훅을 수신하려면 고객 성공 관리자에게 문의하거나 csm@xsolla.com으로 이메일을 보내십시오.
관리자 페이지에 웹훅 URL을 저장하면 웹훅에서 자세한 정보를 수신할 수 있는 권한을 부여할 수 있습니다. 이렇게 하려면 프로젝트 설정
>웹훅> 고급 설정 섹션의 관리자 페이지에서 다음 토글을 활성화로 설정하십시오.
참고
2025년 1월 22일 또는 그 이전에 관리자 페이지에 등록한 경우, 프로젝트 설정 >웹훅 > 테스트 > 결제 > 고급 설정 섹션에서 토글을 찾을 수 있습니다.
토글
설명
저장된 결제 방식을 사용한 트랜잭션에 대한 정보 표시
정보는 웹훅의 다음 사용자 정의 매개 변수에서 전달됩니다.saved_payment_method:0 - 저장된 결제 방식이 사용되지 않음1 - 현재 결제를 진행할 때 결제 방식이 저장됨2 - 이전에 저장한 결제 방식이 사용됨payment_type:1 - 일회성 결제2 - 반복 결제
### 분쟁
- [POST dispute](https://xsolla.redocly.app/ko/webhooks/anti-fraud/dispute.md): 새 분쟁이 발생하거나 분쟁 상태가 변경되면 엑솔라는 해당 dispute 유형이 포함된 웹훅을 웹훅 URL로 보냅니다. 이 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
## 정기 결제
### 취소된 정기결제
- [POST canceled-subscription](https://xsolla.redocly.app/ko/webhooks/subscriptions/canceled-subscription.md): 정기 결제가 취소되면 엑솔라는 cancel_subscription 유형이 포함된 웹훅을 웹훅 URL로 전송합니다.
### 정기결제 생성
- [POST created-subscription](https://xsolla.redocly.app/ko/webhooks/subscriptions/created-subscription.md): 사용자가 정기 결제를 생성하면 엑솔라는 create_subscription 유형이 포함된 웹훅을 웹훅 URL로 전송합니다.
### 비갱신 정기결제
- [POST nonrenewing-subscription](https://xsolla.redocly.app/ko/webhooks/subscriptions/nonrenewing-subscription.md): 정기 결제 상태가 비갱신으로 설정된 경우 엑솔라는 non_renewal_subscription 유형이 포함된 웹훅을 웹훅 URL로 보냅니다. 이 웹훅을 수신하려면 고객 성공 매니저에게 문의하거나 csm@xsolla.com으로 이메일을 보내주세요.
### 업데이트된 정기결제
- [POST updated-subscription](https://xsolla.redocly.app/ko/webhooks/subscriptions/updated-subscription.md): 정기 결제의 일부 매개 변수(plan_id, date_next_charge)가 변경된 경우, 그리고 정기 결제가 갱신될 때마다 엑솔라는 update_subscription 유형이 포함된 웹훅을 웹훅 URL로 전송합니다.