--- title: "웹훅 엔드포인트에서 Tokenz 이벤트 수신" description: "웹훅 엔드포인트에서 Tokenz 계정의 이벤트를 수신하여 연동 시스템이 자동으로 후속 작업을 실행하도록 하세요." source: "https://docs.tokenz.one/ko-KR/v1/checkout/webhooks" api_version: "v1" locale: "ko-KR" version_status: "legacy" docs_stage: "prod" --- # 웹훅 엔드포인트에서 Tokenz 이벤트 수신 웹훅 엔드포인트에서 Tokenz 계정의 이벤트를 수신하여 연동 시스템이 자동으로 후속 작업을 실행하도록 하세요. **금액 형식:** 웹훅 페이로드의 금액 값(`amount` 필드 등)은 각 통화의 최소 단위로 표시됩니다. 통화별 정확한 형식은 [지원 통화](https://docs.tokenz.one/ko-KR/v1/checkout/currency)를 참고하세요. ## 웹훅을 사용하는 이유 Tokenz Checkout을 연동할 때 계정에서 이벤트가 발생하면 애플리케이션이 이를 수신하여 백엔드에서 필요한 작업을 실행해야 합니다. 웹훅 이벤트를 사용하려면 웹훅 엔드포인트를 등록해야 합니다. 등록 후 Tokenz 계정에서 이벤트가 발생하면 애플리케이션의 웹훅 엔드포인트로 실시간 이벤트 데이터를 전송합니다. Tokenz는 HTTPS를 통해 Event 객체를 담은 JSON 페이로드를 전송합니다. 결제 결과 알림을 빠짐없이 받을 수 있도록 Checkout 리디렉션 처리와 함께 웹훅을 구현하는 것을 강력히 권장합니다. ## 이벤트 객체 이벤트가 발생하면 Tokenz는 새 Event 객체를 생성합니다. 하나의 API 요청으로 여러 이벤트가 발생할 수 있습니다. Tokenz 계정에 웹훅 엔드포인트를 등록하면 Tokenz가 애플리케이션에서 호스팅하는 엔드포인트로 POST 요청에 Event 객체를 담아 자동 전송합니다. 이벤트를 수신한 후 백엔드 작업을 실행할 수 있습니다. 예를 들어 `order.succeeded` 이벤트를 받으면 구매한 상품의 다운로드 링크를 보내거나 고객 잔액을 충전할 수 있습니다. 웹훅으로 전송되는 Event 객체는 변경된 객체의 스냅샷입니다. 웹훅에는 항상 이벤트가 발생한 전체 객체와 이벤트 메타데이터가 포함됩니다. ### 이벤트 페이로드 예제 다음은 주문 성공 시 전송되는 이벤트의 예제입니다. ```json { "id": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6", "object": "order.succeeded", "createdAt": "2026-01-15T09:30:00Z", "test": true, "eventData": { "type": "order", "version": "v1", "data": { "order": { "id": "order_1D5xA9BnKfv_t", "object": "order", "status": "succeeded", "amount": { "amount": 3700, "currency": "JPY" }, "items": [ { "id": "item_1D6F8mR5TnK_t", "detail": { "product": { "price": { "amount": 1200, "currency": "JPY" }, "quantity": 3, "label": "ひとにぎりのエメラルド", "description": "80+8", "images": [ "https://images.ctfassets.net/z82qbo7cv7ia/1dWPbk5Qx2M1Qikj6Knyuc/e37b2c26829c0d30793a348ae3adb3b0/fake-pass.webp" ] } } }, { "id": "item_1xejV7puGeK_t", "detail": { "product": { "price": { "amount": 100, "currency": "JPY" }, "quantity": 1, "label": "Diamond", "description": "", "images": [], "sku": "sku_103843dfjhdfgiu", "taxCategory": "VIRTUAL_CURRENCY" } } } ], "description": "Game items purchase", "reference": "ORDER_2024_001", "test": true, "expiresAt": "2024-12-31T23:59:59Z", "createdAt": "2024-01-15T10:00:00Z", "updatedAt": "2024-01-15T10:05:30Z" } } } } ``` ### 라이브 및 테스트 모드 하나의 엔드포인트에서 라이브 및 테스트 모드를 모두 처리하면 두 모드의 이벤트를 모두 수신할 수 있습니다. `test` 플래그로 객체가 어느 모드에 속하는지 확인하고 적절하게 처리하세요. ### 버전 `version`은 이벤트의 API 버전을 나타내며, 포함된 `data.object`의 구조를 결정합니다. ### 이벤트 유형 | 유형 | 설명 | | --- | --- | | `order.created` | [Checkout Session 생성](https://docs.tokenz.one/ko-KR/v1/api/main) 엔드포인트를 통해 새 주문이 생성되었습니다. | | `order.succeeded` | 고객이 주문 결제를 완료했습니다. 고객에게 아이템을 지급할 수 있습니다. | | `order.expired` | 주문이 만료되었습니다. | | `order.canceled` | 주문이 취소되었습니다. | | `order.failed` | 주문 결제에 실패했습니다. | | `refund.created` | 환불이 생성되었습니다. | | `refund.failed` | 환불에 실패했습니다. | | `dispute.created` | 분쟁이 생성되었습니다. | | `dispute.closed` | 분쟁이 종료되었습니다. | | `redemption.completed` | 기프트 코드를 사용했거나 무료 아이템을 수령했습니다. `kind`로 흐름을 구분합니다(`source`는 더 이상 권장되지 않음). 무료 아이템 수령에서는 `code`가 생략됩니다. | ## 재시도와 멱등성 엔드포인트는 2xx 응답으로 웹훅 수신을 확인해야 합니다. 다른 상태 코드를 반환하거나 응답 시간이 초과되거나 접근할 수 없으면 Tokenz가 최대 3일 동안 자동으로 재전송합니다. 초기 재시도는 전송 실패 후 약 5초, 15초, 30초에 이루어집니다. 이후에는 간격이 점점 길어집니다. 재시도 시점은 약간 달라질 수 있으므로 이후 재시도의 정확한 일정에 의존하지 마세요. 테스트 모드에는 다른 재시도 정책이 적용될 수 있으므로 이를 사용하여 라이브 모드의 재시도 시점을 측정하거나 검증하지 마세요. 2xx 응답을 반환하면 해당 이벤트의 재시도가 중단됩니다. 같은 이벤트를 여러 번 받거나 이벤트 순서가 바뀔 수 있습니다. 이벤트를 안전하게 수신하면 바로 2xx로 응답하고, 오래 걸리는 작업은 비동기로 처리하세요. 이벤트의 최상위 `id`를 멱등성 키로 사용하세요. ## 문제 해결: 이벤트가 수신되지 않는 경우 대부분의 경우 “웹훅이 도착하지 않았다”는 것은 Tokenz가 **전송했지만** 엔드포인트가 **거부했다**는 뜻입니다. Tokenz는 `2xx` 이외의 응답, 시간 초과, 접근 불가를 전송 실패로 간주하고 최대 3일 동안 자동 재시도합니다. 따라서 판매자 측에서는 아무것도 도착하지 않은 것처럼 보이지만 Tokenz에서는 같은 전송이 반복해서 실패할 수 있습니다(예: 계속되는 `HTTP 400`). Tokenz는 엔드포인트별 전송 로그를 제공하지 않으므로 자체 엔드포인트에서 진단하세요. **1. 엔드포인트가 반환한 HTTP 상태를 확인하세요.** Tokenz가 받는 응답과 같습니다. 서버의 액세스 로그와 오류 로그에서 수신 `POST` 요청을 확인하세요. - `2xx` — 이벤트가 전송되고 수신 확인되었습니다. 시스템에서 후속 작업이 실행되지 않았다면 전송 문제가 아니라 응답 _이후_ 핸들러 처리의 문제입니다. - `400`, `401`, `403` — 이벤트는 수신했지만 엔드포인트가 거부했습니다(아래 참고). - `5xx` 또는 시간 초과 — 핸들러에서 오류가 발생했거나 응답이 너무 느립니다. **2. `400`을 반환한다면 먼저 서명 검증을 확인하세요.** 가장 흔한 원인입니다. - **원본 요청 본문으로 검증하세요.** 대부분의 프레임워크는 JSON을 파싱하고 다시 직렬화하여 바이트가 달라지므로 HMAC 검증에 실패합니다. 예를 들어 `express.raw()`로 원본 바이트를 읽고, 검증한 후 파싱하세요. [웹훅 엔드포인트 보안 설정](https://docs.tokenz.one/ko-KR/v1/checkout/webhooks-get-started#3.-secure-your-webhook-endpoint)을 참고하세요. - **올바른 서명 비밀키를 사용하세요.** 엔드포인트 등록 시 한 번만 표시되며 해당 엔드포인트 전용입니다. 교체 전 비밀키나 오타가 있는 비밀키를 사용하면 모든 이벤트 검증에 실패합니다. - **테스트 및 라이브 모드를 맞추세요.** 테스트 이벤트에 라이브 서명 비밀키를 사용하거나 그 반대로 사용하면 일치하지 않습니다. 두 모드를 하나의 엔드포인트에서 처리한다면 이벤트의 `test` 플래그로 비밀키를 선택하세요. - **서버 시간 차이를 확인하세요.** 타임스탬프 허용 오차를 5분으로 적용할 때 서버 시간이 크게 어긋나 있으면 유효한 이벤트도 거부할 수 있습니다. **3. 2xx 이외의 응답을 반환하는 다른 원인:** - 엔드포인트 앞의 방화벽, WAF 또는 IP 허용 목록이 Tokenz 요청을 차단합니다. - 엔드포인트가 외부에서 **HTTPS**로 접근되지 않거나, 대시보드에 등록한 URL이 잘못되었거나 다른 환경을 가리킵니다. - 요청에 응답하기 전에 오래 걸리는 작업을 수행하면 응답 시간이 초과될 수 있습니다. 먼저 `2xx`로 수신을 확인한 후 해당 작업을 비동기로 처리하세요. **4. 전송을 별도로 확인하세요.** 엔드포인트(또는 그 사본)가 [Webhook.site](https://webhook.site/)를 가리키도록 설정하여 Tokenz 전송 여부와 정확한 페이로드·헤더를 확인하고, 테스트 모드 결제로 이벤트를 발생시키세요. 엔드포인트가 `2xx`를 반환하면 재시도가 중단됩니다. 이미 처리한 이벤트가 재전송될 수 있으므로 핸들러의 멱등성을 유지하세요. 최상위 `id`를 멱등성 키로 사용하면 재전송으로 주문이 중복 이행되는 것을 방지할 수 있습니다.