Description:
I’m integrating Apple Pay JS (version 3) into an Angular application. Here are the key details:
Environment:
Angular (latest) Apple Pay JS v3 Chrome (confirmed window.ApplePaySession is available) application region is in US. I'm in Taiwan and using my iPhone Taiwan account to scan the QR Code/
Implemented Handlers:
onvalidatemerchant onpaymentmethodselected onpaymentauthorized oncancel
Observed Behavior:
When I click the Apple Pay button, the console logs:
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://applepay.cdn-apple.com') does not match the recipient window's origin ('https://{our-domain-name}') Despite this, the QR code still appears.
Scanning the QR code with an iPhone 13 Pro running iOS 18.4.1 brings up the Apple Pay sheet with the correct amount, but payment never completes.
In the browser, none of my Angular event handlers fire except oncancel.
Questions:
What causes the postMessage origin mismatch with Apple’s CDN frame, and how should my application handle it? Why doesn’t onpaymentauthorized ever fire, and how can I complete the payment flow so that session.completePayment() succeeds?
Any guidance or sample code snippets for a proper merchant-validation and payment-completion sequence in this setup would be greatly appreciated.
my code
onApplePayButtonClicked() { if (!ApplePaySession) { console.error('[ApplePay] ApplePaySession is not supported'); return; }
// Define ApplePayPaymentRequest
const request : ApplePayJS.ApplePayPaymentRequest = {
countryCode: this.currencyCode,
currencyCode: Constants.CountryCodeUS,
merchantCapabilities: this.merchantCapabilities,
supportedNetworks: this.supportedNetworks,
total: {
label: this.label,
type: "final" as ApplePayJS.ApplePayLineItemType,
amount: this.orderAmount.toString(),
},
};
// Create ApplePaySession
const session = new ApplePaySession(3, request);
session.onvalidatemerchant = async event => {
console.info('[ApplePay] onvalidatemerchant', event);
try {
const merchantSession = await fetch(`${this.paymentUrl}/api/applepay/validatemerchant`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
PKeyCompany: this.paymentAppleMerchantId,
ValidationUrl: event.validationURL
})
}).then((r) => r.json());
session.completeMerchantValidation(merchantSession);
} catch (error) {
console.error('[ApplePay] onvalidatemerchant MerchantValidation error', error);
session.abort();
}
};
session.onpaymentauthorized = (event) => {
console.info('[ApplePay] paymentauthorized', event);
const token = event.payment.token;
this.paymentTokenEmitted.emit({
token: JSON.stringify(token),
paymentType: PaymentOptionType.ApplePay
});
session.completePayment(ApplePaySession.STATUS_SUCCESS);
};
session.onpaymentmethodselected = (event) => {
console.info('[ApplePay] paymentmethodselected', event);
const update: ApplePayJS.ApplePayPaymentMethodUpdate = {
newTotal: request.total
};
session.completePaymentMethodSelection(update);
};
session.oncancel = (event) => {
console.error('[ApplePay] oncancel', event);
this.errorEmitted.emit({ error: 'Apple Pay cancel' });
};
session.begin();
}