웹훅과 권한 동기화
Paddle 이벤트 저장, 멱등성, 상태 전이, 한국 결제수단 타입 변경 대응
Paddle 연동의 안정성은 Checkout 버튼이 아니라 webhook 처리에서 결정됩니다. 고객은 결제창을 닫을 수 있고, 카드 인증은 지연될 수 있고, webhook은 순서대로 오지 않을 수 있습니다. 제품 권한은 반드시 서버에서 검증된 이벤트로 열어야 합니다.
최소 이벤트
Paddle 공식 문서는 기본 integration에서 transaction과 subscription 이벤트를 함께 구독하라고 권장합니다.
| 이벤트 | 목적 |
|---|---|
transaction.created | 결제 시도 생성 |
transaction.updated | 결제 상태 변경, totals, payment method 반영 |
subscription.created | subscription ID 연결 |
subscription.updated | status, items, next billing date 반영 |
더 정교한 운영에서는 renewal, cancellation, pause, payment failed 등 세부 이벤트를 추가합니다.
저장해야 할 필드
| 필드 | 이유 |
|---|---|
notification_id | webhook 전달 단위 중복 처리 방지 |
event_id | Paddle 이벤트 원본 추적과 재조회 기준 |
occurred_at | 이벤트 순서 보정 |
paddle_customer_id | 고객 매핑 |
paddle_subscription_id | 구독 조회와 상태 동기화 |
paddle_transaction_id | 결제/환불/대사 연결 |
subscription.status | 권한 상태 결정 |
subscription.items[].price.id | 플랜/권한 매핑 |
transaction.details.totals | 마지막 결제 금액 표시 |
payments[].method_details.type | 결제수단 분석과 CS |
처리 흐름
멱등성 원칙
1. webhook signature 검증
2. notification_id 중복 확인
3. 원본 payload 저장
4. occurred_at 기준으로 최신 이벤트인지 확인
5. 내부 billing_state 갱신
6. entitlement 재계산
7. 후속 작업 큐 발행이벤트 핸들러에서 바로 이메일, 권한, CRM, 회계 시스템을 모두 호출하지 않습니다. 원본 이벤트를 저장하고
내부 상태를 갱신한 뒤, 후속 작업은 큐나 job으로 분리합니다. Paddle은 webhook에 Paddle-Signature
헤더를 포함하고, webhook 서버는 빠르게 200을 반환해야 하므로 raw body 검증과 비동기 처리를 기본값으로
둡니다.
권한 재계산 함수
권한은 이벤트별 if문으로 흩어두지 말고, 현재 subscription snapshot으로 계산합니다.
function resolveEntitlement(input: {
status: string
priceIds: string[]
nextBilledAt: string | null
scheduledChange?: unknown
}) {
if (input.status === 'active' || input.status === 'trialing') return 'full_access'
if (input.status === 'past_due') return 'grace_access'
return 'no_paid_access'
}한국 결제수단 타입
한국 결제수단은 Paddle API와 webhook에 다음처럼 들어올 수 있습니다.
| 타입 | 표시명 |
|---|---|
south_korea_local_card | Korean local card |
kakao_pay | KakaoPay |
naver_pay | Naver Pay |
samsung_pay | Samsung Pay |
payco | Payco |
기존 korea_local 값은 과거 데이터에 남을 수 있으므로 분석 파이프라인에서는 historic value를 유지하고,
새 값은 별도 매핑 테이블로 흡수합니다.
장애 대응
| 장애 | 대응 |
|---|---|
| webhook 지연 | Paddle API 재조회로 subscription snapshot 확인 |
| webhook 중복 | notification_id로 무시 |
| 순서 뒤섞임 | occurred_at이 더 오래된 이벤트는 상태 덮어쓰기 금지 |
| 내부 처리 실패 | 원본 payload 재처리 큐 |
| Paddle API 장애 | 권한 상태를 마지막 정상 snapshot 기준으로 임시 유지 |
테이블 설계, raw body signature 검증, replay queue, snapshot reconcile은 Webhook 구현 부록에서 코드 수준으로 다룹니다.