1+ import { Request , Response , NextFunction } from 'express' ;
2+ import * as PortOne from '@portone/server-sdk' ;
3+ import { WebhookService } from '../services/purchase.webhook.service' ;
4+
5+ export const WebhookController = {
6+ async handleWebhook ( req : Request , res : Response , next : NextFunction ) {
7+ try {
8+ const webhookSecret = process . env . PORTONE_WEBHOOK_SECRET ;
9+ if ( ! webhookSecret ) {
10+ console . error ( 'PORTONE_WEBHOOK_SECRET is not set' ) ;
11+ return res . status ( 500 ) . send ( 'Server Config Error' ) ;
12+ }
13+
14+ // 1. 웹훅 서명 검증
15+ const webhook = await PortOne . Webhook . verify (
16+ webhookSecret ,
17+ req . body ,
18+ req . headers as Record < string , string | string [ ] | undefined >
19+ ) ;
20+
21+ // 2. 이벤트 타입별 처리 -> 현재는 결제 완료(Paid)만 처리
22+ if ( webhook . type === 'Transaction.Paid' ) {
23+ const { paymentId, storeId } = webhook . data ;
24+ await WebhookService . handleTransactionPaid ( paymentId , storeId ) ;
25+ } else if ( webhook . type === 'Transaction.Cancelled' ) {
26+ console . log ( '[Webhook] Transaction Cancelled:' , webhook . data . paymentId ) ;
27+ }
28+ res . status ( 200 ) . send ( 'OK' ) ;
29+ } catch ( err ) {
30+ if ( err instanceof PortOne . Webhook . WebhookVerificationError ) {
31+ console . error ( '[Webhook] Signature Verification Failed' ) ;
32+ return res . status ( 400 ) . send ( 'Verification Failed' ) ;
33+ }
34+ console . error ( '[Webhook] Error:' , err ) ;
35+ res . status ( 500 ) . send ( 'Internal Server Error' ) ;
36+ }
37+ }
38+ } ;
0 commit comments