본문으로 건너뛰기

Webhooks Overview

CROSS Pay 는 결제 상태가 바뀔 때마다 머천트가 등록한 callback_url 로 HTTP POST 요청을 보냅니다. 본 페이지는 머천트 입장에서 webhook 을 처음 도입할 때 알아야 할 동작 흐름·이벤트 종류·페이로드 구조를 다룹니다.

서명 검증·재시도·체크리스트는 별도 페이지로 분리되어 있습니다.

다음으로읽을 곳
서명 검증 코드, replay 보호Verifying Webhooks
재시도·멱등성·dedupDelivery & Retry
프로덕션 전 점검Production Checklist
이벤트별 정확한 필드 사전Webhook Events 레퍼런스
시스템 구성

이벤트 캡처는 CROSS Pay API 가, 실제 HTTP 발송·서명·재시도는 별도 발송 서비스가 담당합니다. 머천트 입장에서는 단일한 동작으로 보이도록 본 가이드에서 통합 안내합니다.

동작 흐름

이벤트 카탈로그

이벤트 (type)발화 시점머천트 후속 액션
payment.completedPG·체인이 결제 확정을 보고 → PROCESSING → PAID주문 확정·발송·디지털 자산 지급
payment.failedPG·체인이 실패를 보고 → PROCESSING → FAILED주문 실패 처리·사용자 안내
payment.expiredTTL 만료 워커가 미결제 세션을 정리 → EXPIRED (PENDING·PROCESSING 모두)장바구니 복구·재결제 유도
payment.cancelled머천트가 PENDING 상태에서 명시 취소 → CANCELLED주문 취소 처리

각 이벤트의 정확한 페이로드 스키마와 필드 사전은 Webhook Events 레퍼런스 에서 확인하세요.

PROCESSING 은 외부 PG 인계 구간

payment.completed / payment.failed 는 결제가 반드시 PROCESSING을 거쳐서 종결합니다. PROCESSING 진입 시점은 POST /checkout/{id}/quotes (SelectQuote) 가 PG session 을 만든 순간입니다. 이 구간에서는 머천트가 단독으로 cancel 을 호출할 수 없습니다(409 INVALID_TRANSITION). PG webhook 의 결과를 기다리거나 TTL 만료를 기다려야 합니다.

payment.refunded

환불 완료 이벤트(payment.refunded) 는 현재 발송되지 않습니다. 환불 결과는 GET /v1/payments/:id 로 조회하세요.

페이로드 구조

CROSS Pay 는 Standard Webhooks v1 규격의 envelope 으로 페이로드를 빌드합니다.

{
"type": "payment.completed",
"timestamp": "2026-04-21T12:00:00Z",
"data": {
"payment": {
"id": "pay_abc123",
"status": "PAID",
"currency": "KRW",
"amount": "50000",
"payer_uid": "user_789",
"receipt_id": "rcpt_xyz",
"provider": "binancepay",
"paid_at": "2026-04-21T12:00:00Z",
"metadata": { "order_id": "shop-order-789" }
}
}
}
필드의미
typedot-delimited 이벤트 이름 (예: payment.completed)
timestamp도메인 이벤트 발생 시각 (paid_at / failed_at 등). 발송 시각 아님
data이벤트별 페이로드. 모든 이벤트가 data.payment 객체를 포함
시간 표기

모든 시간 필드는 ISO-8601 UTC (Z 접미사) 입니다. 머천트 측에서는 UTC 로 파싱한 뒤 표시 타임존으로 변환하세요.

HTTP 요청 형식

항목
메서드POST
Content-Typeapplication/json
본문위 envelope JSON 의 raw bytes

요청에는 다음 4개 헤더가 함께 전달됩니다.

헤더형식의미
webhook-idUUID이벤트 식별자. 멱등성 dedup 키로 사용
webhook-timestampUnix epoch seconds (string)발송 시점. replay 보호 검증에 사용
webhook-signaturev1,<base64> (공백 구분 다중)HMAC-SHA256 서명. 자세한 내용은 Verifying Webhooks 참조
Content-Typeapplication/json본문 인코딩
POST /your/webhook/path HTTP/1.1
Host: shop.example.com
Content-Type: application/json
webhook-id: 0190a1b2-c3d4-7e5f-89ab-cdef01234567
webhook-timestamp: 1745236800
webhook-signature: v1,K8fXq2y...base64...

{"type":"payment.completed","timestamp":"2026-04-21T12:00:00Z","data":{...}}

metadata passthrough

POST /v1/payments 요청 시 보낸 metadata JSON 은 모든 webhook 페이로드의 data.payment.metadata 필드로 변형 없이 그대로 전달됩니다.

// 결제 생성 요청
{
"currency": "KRW",
"amount": 50000,
"metadata": {
"order_id": "shop-order-789",
"user_id": "u_42"
}
}

// 모든 후속 webhook 페이로드의 data.payment.metadata
{
"order_id": "shop-order-789",
"user_id": "u_42"
}

머천트는 metadata 에 자체 주문 ID·사용자 ID 를 실어 보내, webhook 도착 시 추가 API 호출 없이 자체 시스템과 매핑할 수 있습니다.

metadata 는 인덱싱되지 않습니다

CROSS Pay 는 metadata 내부 키로 결제를 검색할 수 없습니다. 머천트 측에서 metadata.order_id ↔ payment.id 매핑 테이블을 별도로 보관하세요.

결제 상태 머신

핵심 규칙:

  • PENDING → PAID/FAILED 직행은 허용되지 않습니다. 모든 PG·체인 종결은 PROCESSING을 경유합니다.
  • PROCESSING → CANCELLED 는 차단됩니다 (PG 와의 race). PROCESSING 상태의 포기 흐름은 expiry (EXPIRED) 또는 PG 의 FAILED 종결로 처리됩니다.
  • PROCESSING → PROCESSING 재진입은 허용됩니다 (결제수단 변경). 두 번째 SelectQuote 가 들어오면 기존 PG session 은 close 되고 새 quote/session 이 발급됩니다.
  • 상태 전이는 단방향이며, 같은 결제에 대해 두 종류의 종결 이벤트가 함께 발화되는 경우는 없습니다.
머천트 측 분기 처리

status 분기에 default/unknown 경로가 없는 SDK 라면 PROCESSING 케이스를 명시적으로 추가하세요. UI 상으로는 "PG 처리 중 — 결과 대기" 같은 중간 상태로 표시하는 것을 권장합니다. webhook 이 종결 이벤트를 전달할 때까지 주문 확정/배송 등 side-effect 를 실행하지 마세요.

callback URL 등록

callback_url 은 머천트별로 설정되며, CROSS Pay 는 머천트가 직접 변경할 수 있는 endpoint 를 현재 제공하지 않습니다.

  • 신규 등록·변경: support@crosspay.ai 로 요청
  • 요건: HTTPS 권장, 공개 라우팅 가능, POST 본문 수신 가능
로컬 개발 시 endpoint 노출 도구

로컬 머천트 endpoint 를 외부에 노출해야 한다면 다음 도구를 활용하세요.

  • webhook.site — 즉시 받아 페이로드 확인
  • ngrok — 로컬 서버를 공개 URL 로 터널링
  • smee.io — 공개 URL → 로컬 프록시

시크릿 (Callback Secret)

서명 검증에 필요한 머천트 시크릿은 CROSS Pay 측에 암호화되어 보관됩니다. 발급된 plaintext 시크릿은 발급 시점에 한 번만 out-of-band(이메일·파트너 채널) 로 머천트에 전달됩니다.

  • 보관: 시크릿 매니저(예: AWS Secrets Manager, GCP Secret Manager) 또는 환경변수에 보관하고 코드/저장소에 커밋하지 않습니다.
  • 재발급: 분실 시 support@crosspay.ai 로 요청.

시크릿을 사용한 서명 검증 절차와 코드 예시는 Verifying Webhooks 를 참고하세요.

연동 시 알아둘 점

  • payment.created 는 발송하지 않습니다. 결제 생성 결과는 POST /v1/payments 응답으로 동기 전달됩니다.

  • payment.completed 페이로드에는 fee breakdown 이 포함되지 않습니다. 정산 데이터가 필요하면 GET /v1/payments/:id 로 보강 조회하세요.

  • 온체인 결제의 paid_at 은 finality 확정 시각입니다. TX 브로드캐스트 시각이 아니라 CROSS Pay 가 온체인 finality 를 확인한 시점입니다.

  • failure_reason 은 controlled vocabulary 입니다. 현재 enum 값은 다음과 같으며, 머천트는 알 수 없는 값에 대해 UNKNOWN 으로 fallback 처리되도록 default 분기를 두는 것을 권장합니다.

    의미
    UNKNOWNPG 가 분류하지 않은 실패. fallback
    DECLINEDPG 가 결제를 거절
    TX_REVERTED온체인 TX 가 mined 됐으나 컨트랙트 호출이 revert
    AMOUNT_MISMATCH온체인 이벤트 금액이 예상치와 불일치
    TOKEN_MISMATCH온체인 이벤트 토큰이 예상치와 불일치
    ONCHAIN_TIMEOUT만료 전에 온체인 컨펌을 관측하지 못함

    실제 PG 원문 메시지는 머천트로 전달되지 않습니다(서버 로그에만 보존).

  • provider 값은 결제 처리 PG 를 식별합니다. 현재 가능한 값: binancepay, payletter, worldpay, onchain (그리고 온체인 CROSS Pay 결제의 경우 crosspay). 머천트 코드는 provider 값에 의존하지 말고 status 와 금액으로 비즈니스 로직을 구성하세요. payment_method 응답의 provider 컬럼(예: binance_pay, snake-case)과 webhook payload 의 payment.provider (예: binancepay, no-separator) 표기가 다를 수 있다는 점에 유의하세요.

  • PG 가 전환된 경우 stale webhook 은 무시됩니다. 같은 checkout 으로 결제수단을 바꾸면 payment.provider 가 갱신되는데, 옛 PG 가 뒤늦게 콜백을 보내도 CROSS Pay 가 ACK 200 으로 무시하고 발송하지 않습니다. 따라서 동일 결제에 대해 두 종류의 종결 이벤트가 머천트에 도착하는 경우는 없습니다.

다음 단계