Skip to Content
웹훅개요
View as Markdown

웹훅 — 개요

웹훅은 권위 있는 신호입니다. 브라우저 콜백(onSuccess)과 대시보드 뷰는 편의 사항이며, 웹훅이 그라운드 트루스입니다.

전달 보장

  • At least once. 단일 이벤트는 가맹점 서버가 타임아웃 내에 2xx를 반환하지 않으면 최대 6회까지 전달될 수 있습니다. 핸들러를 멱등성 있게 만드세요 — X-Delivery로 중복을 제거하세요(페이로드에는 event_id 필드가 없으며, 안정적인 전달 UUID가 멱등성 키입니다).
  • HTTP 요청당 하나의 이벤트. 배치 없음.
  • 엔드포인트별 격리. 여러 엔드포인트가 등록되어 있다면 각각 자체 전달 및 재시도 트랙을 가집니다. 느린 엔드포인트 하나가 다른 엔드포인트를 지연시키지 않습니다.
  • 서명됨. 모든 페이로드는 X-Signature 헤더(그리고 로테이션 후 24시간 윈도우 동안 X-Signature-Prev도)를 가집니다. 본문으로 무엇이든 하기 전에 검증하세요. 서명 검증을 참조하세요.

구독 가능한 이벤트 타입

이벤트발생 시점
payment.settled온체인 송금이 체인의 확인 수를 클리어함. 이것을 사용하여 주문을 결제 완료로 표시하세요.
payment.failed법정화폐 결제가 결제 제공자에 의해 거부됨. 암호화폐 타임아웃에는 발생하지 않음 — 그것은 대신 checkout.expired로 노출되고, 부족한 암호화폐 결제는 payment.underpaid로 노출됩니다.
payment.underpaid자금이 도착했지만 주문 총액에 부족함(일반적: 금액에서 스테이블코인 송금 수수료가 차감됨).
payment.overpaid자금이 주문 총액을 초과하여 도착함. 잉여는 기록되지만 자동 환불되지 않습니다.
order.created새 주문이 열림 — B2B API 호출 또는 체크아웃 세션 전환에 의해.
order.canceled주문이 취소됨. 페이로드의 data.reason이 수동 취소와 payment_timeout(미결제 주문이 시간 초과됨)을 구분합니다.
order.resolvedPARTIAL_PAID 주문이 PAID로 해결됨 — 가맹점이 부족분을 수용함.
order.reopened이전에 자동 취소된 주문(canceled_reason=payment_timeout)이 가맹점에 의해 재오픈됨.
checkout.created구매자가 주문의 체크아웃을 열었음.
checkout.completed구매자 측 흐름이 완료됨(온체인 정산을 의미하지 않음 — 그것은 payment.settled 사용).
checkout.expired구매자가 포기했고 세션 TTL이 끝남.
payment.refund.requested환불 기록이 생성됨 — 가맹점 시작 API 호출 또는 고객 제출 환불 요청 양식으로부터.
payment.refund.approved대기 중인 환불이 승인 워크플로우를 통과함.
payment.refund.rejected대기 중인 환불이 거부됨.
payment.refund.executed환불의 온체인 송금이 클리어되어 기록이 종료 상태 executed로 이동함.
refund_request.created환불 요청 토큰이 발급됨. data.source는 b2b / dashboard / renewal. 구독 선택 사항 — 주문별로 현재 활성화된 토큰을 추적하는 감사 파이프라인에 유용합니다.
refund_request.renewal_requested구매자가 토큰 만료 후 “새 링크 요청”을 클릭함. 구독을 강력히 권장합니다 — 갱신 위젯에 처리할 새 항목이 있음을 가맹점에 알리는 신호입니다.
refund_request.renewed갱신이 승인되어 새 토큰이 이전 토큰을 대체함. data.old_token / data.new_token이 감사 체인을 형성합니다.
refund_request.canceled가맹점이 대시보드에서 토큰을 CANCELED로 전환함(예: 갱신 요청 거부, 라이브 링크 종료). 멱등적 — 첫 전이만 발생합니다. data.reason은 선택적 가맹점 메모입니다.

계획됨 (출시 예정)

출시 예정. 이 이벤트들은 아직 사용할 수 없는 정기 청구서와 구독에 속합니다. 위의 구독 가능한 표에 포함되어 있지 않으며 현재는 구독할 수 없습니다. 정기 청구서를 참고하세요.

계획된 이벤트발생 시점…
subscription.created구독이 생성될 때.
invoice.created청구 주기의 청구서가 생성될 때.
invoice.paid청구서가 결제될 때.
subscription.past_due청구서가 납기일을 지나도 미결제 상태일 때.
subscription.canceled구독이 취소될 때.

대시보드의 엔드포인트 양식에도 동일한 이벤트가 나열됩니다. 존재하지 않는 이벤트를 구독하면 엔드포인트를 저장할 때 거부됩니다.

테스트 이벤트는 구독할 수 없습니다. 대시보드의 엔드포인트별 Send Test 버튼은 해당 엔드포인트 하나에만 webhook.test.ping 이벤트를 재시도 없이 즉시 전송합니다. 위 카탈로그에는 나타나지 않습니다. 구독해서가 아니라 등록된 엔드포인트가 있기 때문에 받는 것입니다.

처리하는 이벤트만 구독하세요. 각 엔드포인트는 자체 이벤트 필터를 가집니다. 와일드카드 "*"는 “미래에 추가될 것을 포함한 모든 이벤트”를 의미합니다. 더 적은 이벤트를 구독하면 핸들러가 단순해지고 엔드포인트에 오류가 있을 때 재시도도 줄어듭니다.

페이로드 + 헤더

HTTP 본문은 이벤트별 데이터 객체 자체입니다. Stripe 스타일의 외부 envelope 없음 — 이벤트 타입, 전달 ID, 발신 타임스탬프와 같은 필드는 헤더에 있습니다. payment.settled의 경우 본문은 다음과 같습니다.

{ "receipt_id": "rcp_…", "order_id": "ord_…", "payment_intent_id": "pin_…", "checkout_session_id": "cst_…", "merchant_id": "mer_…", "customer_id": "cus_…", "total": "49.00", "currency": "USD", "payment_method": "crypto", "token": "USDC", "network": "polygon", "tx_hash": "0x…", "deposit_address": "0x…", "treasury_address": "0x…", "amount_received": "49.00", "confirmations": 5, "metadata": { /* 이벤트별 */ } }

다른 이벤트는 자체 필드를 가집니다. 필드 이름은 안정적입니다(소문자 스네이크 케이스); 온체인 트랜잭션 해시는 항상 tx_hash입니다.

tx_hash는 네트워크 고유 형식의 트랜잭션 식별자입니다(EVM 체인은 0x…, TRON·Solana·TON은 네이티브 해시 또는 서명). TRON, Solana, TON에서는 구매자가 가맹점의 트레저리 지갑으로 직접 결제하므로 deposit_address가 없을 수 있으며, confirmations는 체인 및 자산을 따릅니다.

인바운드 요청의 헤더

Content-Type: application/json X-Event: payment.settled X-Delivery: 7c9e6679-7425-40de-944b-e07fc1f90ae7 Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7 X-Timestamp: 1729536000 X-Signature: sha256=9a8b7c… X-Signature-Prev: sha256=fa31b2… (로테이션 grace 윈도우 동안에만)
헤더내용
X-Event이벤트 타입(예: payment.settled). JSON 파싱을 건너뛰려면 프록시 레이어에서 이것으로 라우팅하세요.
X-Delivery전달 행을 식별하는 UUID. 동일한 (event, endpoint) 쌍의 모든 재시도에서 안정적 — 멱등성 키로 사용하세요.
Idempotency-KeyX-Delivery와 미러링(동일한 값). 모든 전달에 설정됨.
X-Timestamp시도가 전송된 유닉스 초. 페이로드에 서명되므로 캡처된 (body, X-Signature) 쌍이 무한정 재생될 수 없습니다 — 타임스탬프가 허용 윈도우 밖인 전달을 거부하세요.
X-SignatureHMAC-SHA256(secret, X-Timestamp + "." + raw_body)의 sha256=<hex>. 서명 검증 참조.
X-Signature-Prev이전 시크릿으로 동일한 알고리즘. 로테이션 후 24시간 윈도우에만 존재 — 어느 쪽 키를 실행 중인 검증자도 컷오버 동안 전달을 계속 받을 수 있게 합니다. 윈도우가 닫힌 후 헤더는 더 이상 전송되지 않습니다.

재시도 스케줄

엔드포인트가 타임아웃 내에 2xx를 반환하지 않으면 다음 스케줄로 재시도합니다 (타임스탬프는 첫 시도 기준).

시도지연누적
10s0s
2+1 min1m
3+5 min6m
4+15 min21m
5+1 hour1h 21m
6+6 hours7h 21m

6번째 시도가 실패하면 전달은 Failed로 표시되고 계정 이메일로 알림이 전송됩니다. 실패한 이벤트는 대시보드의 Developers → Webhooks → Delivery history 패널에서 재생할 수 있습니다. 각 재생은 자체 X-Delivery를 가진 새 전달입니다.

엔드포인트 등록

가맹점 대시보드 에서:

  1. Developers → Webhooks → + Add endpoint
  2. URL 붙여넣기 — https://…만(일반 HTTP는 거부됨; 생성 양식도 localhost, 사설 IP 범위, userinfo가 있는 URL을 차단함)
  3. 구독할 이벤트 선택(또는 * 모두)
  4. 환경 선택 — test 또는 live(각각 자체 시크릿을 가지며 절대 교차되지 않음)
  5. 저장 → 대시보드가 서명 시크릿(whsec_…)을 한 번 표시합니다. 서버 측에 저장하세요 — 다음 두 기능에 필요합니다.

가맹점당 환경당 최대 10개의 엔드포인트(예: 프로덕션 이행용 하나, 스테이징 미러링용 하나, Slack 알림용 하나)를 등록할 수 있습니다. 각각 자체 재시도 상태와 시크릿을 가집니다.

각 엔드포인트의 라이프사이클 액션

각 엔드포인트 카드의 ⋮ 메뉴는 다음을 노출합니다.

  • Edit — URL, 설명 또는 구독 목록 변경. 새 URL은 생성과 동일한 https:///SSRF 규칙으로 재검증됩니다.
  • Send Test — 현재 시크릿으로 서명된 webhook.test.ping envelope를 동기적으로 POST합니다. 대시보드는 HTTP 상태, 지연, 응답의 512바이트 스니펫을 표시합니다. 테스트 핑은 재시도되지 않으므로 답변이 즉시 반환됩니다.
  • Rotate Secret — 새 시크릿을 생성합니다. 이전 시크릿은 24시간 동안 유효합니다(전달은 X-Signature와 X-Signature-Prev를 모두 포함하여 윈도우 동안 어느 쪽 키를 실행 중인 검증자도 재배포 중에 이벤트를 계속 받을 수 있게 합니다).
  • Reveal Secret — 기존 시크릿을 다시 표시합니다. 새 2FA 검증으로 게이팅되고 감사 로그에 기록됨. 사본을 분실했고 Rotate가 허용되지 않는 경우에만 사용하세요.
  • Enable / Disable — 전달 이력을 잃지 않고 엔드포인트를 켜거나 끕니다. 비활성화된 엔드포인트는 대시보드에 남아 있지만 새 전달을 받지 않습니다.
  • Delete — 영구적입니다. 나중에 재활성화할 수 있는 경우 Disable을 사용하세요.

핸들러를 위한 팁

  1. 빠르게 2xx 반환. 무거운 작업을 수행하기 전에 200 OK로 응답하세요 — 이행을 백그라운드 작업으로 넘기세요. 시도당 타임아웃은 10초입니다. 더 오래 응답을 보류하면 재시도가 트리거됩니다. 타임아웃은 플랫폼 측이며 가맹점이 구성할 수 없습니다 — 핸들러가 진정으로 더 많은 시간이 필요한 경우 지원팀에 문의하세요.
  2. X-Delivery로 중복 제거(또는 Idempotency-Key — 동일한 값). 2xx를 반환해도 업스트림 프록시가 연결을 끊고 재시도를 트리거할 수 있습니다. 전달 ID는 동일한 전달 행의 모든 재시도에서 안정적이므로 올바른 키입니다.
  3. 알 수 없는 이벤트 타입을 허용. 새 이벤트가 나타날 수 있습니다. 4xx 대신 200을 반환하고 no-op 하세요. 그렇지 않으면 해당 전달이 계속 재시도됩니다.
  4. 비즈니스 로직 옆에 X-Delivery 로깅. 무언가 잘못되면 그것이 저희 측과 가맹점 측 사이의 조인 키입니다.

다음 단계

  • 서명 검증 — 정확한 알고리즘 + 리플레이 보호 패턴.
  • 개념 → 세션 — 각 이벤트 발생 시 세션이 어떤 상태에 있는지.