# 웹훅이 오지 않을 때

Source: https://help.didit.me/ko/integration/webhook-troubleshooting
Updated: 2026-10-12

웹훅이 오지 않으면 대상의 Deliveries 탭부터 확인하세요. 보내지 않았다면 구독 설정, 보냈는데 실패했다면 응답 코드가 원인을 알려줍니다.

먼저 대상의 **Deliveries** 탭을 확인하세요. Didit이 전송을 시도조차 하지 않았다면 구독이나 대상 설정 문제입니다. 시도는 했지만 실패했다면 응답 코드가 원인을 알려줍니다. **404**는 해당 URL에서 라우트에 접근할 수 없었다는 뜻이고, 서명 불일치는 잘못된 바이트를 해시한 것입니다.

## 1단계: Didit이 실제로 전송을 시도했는가

개발자와 웹훅에서 엔드포인트를 선택하고 전달 목록의 요청과 응답을 읽으세요. 수정 후 재전송하세요. 애플리케이션, 환경, 이벤트 구독과 엔드포인트 활성 상태를 확인하세요.

![대상별 전송 상태를 보여주는 Didit 콘솔의 웹훅 페이지](https://help.didit.me/screenshots/webhooks-light.webp)

*누락된 이벤트와 실패하는 엔드포인트를 구분하는 데 필요한 모든 것이 이 페이지에 있습니다.*

이 확인 하나로 문제를 절반으로 좁힐 수 있습니다.

- **시도 기록 없음** → 해당 대상에 대해 이벤트가 아예 생성되지 않았습니다. 2단계로 이동하세요.
- **시도 기록 있음, 실패** → Didit은 전송했지만 여러분 쪽이 거부했거나 수신하지 못했습니다. 3단계로 이동하세요.
- **시도 기록 있음, 2xx** → 정상적으로 전달되었습니다. 문제는 전송이 아니라 여러분의 핸들러 안에 있습니다.

## 2단계: 시도 기록이 없는 경우

가능성이 높은 순서대로 정리하면 다음과 같습니다.

1. **이벤트가 구독되어 있지 않습니다.** 와일드카드는 없으며 - 모든 이벤트 계열을 명시적으로 나열해야 합니다. 그리고 존재하지 않는 이름(`session.status.updated`, `kyc.completed`)을 구독하면 아무것도 받지 못한 채 조용히 지나갑니다. [이벤트 목록](https://help.didit.me/ko/integration/webhooks-basics)과 대조해 확인하세요.
2. **잘못된 애플리케이션.** 대상은 애플리케이션에 속합니다. 세션이 대상과 다른 애플리케이션에서 실행된다면 어떤 이벤트도 도달하지 않습니다. 모든 것이 올바르게 설정된 것처럼 보이는데도 문제가 생기는 가장 흔한 원인입니다.
3. **실제로 아무것도 바뀌지 않았습니다.** 웹훅은 변경이 있을 때 발생합니다. 상태가 그대로인 세션이나, 임계값을 넘는 결과가 없었던 AML 모니터링 재검토는 정상적으로 이벤트를 만들지 않습니다.
4. **기다리는 상태가 아직 발생하지 않았습니다.** In Progress 상태의 세션은 아직 끝나지 않았습니다. [세션이 끝나지 않을 때](https://help.didit.me/ko/verification-sessions/session-not-finished)를 참고하세요.

## 3단계: 전송을 시도했지만 실패한 경우

**404**는 요청이 도달했지만 해당 위치에 라우트가 없었다는 뜻입니다. 다음을 확인하세요.

- 후행 슬래시를 포함한 정확한 경로. `/hook`을 `/hook/`으로 리디렉션하는 프레임워크는 정상 작동하던 엔드포인트를 404나 본문 유실로 바꿔버릴 수 있습니다.
- URL이 공개적으로 접근 가능한지. 인터넷에서 접근할 수 없는 로컬이나 스테이징 호스트는 이런 식으로 실패합니다.
- 앱 앞단의 프록시, 로드 밸런서, 경로 기반 라우터가 해당 경로를 다른 곳으로 보내고 있지는 않은지.

**5xx**는 여러분의 핸들러가 예외를 던졌다는 뜻입니다. 실제로 무엇을 받았는지 확인할 수 있도록 파싱 전에 원본 본문을 로그로 남기세요.

**타임아웃**은 충분히 빠르게 응답하지 못했다는 뜻입니다. 먼저 2xx를 반환하고, 처리는 나중에 하세요.

**아무 응답도 없음 / 연결 거부**는 여러분의 엣지가 차단했다는 뜻입니다. Didit은 고정 IP **18.203.201.92**에서 `DiditWebhook/2.0` User-Agent로 전송합니다. Cloudflare나 기본 차단(default-deny) 정책의 WAF 뒤에 있다면, 수신 호스트명에 대해 해당 IP를 허용하세요.

## 흔한 사례: 자동 전송은 404, 그런데 Resend는 성공

이 사례는 이름을 붙일 만큼 자주 나옵니다. 자동 전송이 404로 실패한 뒤, 같은 이벤트에서 **Resend**를 클릭하면 성공합니다.

이 조합은 페이로드와 엔드포인트 모두 문제가 없다는 뜻이므로, 차이는 내용이 아니라 타이밍이나 경로에 있습니다. 다음을 확인하세요.

- 원래 전송 시점에 있었던 **배포나 재시작**. 앱이 다시 살아난 뒤라 Resend는 나중에 성공합니다.
- 플랫폼의 타임아웃을 초과한 **콜드 스타트** - 서버리스에서 느린 첫 호출일 때 흔합니다.
- 두 시도 사이에 **바뀐 경로 기반 라우팅**, 또는 일부 요청에만 매칭되는 규칙.
- 여러분의 엣지에 있는 **속도 제한이나 봇 방지**가 수동 재전송은 무더기가 아니라 단독으로 도착해서 통과시켰을 가능성.

Deliveries 탭에는 두 시도가 타임스탬프와 함께 모두 남아 있으므로, 해당 시각의 여러분 쪽 배포 및 오류 로그와 비교해 보세요.

## 서명 검증 실패

거의 항상 다음 세 가지 중 하나입니다.

1. **재직렬화된 JSON을 해시했습니다.** 받은 그대로의 **원본** 요청 본문 바이트를 HMAC 처리하세요. 파싱 후 다시 문자열로 만들면 공백과 키 순서가 바뀌어 서명이 일치하지 않습니다. 대부분의 프레임워크는 원본 본문을 얻으려면 별도 설정이 필요합니다.
2. **잘못된 시크릿.** 서명 시크릿은 **대상별로** 다르며, API 키가 아닙니다. 두 개의 대상은 서로 다른 두 개의 시크릿을 가집니다.
3. **잘못된 인코딩 가정.** 시크릿을 문자열 그대로 사용하는지 아니면 먼저 디코딩해야 하는지 확실하지 않다면 추측하지 말고, [서명 검증 참고 자료](https://docs.didit.me/integration/webhooks#signature-verification)를 정확히 따르고, 디버깅하는 동안 원본 본문을 로그로 남겨 비교하세요.

> **Warning:** 서명 불일치를 검증 자체를 건너뛰는 방식으로 "해결"하지 마세요. 검증하지 않는 웹훅 엔드포인트는 URL을 알아낸 누구로부터도 위조된 승인을 받아들이게 되며, 디버깅용 지름길이 계정 탈취 경로로 바뀝니다.

## 두 번의 재시도는 큐가 아닙니다

5xx 또는 404 응답에는 약 1분 후, 이어서 4분 후 두 번 재시도합니다. 5초 시간 초과나 연결 실패는 자동 재시도하지 않습니다. 수정 후 전달 목록에서 다시 보내세요. 최종 실패에는 알림이 표시됩니다.

재조정 경로를 마련하세요. 시작할 때 아직 최종 상태를 알지 못하는 세션에 대해 결정 엔드포인트를 폴링하세요. 웹훅은 빠른 경로로, 폴링은 대비책으로 다루세요.

## 실제 인증 없이 테스트하기

[Video: API 키 설정 및 웹훅 테스트 - Didit Academy](https://www.youtube.com/watch?v=thOMIGbNLP0&t=140)

대상 페이지의 **테스트 이벤트 보내기**은 선택한 종류 - 승인, 거절, 검토 대기, KYB, 엔티티, 트랜잭션 - 의 완전한 형태의 이벤트를 전송합니다. 실제 세션이 여기에 의존하기 전에 엔드포인트, 서명 검증, 핸들러가 제대로 작동하는지 이를 통해 확인하세요.

샌드박스는 이것의 나머지 절반입니다. 샌드박스 세션은 `"environment": "sandbox"`가 포함된 실제 웹훅을 발생시키므로, 비용 없이 전체 경로를 처음부터 끝까지 시험해 볼 수 있습니다. [샌드박스에서 테스트하기](https://help.didit.me/ko/getting-started/sandbox-and-testing)를 참고하세요.
