diff --git a/SodaLive/Resources/payverse_starter.html b/SodaLive/Resources/payverse_starter.html
new file mode 100644
index 0000000..d583994
--- /dev/null
+++ b/SodaLive/Resources/payverse_starter.html
@@ -0,0 +1,31 @@
+//
+//  Untitled.swift
+//  SodaLive
+//
+//  Created by klaus on 9/29/25.
+//
+
+
+
+
+    
+    
+    
+    
+
+
+
+
+
diff --git a/SodaLive/Resources/payverse_starter_debug.html b/SodaLive/Resources/payverse_starter_debug.html
new file mode 100644
index 0000000..6df7103
--- /dev/null
+++ b/SodaLive/Resources/payverse_starter_debug.html
@@ -0,0 +1,58 @@
+
+
+
+    
+    
+    PayVerse Starter
+    
+    
+    
+
+
+
+    
PayVerse Starter
+    
결제 모듈 로드를 준비중입니다...
+    
+
 
+
+
+
diff --git a/SodaLive/Sources/App/AppViewModel.swift b/SodaLive/Sources/App/AppViewModel.swift
index 36f2536..df6b5dd 100644
--- a/SodaLive/Sources/App/AppViewModel.swift
+++ b/SodaLive/Sources/App/AppViewModel.swift
@@ -107,4 +107,8 @@ final class AppViewModel: ObservableObject {
                 .store(in: &subscription)
         }
     }
+    
+    func handlePayverseOpenURL(_ url: URL) {
+        
+    }
 }
diff --git a/SodaLive/Sources/App/SodaLiveApp.swift b/SodaLive/Sources/App/SodaLiveApp.swift
index 203c19d..9ff2831 100644
--- a/SodaLive/Sources/App/SodaLiveApp.swift
+++ b/SodaLive/Sources/App/SodaLiveApp.swift
@@ -17,9 +17,11 @@ struct SodaLiveApp: App {
     
     @ObservedObject var viewModel = AppViewModel()
     
+    @StateObject var canPgPaymentViewModel = CanPgPaymentViewModel()
+    
     var body: some Scene {
         WindowGroup {
-            ContentView()
+            ContentView(canPgPaymentViewModel: canPgPaymentViewModel)
                 .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
                     CreatorCommunityMediaPlayerManager.shared.pauseContent()
                 }
@@ -34,8 +36,16 @@ struct SodaLiveApp: App {
                 }
                 .onOpenURL { url in
                     DEBUG_LOG("I have received a URL through a custom scheme! \(url.absoluteString)")
-                    ApplicationDelegate.shared.application(UIApplication.shared, open: url, options: [:])
-                    AppsFlyerLib.shared().handleOpen(url)
+                    
+                    if let comps = URLComponents(url: url, resolvingAgainstBaseURL: false),
+                        url.scheme?.lowercased() == APPSCHEME.lowercased(),
+                       comps.host?.lowercased() == "payverse",
+                       comps.path.lowercased() == "/result" {
+                        canPgPaymentViewModel.handleVerifyOpenURL(url)
+                    } else {
+                        ApplicationDelegate.shared.application(UIApplication.shared, open: url, options: [:])
+                        AppsFlyerLib.shared().handleOpen(url)
+                    }
                 }
         }
     }
diff --git a/SodaLive/Sources/ContentView.swift b/SodaLive/Sources/ContentView.swift
index 57d1880..cadc5e8 100644
--- a/SodaLive/Sources/ContentView.swift
+++ b/SodaLive/Sources/ContentView.swift
@@ -8,6 +8,7 @@
 import SwiftUI
 
 struct ContentView: View {
+    @ObservedObject var canPgPaymentViewModel: CanPgPaymentViewModel
     @StateObject private var appState = AppState.shared
     
     @State private var isShowDialog = false
@@ -86,6 +87,7 @@ struct ContentView: View {
                 
             case .canPgPayment(let canResponse, let refresh, let afterCompletionToGoBack):
                 CanPgPaymentView(canResponse: canResponse, refresh: refresh, afterCompletionToGoBack: afterCompletionToGoBack)
+                    .environmentObject(canPgPaymentViewModel)
                 
             case .liveReservation:
                 LiveReservationStatusView()
@@ -304,6 +306,6 @@ struct ContentView: View {
 
 struct ContentView_Previews: PreviewProvider {
     static var previews: some View {
-        ContentView()
+        ContentView(canPgPaymentViewModel: CanPgPaymentViewModel())
     }
 }
diff --git a/SodaLive/Sources/Debug/Utils/Constants.swift b/SodaLive/Sources/Debug/Utils/Constants.swift
index d58e278..61bb709 100644
--- a/SodaLive/Sources/Debug/Utils/Constants.swift
+++ b/SodaLive/Sources/Debug/Utils/Constants.swift
@@ -19,3 +19,6 @@ let BOOTPAY_APP_HECTO_ID = "667fca5d3bab7404f831c3e5"
 let NOTIFLY_PROJECT_ID = "5f7ebe90d1ce5f0392164b8a53a662bc"
 let NOTIFLY_USERNAME = "voiceon"
 let NOTIFLY_PASSWORD = "c6c585db0aaa4189be44d0467c7d66b6@A"
+
+let APPSCHEME = "voiceon-test"
+let PAYVERSE_HTML_RESOURCE = "payverse_starter_debug"
diff --git a/SodaLive/Sources/MyPage/Can/CanApi.swift b/SodaLive/Sources/MyPage/Can/CanApi.swift
index 0766dfe..17bdabd 100644
--- a/SodaLive/Sources/MyPage/Can/CanApi.swift
+++ b/SodaLive/Sources/MyPage/Can/CanApi.swift
@@ -22,6 +22,9 @@ enum CanApi {
     case pgVerifyHecto(request: PgVerifyRequest)
     
     case useCanCoupon(request: UseCanCouponRequest)
+    
+    case payverseChargeCan(request: PayverseChargeRequest)
+    case payverseVerify(transactionId: String, orderId: String)
 }
 
 extension CanApi: TargetType {
@@ -60,6 +63,12 @@ extension CanApi: TargetType {
             
         case .useCanCoupon:
             return "/can/coupon/use"
+            
+        case .payverseChargeCan:
+            return "/charge/payverse"
+            
+        case .payverseVerify:
+            return "/charge/payverse/verify"
         }
     }
     
@@ -68,7 +77,7 @@ extension CanApi: TargetType {
         case .getCanStatus, .getCanChargeStatus, .getCanUseStatus, .getCans:
             return .get
             
-        case .chargeCan, .verify, .pgChargeCan, .pgVerify, .pgVerifyHecto, .useCanCoupon:
+        case .chargeCan, .verify, .pgChargeCan, .pgVerify, .pgVerifyHecto, .useCanCoupon, .payverseChargeCan, .payverseVerify:
             return .post
         }
     }
@@ -112,6 +121,14 @@ extension CanApi: TargetType {
             
         case .useCanCoupon(let request):
             return .requestJSONEncodable(request)
+            
+        case .payverseChargeCan(let request):
+            return .requestJSONEncodable(request)
+            
+        case .payverseVerify(let transactionId, let orderId):
+            return .requestJSONEncodable(
+                PayverseVerifyRequest(transactionId: transactionId, orderId: orderId)
+            )
         }
     }
     
diff --git a/SodaLive/Sources/MyPage/Can/CanRepository.swift b/SodaLive/Sources/MyPage/Can/CanRepository.swift
index 2debe48..b1dbfab 100644
--- a/SodaLive/Sources/MyPage/Can/CanRepository.swift
+++ b/SodaLive/Sources/MyPage/Can/CanRepository.swift
@@ -53,5 +53,13 @@ final class CanRepository {
         let request = UseCanCouponRequest(couponNumber: couponNumber)
         return api.requestPublisher(.useCanCoupon(request: request))
     }
+    
+    func payverseChargeCan(canId: Int) -> AnyPublisher {
+        return api.requestPublisher(.payverseChargeCan(request: PayverseChargeRequest(canId: canId)))
+    }
+    
+    func payverseVerify(transactionId: String, orderId: String) -> AnyPublisher {
+        return api.requestPublisher(.payverseVerify(transactionId: transactionId, orderId: orderId))
+    }
 }
 
diff --git a/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentView.swift b/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentView.swift
index 0d7683f..4abfc1d 100644
--- a/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentView.swift
+++ b/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentView.swift
@@ -11,12 +11,14 @@ import BootpayUI
 
 struct CanPgPaymentView: View {
     
-    @StateObject var viewModel = CanPgPaymentViewModel()
+    @EnvironmentObject var viewModel: CanPgPaymentViewModel
     
     let canResponse: GetCanResponse
     let refresh: () -> Void
     let afterCompletionToGoBack: Bool
     
+    @State private var showExitConfirm: Bool = false
+    
     init(canResponse: GetCanResponse, refresh: @escaping () -> Void, afterCompletionToGoBack: Bool) {
         self.canResponse = canResponse
         self.refresh = refresh
@@ -64,6 +66,37 @@ struct CanPgPaymentView: View {
                         DEBUG_LOG("onClose")
                         viewModel.isShowPaymentView = false
                     }
+            } else if viewModel.isShowPayversePaymentView {
+                ZStack(alignment: .topLeading) {
+                    PayverseWebView(startPayloadJson: viewModel.payversePayloadJson)
+                        .ignoresSafeArea(edges: .bottom)
+                    HStack(spacing: 8) {
+                        Button(action: { showExitConfirm = true }) {
+                            Text("닫기")
+                                .font(.custom(Font.bold.rawValue, size: 14))
+                                .foregroundColor(.white)
+                                .padding(.horizontal, 12)
+                                .padding(.vertical, 8)
+                                .background(Color.black.opacity(0.6))
+                                .clipShape(Capsule())
+                        }
+                        .padding(.leading, 16)
+                        .padding(.top, 12)
+                        Spacer()
+                    }
+                }
+                .background(Color.black.ignoresSafeArea())
+                .alert("결제를 종료할까요?", isPresented: $showExitConfirm) {
+                    Button("계속", role: .cancel) { }
+                    Button("종료", role: .destructive) {
+                        DEBUG_LOG("Payverse: user requested to exit")
+                        viewModel.isShowPayversePaymentView = false
+                        // 필요 시 상위로 복귀
+                        AppState.shared.back()
+                    }
+                } message: {
+                    Text("진행 중인 결제를 중단하고 이전 화면으로 돌아갑니다.")
+                }
             } else {
                 GeometryReader { proxy in
                     VStack(spacing: 0) {
@@ -102,15 +135,14 @@ struct CanPgPaymentView: View {
                                     .frame(width: screenSize().width - 26.7, alignment: .leading)
                                     .padding(.top, 26.7)
                                 
-                                
-                                HStack(spacing: 13.3) {
-                                    Text("카드")
-                                        .font(.custom( viewModel.paymentMethod == .card ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7))
-                                        .foregroundColor(viewModel.paymentMethod == .card ? Color.button : Color.grayee)
+                                HStack(spacing: 16.7) {
+                                    Text("통합 결제")
+                                        .font(.custom( viewModel.paymentMethod == .unified ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7))
+                                        .foregroundColor(viewModel.paymentMethod == .unified ? Color.button : Color.grayee)
                                         .frame(maxWidth: .infinity)
                                         .padding(.vertical, 16.7)
                                         .background(
-                                            viewModel.paymentMethod == .card ?
+                                            viewModel.paymentMethod == .unified ?
                                             Color.button.opacity(0.3) :
                                                 Color.gray23
                                         )
@@ -118,60 +150,11 @@ struct CanPgPaymentView: View {
                                         .overlay(
                                             RoundedRectangle(cornerRadius: 10)
                                                 .stroke(lineWidth: 1)
-                                                .foregroundColor(viewModel.paymentMethod == .card ? Color.button : Color.gray77)
+                                                .foregroundColor(viewModel.paymentMethod == .unified ? Color.button : Color.gray77)
                                         )
                                         .onTapGesture {
-                                            if viewModel.paymentMethod != .card {
-                                                viewModel.paymentMethod = .card
-                                            }
-                                        }
-                                    
-                                    
-                                    Text("계좌이체")
-                                        .font(.custom( viewModel.paymentMethod == .bank ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7))
-                                        .foregroundColor(viewModel.paymentMethod == .bank ? Color.button : Color.grayee)
-                                        .frame(maxWidth: .infinity)
-                                        .padding(.vertical, 16.7)
-                                        .background(
-                                            viewModel.paymentMethod == .bank ?
-                                            Color.button.opacity(0.3) :
-                                                Color.gray23
-                                        )
-                                        .cornerRadius(10)
-                                        .overlay(
-                                            RoundedRectangle(cornerRadius: 10)
-                                                .stroke(lineWidth: 1)
-                                                .foregroundColor(viewModel.paymentMethod == .bank ? Color.button : Color.gray77)
-                                        )
-                                        .onTapGesture {
-                                            if viewModel.paymentMethod != .bank {
-                                                viewModel.paymentMethod = .bank
-                                            }
-                                        }
-                                }
-                                .frame(width: screenSize().width - 26.7)
-                                .padding(.top, 16.7)
-                                
-                                HStack(spacing: 13.3) {
-                                    Text("휴대폰 결제")
-                                        .font(.custom( viewModel.paymentMethod == .phone ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7))
-                                        .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.grayee)
-                                        .frame(maxWidth: .infinity)
-                                        .padding(.vertical, 16.7)
-                                        .background(
-                                            viewModel.paymentMethod == .phone ?
-                                            Color.button.opacity(0.3) :
-                                                Color.gray23
-                                        )
-                                        .cornerRadius(10)
-                                        .overlay(
-                                            RoundedRectangle(cornerRadius: 10)
-                                                .stroke(lineWidth: 1)
-                                                .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.gray77)
-                                        )
-                                        .onTapGesture {
-                                            if viewModel.paymentMethod != .phone {
-                                                viewModel.paymentMethod = .phone
+                                            if viewModel.paymentMethod != .unified {
+                                                viewModel.paymentMethod = .unified
                                             }
                                         }
                                     
@@ -195,6 +178,28 @@ struct CanPgPaymentView: View {
                                                 viewModel.paymentMethod = .kakaopay
                                             }
                                         }
+                                    
+                                    Text("휴대폰 결제")
+                                        .font(.custom( viewModel.paymentMethod == .phone ? Font.bold.rawValue : Font.medium.rawValue, size: 16.7))
+                                        .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.grayee)
+                                        .frame(maxWidth: .infinity)
+                                        .padding(.vertical, 16.7)
+                                        .background(
+                                            viewModel.paymentMethod == .phone ?
+                                            Color.button.opacity(0.3) :
+                                                Color.gray23
+                                        )
+                                        .cornerRadius(10)
+                                        .overlay(
+                                            RoundedRectangle(cornerRadius: 10)
+                                                .stroke(lineWidth: 1)
+                                                .foregroundColor(viewModel.paymentMethod == .phone ? Color.button : Color.gray77)
+                                        )
+                                        .onTapGesture {
+                                            if viewModel.paymentMethod != .phone {
+                                                viewModel.paymentMethod = .phone
+                                            }
+                                        }
                                 }
                                 .frame(width: screenSize().width - 26.7)
                                 .padding(.top, 16.7)
@@ -299,12 +304,16 @@ struct CanPgPaymentView: View {
                                         viewModel.errorMessage = "결제진행에 동의하셔야 결제가 가능합니다."
                                         viewModel.isShowPopup = true
                                     } else {
-                                        viewModel.chargeCan(canId: canResponse.id) {
-                                            viewModel.payload.orderName = canResponse.title
-                                            viewModel.payload.price = Double(canResponse.price)
-                                            viewModel.payload.taxFree = 0
-                                            
-                                            viewModel.isShowPaymentView = true
+                                        if viewModel.paymentMethod == .unified {
+                                            viewModel.payverseChargeCan(canId: canResponse.id)
+                                        } else {
+                                            viewModel.chargeCan(canId: canResponse.id) {
+                                                viewModel.payload.orderName = canResponse.title
+                                                viewModel.payload.price = Double(canResponse.price)
+                                                viewModel.payload.taxFree = 0
+                                                
+                                                viewModel.isShowPaymentView = true
+                                            }
                                         }
                                     }
                                 }
@@ -348,6 +357,21 @@ struct CanPgPaymentView: View {
                 LoadingView()
             }
         }
+        .onAppear {
+            viewModel.canResponse = canResponse
+            viewModel.refresh = refresh
+            viewModel.afterCompletionToGoBack = afterCompletionToGoBack
+        }
+        .onDisappear {
+            viewModel.canResponse = nil
+            viewModel.refresh = nil
+            viewModel.afterCompletionToGoBack = nil
+            viewModel.paymentMethod = nil
+            viewModel.isTermsAgree = false
+            viewModel.isShowPaymentView = false
+            viewModel.isShowPayversePaymentView = false
+        }
+        
     }
 }
 
diff --git a/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentViewModel.swift b/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentViewModel.swift
index 448cb0e..152f3f8 100644
--- a/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentViewModel.swift
+++ b/SodaLive/Sources/MyPage/Can/Payment/CanPgPaymentViewModel.swift
@@ -11,8 +11,7 @@ import Combine
 import Bootpay
 
 enum PaymentMethod: String {
-    case card = "카드"
-    case bank = "계좌이체"
+    case unified = "통합 결제"
     case phone = "휴대폰"
     case kakaopay = "카카오페이"
 }
@@ -28,9 +27,15 @@ final class CanPgPaymentViewModel: ObservableObject {
     @Published var isLoading = false
     
     @Published var isShowPaymentView = false
+    @Published var isShowPayversePaymentView = false
     @Published var paymentMethod: PaymentMethod? = nil
     
     let payload = Payload()
+    var payversePayloadJson: String = ""
+    
+    var canResponse: GetCanResponse? = nil
+    var refresh: (() -> Void)? = nil
+    var afterCompletionToGoBack: Bool? = nil
     
     func chargeCan(canId: Int, onSuccess: @escaping () -> Void) {
         isLoading = true
@@ -137,4 +142,139 @@ final class CanPgPaymentViewModel: ObservableObject {
             isShowPopup = true
         }
     }
+    
+    func payverseChargeCan(canId: Int) {
+        isLoading = true
+        repository.payverseChargeCan(canId: canId)
+            .sink { result in
+                switch result {
+                case .finished:
+                    DEBUG_LOG("finish")
+                case .failure(let error):
+                    ERROR_LOG(error.localizedDescription)
+                }
+            } receiveValue: { [unowned self] response in
+                self.isLoading = false
+                let responseData = response.data
+                
+                do {
+                    let jsonDecoder = JSONDecoder()
+                    let decoded = try jsonDecoder.decode(ApiResponse.self, from: responseData)
+                    
+                    if let data = decoded.data, decoded.success {
+                        if let payloadJson = data.payloadJson.data(using: .utf8) {
+                            var obj = try JSONSerialization.jsonObject(with: payloadJson, options: []) as? [String: Any] ?? [:]
+                            obj["returnUrl"] = "\(APPSCHEME)://payverse/result"
+                            obj["webhookUrl"] = "\(BASE_URL)/charge/payverse/webhook"
+                            obj["appScheme"] = APPSCHEME
+                            let merged = try JSONSerialization.data(withJSONObject: obj, options: [])
+                            self.payversePayloadJson = String(data: merged, encoding: .utf8)!
+                            self.isShowPayversePaymentView = true
+                        } else {
+                            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+                            self.isShowPopup = true
+                            return
+                        }
+                    } else {
+                        if let message = decoded.message {
+                            self.errorMessage = message
+                        } else {
+                            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+                        }
+                        
+                        self.isShowPopup = true
+                    }
+                } catch {
+                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+                    self.isShowPopup = true
+                }
+            }
+            .store(in: &subscription)
+    }
+    
+    func handleVerifyOpenURL(_ url: URL) {
+        guard let comps = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
+            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+            self.isShowPopup = true
+            return
+        }
+        let q = comps.queryItems?.reduce(into: [String:String]()) { $0[$1.name] = $1.value } ?? [:]
+        
+        let tid = q["tid"] ?? q["tx_id"]
+        let orderId = q["orderId"]
+        let resultStatus = q["resultStatus"]
+        
+        if resultStatus == "FAILED" ||
+            resultStatus == "DECLINE" ||
+            orderId == nil || orderId?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true ||
+            tid == nil || tid?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
+            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+            self.isShowPopup = true
+            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                AppState.shared.back()
+            }
+            return
+        } else {
+            payverseVerify(transactionId: tid!, orderId: orderId!)
+        }
+    }
+    
+    func payverseVerify(transactionId: String, orderId: String) {
+        isLoading = true
+        repository.payverseVerify(transactionId: transactionId, orderId: orderId)
+            .sink { result in
+                switch result {
+                case .finished:
+                    DEBUG_LOG("finish")
+                case .failure(let error):
+                    ERROR_LOG(error.localizedDescription)
+                }
+            } receiveValue: { [unowned self] response in
+                self.isLoading = false
+                let responseData = response.data
+                
+                do {
+                    let jsonDecoder = JSONDecoder()
+                    let decoded = try jsonDecoder.decode(ApiResponseWithoutData.self, from: responseData)
+                    
+                    if decoded.success {
+                        if let canResponse = self.canResponse {
+                            let can = UserDefaults.int(forKey: .can)
+                            UserDefaults.set(can + canResponse.can + canResponse.rewardCan, forKey: .can)
+                            
+                            if let refresh = refresh {
+                                refresh()
+                            }
+                            
+                            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
+                                if let afterCompletionToGoBack = self.afterCompletionToGoBack, afterCompletionToGoBack {
+                                    AppState.shared.back()
+                                    AppState.shared.back()
+                                } else {
+                                    if let refresh = self.refresh {
+                                        AppState.shared.setAppStep(step: .canStatus(refresh: refresh))
+                                    } else {
+                                        AppState.shared.setAppStep(step: .canStatus(refresh: {}))
+                                    }
+                                }
+                            }
+                        } else {
+                            AppState.shared.setAppStep(step: .canStatus(refresh: {}))
+                        }
+                    } else {
+                        if let message = decoded.message {
+                            self.errorMessage = message
+                        } else {
+                            self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+                        }
+                        
+                        self.isShowPopup = true
+                    }
+                } catch {
+                    self.errorMessage = "다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
+                    self.isShowPopup = true
+                }
+            }
+            .store(in: &subscription)
+    }
 }
diff --git a/SodaLive/Sources/MyPage/Can/Payment/Payverse/PayverseChargeDto.swift b/SodaLive/Sources/MyPage/Can/Payment/Payverse/PayverseChargeDto.swift
new file mode 100644
index 0000000..76bc4a6
--- /dev/null
+++ b/SodaLive/Sources/MyPage/Can/Payment/Payverse/PayverseChargeDto.swift
@@ -0,0 +1,20 @@
+//
+//  PayverseChargeDto.swift
+//  SodaLive
+//
+//  Created by klaus on 9/29/25.
+//
+
+struct PayverseChargeRequest: Encodable {
+    let canId: Int
+}
+
+struct PayverseChargeResponse: Decodable {
+    let chargeId: Int
+    let payloadJson: String
+}
+
+struct PayverseVerifyRequest: Encodable {
+    let transactionId: String
+    let orderId: String
+}
diff --git a/SodaLive/Sources/MyPage/Can/Payment/PayverseWebView.swift b/SodaLive/Sources/MyPage/Can/Payment/PayverseWebView.swift
new file mode 100644
index 0000000..ae1787d
--- /dev/null
+++ b/SodaLive/Sources/MyPage/Can/Payment/PayverseWebView.swift
@@ -0,0 +1,247 @@
+//
+//  PayverseWebView.swift
+//  SodaLive
+//
+//  Created by klaus on 9/29/25.
+//
+
+import SwiftUI
+import WebKit
+
+struct PayverseWebView: UIViewRepresentable {
+    let startPayloadJson: String
+    
+    func makeUIView(context: Context) -> WKWebView {
+        // WKWebView 구성: JavaScript 허용 및 팝업 허용
+        let config = WKWebViewConfiguration()
+        config.defaultWebpagePreferences.allowsContentJavaScript = true
+        config.preferences.javaScriptCanOpenWindowsAutomatically = true
+        config.websiteDataStore = .default()
+        
+        let webView = WKWebView(frame: .zero, configuration: config)
+        webView.navigationDelegate = context.coordinator
+        
+        // 빈 화면을 검은 화면으로 보기 위해 다크 모드 강제 적용
+        if #available(iOS 13.0, *) {
+            webView.overrideUserInterfaceStyle = .dark
+        }
+        webView.isOpaque = false
+        webView.backgroundColor = .black
+        webView.scrollView.backgroundColor = .black
+        webView.allowsBackForwardNavigationGestures = true
+        webView.scrollView.contentInsetAdjustmentBehavior = .never
+        
+        // 번들 리소스 로딩 (PAYVERSE_HTML_RESOURCE.html)
+        if let url = Bundle.main.url(forResource: PAYVERSE_HTML_RESOURCE,
+                                     withExtension: "html") {
+            // 로컬 파일 접근 권한을 위해 디렉터리 권한 부여
+            webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
+            DEBUG_LOG("[DEBUG_LOG] Loading local Payverse HTML: \(url.lastPathComponent)")
+        } else {
+            DEBUG_LOG("[ERROR_LOG] Payverse HTML resource not found: \(PAYVERSE_HTML_RESOURCE).html")
+        }
+        
+        return webView
+    }
+    
+    func updateUIView(_ uiView: WKWebView, context: Context) {}
+    
+    func makeCoordinator() -> Coordinator {
+        Coordinator(startPayloadJson: startPayloadJson)
+    }
+    
+    final class Coordinator: NSObject, WKNavigationDelegate {
+        private let startPayloadJson: String
+        init(startPayloadJson: String) {
+            self.startPayloadJson = startPayloadJson
+        }
+        func webView(_ webView: WKWebView,
+                     decidePolicyFor navigationAction: WKNavigationAction,
+                     decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
+            guard let url = navigationAction.request.url else {
+                decisionHandler(.allow); return
+            }
+            
+            updateBlindViewIfNaverLogin(webView, url.absoluteString)
+            
+            // 커스텀 스킴: myapp://payverse/result?...  → 앱으로 전환
+            if url.scheme?.lowercased() == APPSCHEME.lowercased() {
+                UIApplication.shared.open(url, options: [:], completionHandler: nil)
+                decisionHandler(.cancel)
+            } else if(url.scheme?.lowercased() == "file") {
+                // 로컬 리소스(file://)는 WebView에서 로드 허용
+                decisionHandler(.allow)
+            } else if(url.absoluteString.starts(with: "about:blank")) {
+                decisionHandler(.allow)
+            } else if(isItunesURL(url.absoluteString)) {
+                startAppToApp(url)
+                decisionHandler(.cancel)
+            } else if(!url.absoluteString.starts(with: "http")) {
+                // http/https 이외의 스킴은 외부 앱/App Store 처리
+                startAppToApp(url)
+                decisionHandler(.cancel)
+            } else {
+                decisionHandler(.allow)
+            }
+        }
+        
+        // 리소스 로드 성공 여부 확인 + 결제 시작 호출
+        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
+            webView.evaluateJavaScript("document.readyState") { value, error in
+                if let state = value as? String {
+                    DEBUG_LOG("[DEBUG_LOG] WebView readyState: \(state)")
+                }
+                if let error = error {
+                    DEBUG_LOG("[ERROR_LOG] readyState eval error: \(error.localizedDescription)")
+                }
+            }
+            // startPay 가 노출되어 있는지 확인 로그
+            webView.evaluateJavaScript("typeof startPay === 'function'") { value, _ in
+                if let ok = value as? Bool {
+                    DEBUG_LOG("[DEBUG_LOG] startPay function available: \(ok)")
+                }
+            }
+            // JSON 문자열을 JS 문자열 리터럴에 안전하게 담기 위해 이스케이프 처리
+            func esc(_ s: String) -> String {
+                var r = s.replacingOccurrences(of: "\\", with: "\\\\")
+                r = r.replacingOccurrences(of: "'", with: "\\'")
+                r = r.replacingOccurrences(of: "\n", with: "\\n")
+                r = r.replacingOccurrences(of: "\r", with: "")
+                r = r.replacingOccurrences(of: "\u{2028}", with: "\\u2028")
+                r = r.replacingOccurrences(of: "\u{2029}", with: "\\u2029")
+                r = r.replacingOccurrences(of: "", with: "<\\/")
+                return r
+            }
+            let escaped = esc(self.startPayloadJson)
+            let js = """
+            (function(){
+                try {
+                    if (typeof startPay === 'function') {
+                        startPay('\(escaped)');
+                        console.log('iOS: startPay invoked');
+                    } else {
+                        setTimeout(function(){
+                            try {
+                                if (typeof startPay === 'function') {
+                                    startPay('\(escaped)');
+                                    console.log('iOS: startPay invoked (retry)');
+                                }
+                            } catch(e) {
+                                console.log('iOS: startPay retry error: ' + (e && e.message ? e.message : e));
+                            }
+                        }, 300);
+                    }
+                } catch(e) {
+                    console.log('iOS: startPay call error: ' + (e && e.message ? e.message : e));
+                }
+            })();
+            """
+            webView.evaluateJavaScript(js) { _, error in
+                if let error = error {
+                    DEBUG_LOG("[ERROR_LOG] startPay invoke error: \(error.localizedDescription)")
+                } else {
+                    DEBUG_LOG("[DEBUG_LOG] startPay invoked from iOS")
+                }
+            }
+        }
+        
+        func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
+            DEBUG_LOG("[ERROR_LOG] WebView didFail: \(error.localizedDescription)")
+        }
+        
+        func updateBlindViewIfNaverLogin(_ webView: WKWebView, _ url: String) {
+            if(url.starts(with: "https://nid.naver.com")) { //show
+                webView.evaluateJavaScript("document.getElementById('back').remove();")
+            }
+        }
+        
+        func isItunesURL(_ urlString: String) -> Bool {
+            return isMatch(urlString, "\\/\\/itunes\\.apple\\.com\\/")
+        }
+        
+        func isMatch(_ urlString: String, _ pattern: String) -> Bool {
+            let regex = try! NSRegularExpression(pattern: pattern, options: [])
+            let result = regex.matches(in: urlString, options: [], range: NSRange(location: 0, length: urlString.count))
+            return result.count > 0
+        }
+        
+        func startAppToApp(_ url: URL) {
+            UIApplication.shared.open(url, options: [:], completionHandler: { result in
+                if(result == false) {
+                    self.startItunesToInstall(url)
+                }
+            })
+        }
+        
+        func startItunesToInstall(_ url: URL) {
+            let sUrl = url.absoluteString
+            var itunesUrl = ""
+            
+            if(sUrl.starts(with: "kfc-bankpay")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EB%B1%85%ED%81%AC%ED%8E%98%EC%9D%B4-%EA%B8%88%EC%9C%B5%EA%B8%B0%EA%B4%80-%EA%B3%B5%EB%8F%99-%EA%B3%84%EC%A2%8C%EC%9D%B4%EC%B2%B4-%EA%B2%B0%EC%A0%9C-%EC%A0%9C%EB%A1%9C%ED%8E%98%EC%9D%B4/id398456030"
+            } else if(sUrl.starts(with: "ispmobile")) {
+                itunesUrl = "https://apps.apple.com/kr/app/isp/id369125087"
+            } else if(sUrl.starts(with: "hdcardappcardansimclick") || sUrl.starts(with: "smhyundaiansimclick")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%ED%98%84%EB%8C%80%EC%B9%B4%EB%93%9C/id702653088"
+            } else if(sUrl.starts(with: "shinhan-sr-ansimclick") || sUrl.starts(with: "smshinhanansimclick")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%8B%A0%ED%95%9C%ED%8E%98%EC%9D%B4%ED%8C%90/id572462317"
+            } else if(sUrl.starts(with: "kb-acp")) {
+                itunesUrl = "https://apps.apple.com/kr/app/kb-pay/id695436326"
+            } else if(sUrl.starts(with: "liivbank")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EB%A6%AC%EB%B8%8C/id1126232922"
+            } else if(sUrl.starts(with: "mpocket.online.ansimclick") || sUrl.starts(with: "ansimclickscard") || sUrl.starts(with: "ansimclickipcollect") || sUrl.starts(with: "samsungpay") || sUrl.starts(with: "scardcertiapp")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%82%BC%EC%84%B1%EC%B9%B4%EB%93%9C/id535125356"
+            } else if(sUrl.starts(with: "lottesmartpay")) {
+                itunesUrl = "https://apps.apple.com/us/app/%EB%A1%AF%EB%8D%B0%EC%B9%B4%EB%93%9C-%EC%95%B1%EC%B9%B4%EB%93%9C/id688047200"
+            } else if(sUrl.starts(with: "lotteappcard")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EB%94%94%EC%A7%80%EB%A1%9C%EC%B9%B4-%EB%A1%AF%EB%8D%B0%EC%B9%B4%EB%93%9C/id688047200"
+            } else if(sUrl.starts(with: "newsmartpib")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%9A%B0%EB%A6%AC-won-%EB%B1%85%ED%82%B9/id1470181651"
+            } else if(sUrl.starts(with: "com.wooricard.wcard")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%9A%B0%EB%A6%ACwon%EC%B9%B4%EB%93%9C/id1499598869"
+            } else if(sUrl.starts(with: "citispay") || sUrl.starts(with: "citicardappkr") || sUrl.starts(with: "citimobileapp")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%94%A8%ED%8B%B0%EB%AA%A8%EB%B0%94%EC%9D%BC/id1179759666"
+            } else if(sUrl.starts(with: "shinsegaeeasypayment")) {
+                itunesUrl = "https://apps.apple.com/kr/app/ssgpay/id666237916"
+            } else if(sUrl.starts(with: "cloudpay")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%ED%95%98%EB%82%98%EC%B9%B4%EB%93%9C-%EC%9B%90%ED%81%90%ED%8E%98%EC%9D%B4/id847268987"
+            } else if(sUrl.starts(with: "hanawalletmembers")) {
+                itunesUrl = "https://apps.apple.com/kr/app/n-wallet/id492190784"
+            } else if(sUrl.starts(with: "nhappvardansimclick")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%98%AC%EC%9B%90%ED%8E%98%EC%9D%B4-nh%EC%95%B1%EC%B9%B4%EB%93%9C/id1177889176"
+            } else if(sUrl.starts(with: "nhallonepayansimclick") || sUrl.starts(with: "nhappcardansimclick") || sUrl.starts(with: "nhallonepayansimclick") || sUrl.starts(with: "nonghyupcardansimclick")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%98%AC%EC%9B%90%ED%8E%98%EC%9D%B4-nh%EC%95%B1%EC%B9%B4%EB%93%9C/id1177889176"
+            } else if(sUrl.starts(with: "payco")) {
+                itunesUrl = "https://apps.apple.com/kr/app/payco/id924292102"
+            } else if(sUrl.starts(with: "lpayapp") || sUrl.starts(with: "lmslpay")) {
+                itunesUrl = "https://apps.apple.com/kr/app/l-point-with-l-pay/id473250588"
+            } else if(sUrl.starts(with: "naversearchapp")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EB%84%A4%EC%9D%B4%EB%B2%84-naver/id393499958"
+            } else if(sUrl.starts(with: "tauthlink")) {
+                itunesUrl = "https://apps.apple.com/kr/app/pass-by-skt/id1141258007"
+            } else if(sUrl.starts(with: "uplusauth") || sUrl.starts(with: "upluscorporation")) {
+                itunesUrl = "https://apps.apple.com/kr/app/pass-by-u/id1147394645"
+            } else if(sUrl.starts(with: "ktauthexternalcall")) {
+                itunesUrl = "https://apps.apple.com/kr/app/pass-by-kt/id1134371550"
+            } else if(sUrl.starts(with: "supertoss")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%ED%86%A0%EC%8A%A4/id839333328"
+            } else if(sUrl.starts(with: "kakaotalk")) {
+                itunesUrl = "https://apps.apple.com/kr/app/kakaotalk/id362057947"
+            } else if(sUrl.starts(with: "chaipayment")) {
+                itunesUrl = "https://apps.apple.com/kr/app/%EC%B0%A8%EC%9D%B4/id1459979272"
+            } else if(sUrl.starts(with: "ukbanksmartbanknonloginpay")) {
+                itunesUrl = "https://itunes.apple.com/kr/developer/%EC%BC%80%EC%9D%B4%EB%B1%85%ED%81%AC/id1178872626?mt=8"
+            } else if(sUrl.starts(with: "newliiv")) {
+                itunesUrl = "https://apps.apple.com/us/app/%EB%A6%AC%EB%B8%8C-next/id1573528126"
+            } else if(sUrl.starts(with: "kbbank")) {
+                itunesUrl = "https://apps.apple.com/kr/app/kb%EC%8A%A4%ED%83%80%EB%B1%85%ED%82%B9/id373742138"
+            }
+            
+            if(itunesUrl.count > 0) {
+                if let appstore = URL(string: itunesUrl) {
+                    startAppToApp(appstore)
+                }
+            }
+        }
+    }
+}
diff --git a/SodaLive/Sources/Utils/Constants.swift b/SodaLive/Sources/Utils/Constants.swift
index 17e44a5..459d37f 100644
--- a/SodaLive/Sources/Utils/Constants.swift
+++ b/SodaLive/Sources/Utils/Constants.swift
@@ -19,3 +19,6 @@ let BOOTPAY_APP_HECTO_ID = "664c1707b18b225deca4b42a"
 let NOTIFLY_PROJECT_ID = "765102ec85855aa680da35f1b0f55712"
 let NOTIFLY_USERNAME = "voiceon"
 let NOTIFLY_PASSWORD = "c6c585db0aaa4189be44d0467c7d66b6@A"
+
+let APPSCHEME = "voiceon"
+let PAYVERSE_HTML_RESOURCE = "payverse_starter"