From 738916f98e65c842a6a89048a3e9fd7d96c05a44 Mon Sep 17 00:00:00 2001 From: Diyar Bashtani Date: Tue, 25 Aug 2026 14:56:18 +0200 Subject: [PATCH] fix(napm): report failed web redirect to backend when confirmation is required When a web redirect fails (customer cancels ASWebAuthenticationSession or the session fails to start), the failure was only surfaced locally and continuePayment was never invoked, leaving the invoice pending on the backend while the merchant app received a cancellation failure. This mirrors the existing deep link behavior, which reports success: didOpenUrl when redirect.confirmationRequired is set. --- ...eAlternativePaymentDefaultInteractor.swift | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift index 50b2d1f12..9bdfd76df 100644 --- a/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift +++ b/Sources/ProcessOutUI/Sources/Modules/NativeAlternativePayment/Interactor/NativeAlternativePaymentDefaultInteractor.swift @@ -407,8 +407,24 @@ final class NativeAlternativePaymentDefaultInteractor: callback: configuration.redirect.callback, prefersEphemeralSession: configuration.redirect.prefersEphemeralSession ) - let returnUrl = try await webAuthenticationSession.authenticate(using: authenticationRequest) - redirectResult = .init(success: true, result: .init(url: returnUrl)) + do { + let returnUrl = try await webAuthenticationSession.authenticate(using: authenticationRequest) + redirectResult = .init(success: true, result: .init(url: returnUrl)) + } catch { + // Report failed redirect to backend, mirroring the deep link branch, + // so that invoice state doesn't remain pending when customer cancels + // or authentication session is unable to start. + if redirect.confirmationRequired { + _ = try? await serviceAdapter.continuePayment( + with: .init( + flow: configuration.flow, + redirect: .init(success: false), + localeIdentifier: configuration.localization.localeOverride?.identifier + ) + ) + } + throw error + } default: throw POFailure(errorDescription: "Unknown redirect type.", code: .Mobile.internal) }