We are attempting to integrate the Apple Pay service into our website and have successfully verified our domain with Apple manually. However, we consistently receive an 'ApplePay reverify failed' email a month before the expiration time. Upon checking, we updated the SSL certificate for the domain before receiving the email, and the link still works fine in the browser. We would greatly appreciate any feedback from someone who can help us with this issue.
Apple Pay on the Web
RSS for tagApple Pay on the Web allows you to accept Apple Pay on your website using JavaScript-based APIs.
Posts under Apple Pay on the Web tag
105 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
We have an Apple Pay account and have successfully created and verified the payment processing certificate in our Apple Developer account.
When initiating an Apple Pay payment, the Apple session is created successfully with the correct data return from api , but it is not accepted with the error: “Payment not completed.”
The issue occurs even though the merchant validation step works without errors.
Our websites where this is happening are:
https://magicdeliver.com/
https://www.pulsarmodular.com/
Could you please help us identify the cause of the issue and guide us on resolving it?
I am attempting to verify my domain
https://technoq.genesistechnologies.tech
for use with Apple Pay Merchant ID. However, when I attempt verification, the process fails with the message:
“Domain verification failed.”
Unfortunately, no additional details are provided.
I have already completed the following steps:
Downloaded the verification file apple-developer-merchantid-domain-association.txt.
Placed it in the .well-known directory as instructed.
Confirmed that it is publicly accessible at:
https://technoq.genesistechnologies.tech/.well-known/apple-developer-merchantid-domain-association.txt
Verified that a valid SSL certificate is configured for the domain.
Could you please advise on why the verification might be failing and what additional steps I should take to resolve this issue?
Hello all,
I’m helping a customer integrate Apple Pay, and I’m seeing a behavior I can’t fully explain. I hope someone here can help clarify whether this is expected or whether it’s a bug / misconfiguration on my side.
Currency: RSD (Serbian Dinar)
Amount: 3.45 RSD (two decimals)
Result: Apple Pay cancels the payment automatically when the amount includes decimals, without even displaying the paymentsheet.
Things I have checked:
ISO 4217 defines RSD with 2 minor units, so fractional amounts like 3.45 should be valid.
Processors treat RSD as a two-decimal currency.
Apple’s documentation does not provide a per-currency decimal rule table.
In testing, whole-number RSD amounts succeed, while fractional amounts (e.g. 3.45 RSD) fail. I did not encounter this problem with other currencies like EUR, USD.
Has anyone encountered this issue before?
ApplePaySession.applePayCapabilities() started returning applePayUnsupported in third-party browsers
We rely on ApplePaySession.applePayCapabilities() to decide whether to show the Apple Pay button. We use two different merchant IDs for non-prod/prod environments, and encountered a change in behavior where this API now returns different results.
These merchant IDs are generated from a third-party provider Adyen. However, Adyen has informed us that they are unable to identify the root cause of the issue and advised us to seek assistance directly from Apple Pay support.
Timeline
Last known working date: 13/08/2025
Issue first noticed: 18/08/2025
Environment Details
Apple Pay JS API version 1.latest
Browsers Tested: Third party browsers including Chrome/139.0.0.0, Firefox/141.0
Browsers with ApplePaySession built-in (like iOS Chrome, iOS Safari, and macOS Safari) are working fine
Framework Stack: Angular v18.1.3
(important) no configuration setup in Apple dev account, merchantId is generated from a third-party provider Adyen.
Current Execution Flow:
Apple Pay JS API script element is injected
<script type="text/javascript" async="" src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"></script>
Triggers below to check apple pay readiness, different ${merchantId_credential} is used:
await window.ApplePaySession.applePayCapabilities(`${merchantId_credential}`);
(**ApplePaySession is a valid object at this point)
Observed that different paymentCredentialStatus is returned
// nonprod env
{
"paymentCredentialStatus": "applePayUnsupported" // unexpected
}
// prod env
{
"paymentCredentialStatus": "paymentCredentialStatusUnknown"
}
The same code is executed in each environment and the behaviour was also the same, but has changed since then.
Side notes
By checking the SDK’s internal code, we saw that in third-party browsers it makes an extra call to the following endpoint. Responses from this call also come back differently depending on the merchantId.
When invoking below:
curl -X POST \
https://smp-paymentservices.apple.com/paymentservices/v3/checkStatus/merchant/{merchantId} \
-H 'Content-Type: application/json' \
-d '{
"initiative": "web",
"initiativeContext": "env_specific_domain"
}'
Our non-prod environment returns {"registered":false} while using prod's merchantId and domain it returns {"registered":true}. We thought the issue might be domain-related since the environments are on different domains, but so far, no luck.
The main questions we're looking to resolve are:
Why did the behavior change at a certain point despite no code changes? How should we approach this investigation, and what specific requests should we be making to the Adyen team?
Why does the response from the call to https://smp-paymentservices.apple.com/paymentservices/v3/checkStatus/merchant/{merchantId} return different results? Perhaps this could provide a clue regarding the question above?
We noticed that canMakePayments() is returning true, so we could consider using that as a workaround. Would it be safe to change the source of truth relying on canMakePayments() for displaying Apple Pay?
There is a concern that this issue may also occur in our production environment, so we would appreciate assistance in understanding what is happening and finding a resolution.
I am working on implementing merchant token notifications. When calling this endpoint https://developer.apple.com/documentation/merchanttokennotificationservices/merchant-token-event-retrieval, the result contains a CardMetadata object with an expirationDate field (see https://developer.apple.com/documentation/merchanttokennotificationservices/cardmetadata). What is the format of this field? The spec only mentions that it has a maximum length of 8 characters.
Hi,
We have app in which we take donations from people and send to non-profit organisations. I have read that Apple Pay can be integrated on non profit platforms to take donations, but we are middle man, we are not non profit .. we take donations, cut our platform fees and then sent to donations to non profit orgs.
My question is can we integrate Apple Pay in our iOS app to take donations from apple? as we have integrated Apple Pay on the web.
Topic:
App & System Services
SubTopic:
Apple Pay
Tags:
Apple Pay on the Web
Apple Pay
Tap to Pay on iPhone
We have finished integrating Apple Pay in our app and our payment processor is requiring us to send the 3dSecure version used for apple pay (2.1,2.2,2.3,etc.). I believe this only applies to mastercard but would appreciate if anyone has run into something similar and what you specified. I have not been able to find anything in Apple's documentation specifying the version that is used.
We’ve noticed that the ApplePaySession.applePayCapabilities() check has stopped working correctly in Safari over the past couple of days.
Behavior observed:
1.) In Safari Private Window, paymentCredentialStatus behaves as expected and case 1 is triggered.
2.) In a normal Safari window, it always triggers case 3 (paymentCredentialsUnavailable), even when the user has active cards provisioned in Wallet.
We tested across multiple devices, and the behavior is consistent.
if (window.ApplePaySession) {
var merchantIdentifier = 'YOUR MERCHANT IDENTIFIER';
var promise = ApplePaySession.applePayCapabilities(merchantIdentifier);
promise.then(function(capabilities) {
switch (capabilities.paymentCredentialStatus) {
case "paymentCredentialsAvailable":
// Show Apple Pay button as primary option
case "paymentCredentialStatusUnknown":
// Offer Apple Pay
case "paymentCredentialsUnavailable":
// Consider showing Apple Pay button
case "applePayUnsupported":
// Don’t show Apple Pay button
}
})
}
This used to work fine until a few days ago, but now the capability check in non-private Safari windows always indicates unavailable, even with valid active cards.
Has anyone else faced this issue recently? Could this be a Safari regression or a change on Apple’s side?
Thanks in advance!
Hi - I have a question. I am trying to understand when Apple Pay will be available on non-IOS desktop devices (specifically Google Chrome). I was hoping to understand better the process, specifically the following:
How can I get the Apple Pay QR code installed on my desktop checkout page on Google Chrome?
How long does this process usually take?
If I work with Stripe, do I need to get approval from them to install the Apple QR code onto my Google Chrome checkout page?
Is this readily available to all merchants (i.e., installing Apple Pay on Google Chrome)/
I have not seen this on any other checkout pages yet. Are there any examples you could point me to of merchants that have installed Apple Pay onto non-IOS desktop so I could trial the process (i.e., a list of existing merchants that have put the QR code onto their Google Chrome checkout pages)?
We are writing to report a recurring stability issue with the Apple Pay sandbox environment. We are using the official sandbox test cards provided on the Apple Developer website for our testing:
https://developer.apple.com/apple-pay/sandbox-testing/
We are experiencing frequent, intermittent failures when attempting to add these sandbox cards to the Wallet for testing purposes. The issue typically occurs a couple of times per day. When the failure occurs, the card provisioning process fails unexpectedly.
The issue is not limited to a single card; we have observed this behavior across all available card networks. In some instances, all cards (Visa, Mastercard, Discover, Amex) fail to provision simultaneously. At other times, the issue appears to be isolated to specific networks while others work correctly.
Crucially, the issue appears to be temporary. After some time passes (ranging from minutes to an hour), we are able to add the exact same card successfully without making any changes to our test environment or configuration.
We have diligently checked our setup to rule out configuration errors on our end. This includes verifying:
The device is set to a supported region.
We are signed in with a valid sandbox tester Apple ID.
All other prerequisites for sandbox testing are met.
The fact that the process works correctly at other times strongly suggests that this is a server-side stability issue within the Apple Pay sandbox environment rather than a persistent misconfiguration on our part.
To help with your investigation, we have attached an image that demonstrates a failed attempt to add a card.
Could you please investigate the stability of the sandbox card provisioning service? Please let us know if this is a known issue or if there is any further information we can provide.
Thank you for your time and assistance.
Hello,
I am currently testing an Adyen integration with Sylius and need to verify Apple Pay with Cartes Bancaires in the sandbox environment. Could you please advise how Cartes Bancaires can be tested in Apple Pay Sandbox (e.g. cards details)?
Thank you in advance for your guidance.
Best regards,
Grzegorz
MacOS: 12 ( Monterrey )
Safari: 17.6
Demo Site: https://applepaydemo.apple.com/
At the bottom where the Apple Pay button should appear, I see a warning something like "This browser doesn't support Apple Pay, please use safari" along with a link to requirements for apple pay.
All the requirements are fulfilled, OS and Safari's version are above the minimum required.
Link was opened in Safari.
And the other thing is if I open the same site in Chrome, I can see the apple pay button and when I click on it a QR appears which is the expected behaviour.
How to resolve this?
Hey,
I am trying to implement the apple pay process pay backend service,
I have checked everything and somehow it fails. I only have 1 certificate for merchant and 1 for the apple pay process, I have the private keys and try to run this following code that fails -
import crypto from 'crypto';
import fs from 'fs';
import forge from 'node-forge';
const MERCHANT_ID_FIELD_OID = '1.2.840.113635.100.6.32';
function decryptedToken()
{
const token = "";
const ephemeralPublicKey = "";
const encryptedData = "";
//===================================
// Import certs
//===================================
const epk = Buffer.from(ephemeralPublicKey, 'base64');
const merchantCert = fs.readFileSync('merchant_full.pem', 'utf8')
const paymentProcessorCert = fs.readFileSync("apple_pay_private.pem");
//===================================
let symmetricKey = '';
try {
symmetricKey = restoreSymmetricKey(epk, merchantCert, paymentProcessorCert);
} catch (err) {
throw new Error(`Restore symmetric key failed: ${err.message}`);
}
try {
//-----------------------------------
// Use the symmetric key to decrypt the value of the data key
//-----------------------------------
const decrypted = JSON.parse(decryptCiphertextFunc(symmetricKey, encryptedData));
console.log("Decrypted Token:", decrypted);
// const preppedToken = prepTabaPayToken(token, decrypted)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Send decrypted token back to frontend
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// res.send(preppedToken);
} catch (err) {
throw new Error(`Decrypt cipher data failed: ${err.message}`);
}
}
// extractMerchantID -
const extractMerchantID = (merchantCert) => {
//===================================
// Extract merchant identification from public key certificate
//===================================
try {
const info = forge.pki.certificateFromPem(merchantCert);
const result = info['extensions'].filter(d => d.id === MERCHANT_ID_FIELD_OID);
//-----------------------------------
// Return
//-----------------------------------
return result[0].value.toString().substring(2);
} catch (err) {
throw new Error(Unable to extract merchant ID from certificate: ${err});
}
}
// generateSharedSecret -
const generateSharedSecret = (merchantPrivateKey, ephemeralPublicKey) => {
//===================================
// Use private key from payment processing certificate and the ephemeral public key to generate
// the shared secret using Elliptic Curve Diffie*Hellman (ECDH)
//===================================
const privateKey = crypto.createPrivateKey({
key: merchantPrivateKey,
format: "pem",
type: "sec1", // because it's "EC PRIVATE KEY"
});
const publicKey = crypto.createPublicKey({
key: ephemeralPublicKey,
format: 'der',
type: 'spki'
});
//-----------------------------------
// Return
//-----------------------------------
return crypto.diffieHellman({privateKey,publicKey: publicKey,});
//-----------------------------------
}
// getSymmetricKey -
const getSymmetricKey = (merchantId, sharedSecret) => {
//===================================
// Get KDF_Info as defined from Apple Pay documentation
//===================================
const KDF_ALGORITHM = '\x0didaes256GCM';
const KDF_PARTY_V = Buffer.from(merchantId, 'hex').toString('binary');
const KDF_PARTY_U = 'Apple';
const KDF_INFO = KDF_ALGORITHM + KDF_PARTY_U + KDF_PARTY_V;
//-----------------------------------
// Create hash
//-----------------------------------
const hash = crypto.createHash('sha256');
hash.update(Buffer.from('000000', 'hex'));
hash.update(Buffer.from('01', 'hex'));
hash.update(Buffer.from(sharedSecret, 'hex'));
hash.update(KDF_INFO, 'binary');
//-----------------------------------
// Return
//-----------------------------------
return hash.digest('hex');
//-----------------------------------
}
// restoreSymmetricKey -
const restoreSymmetricKey = (ephemeralPublicKey, merchantCert, paymentProcessorCert) => {
//===================================
// 3.a Use the payment processor private key and the ephemeral public key, to generate the shared secret
//===================================
const sharedSecret = generateSharedSecret(paymentProcessorCert, ephemeralPublicKey);
//-----------------------------------
// 3.b Use the merchant identifier of the public key certificate and the shared secret, to derive the symmetric key
//-----------------------------------
const merchantId = extractMerchantID(merchantCert);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Return
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
console.log("Merchant ID:", merchantId);
console.log("Shared Secret (hex):", sharedSecret);
return getSymmetricKey(merchantId, sharedSecret);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
// decryptCiphertextFunc -
const decryptCiphertextFunc = (symmetricKey, encryptedData) => {
console.log("🔑 Decrypting Ciphertext with Symmetric Key:", symmetricKey);
//===================================
// Get symmetric key and initialization vector
//===================================
const buf = Buffer.from(encryptedData, 'base64');
const SYMMETRIC_KEY = Buffer.from(symmetricKey, 'hex');
const IV = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); // Initialization vector of 16 null bytes
const CIPHERTEXT = buf.slice(0, -16);
//-----------------------------------
// Create and return a Decipher object that uses the given algorithm and password (key)
//-----------------------------------
const decipher = crypto.createDecipheriv("aes-256-gcm", SYMMETRIC_KEY, IV);
const tag = buf.slice(-16, buf.length);
decipher.setAuthTag(tag);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Load encrypted token into Decipher object
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let decrypted = decipher.update(CIPHERTEXT);
console.log("🔑 Decrypted Data");
decrypted += decipher.final();
//:::::::::::::::::::::::::::::::::::
// Return
//:::::::::::::::::::::::::::::::::::
return decrypted;
//:::::::::::::::::::::::::::::::::::
}
decryptedToken();
Hi everyone,
We’ve recently run into an issue with Apple Pay on the web and would appreciate some clarification.
Background:
Previously, we integrated Apple Pay without using the Apple Pay JS SDK.
We relied on ApplePaySession.canMakePayments() to check availability, and it worked fine.
After Apple announced support for browsers beyond Safari, we switched to the Apple Pay JS SDK.
According to Apple’s documentation, we should now use applePayCapabilities() for capability checks in third-party browsers.
Our current behavior:
We implemented applePayCapabilities().
Initially, it was returning either paymentCredentialStatusUnknown or paymentCredentialsUnavailable.
Based on those values, we displayed the Apple Pay button.
The problem:
About a week ago, on the same device/browser, applePayCapabilities() started returning applePayUnsupported.
Setup: MacBook Pro 13-inch (M1, 2020), Google Chrome Version 136.0.7103.93.
The Apple documentation says: “Don’t show an Apple Pay button or offer Apple Pay” when the result is applePayUnsupported.
However, at the same time, canMakePayments() is returning true.
This creates a direct conflict between the two recommendations:
canMakePayments() → true ⇒ show the button.
applePayCapabilities() → applePayUnsupported ⇒ don’t show the button.
Question:
What’s the correct approach here?
Should we prioritize applePayCapabilities() and hide the button, or is it acceptable to continue relying only on canMakePayments() as the source of truth for showing Apple Pay?
Any insights from others who’ve run into this contradiction would be very helpful.
Thanks in advance!
Hello,
We are experiencing a consistent delay when initiating Apple Pay sessions using the https://apple-pay-gateway.apple.com/paymentservices/startSession endpoint. Below is a detailed overview of our setup and the issue.
Setup
Our web service is hosted in AWS and there is a proxy server between our web service and Apple servers.
We are passing the correct domain in the initiativeContext field of the startSession request.
The .well-known/apple-developer-merchantid-domain-association file is hosted on a different domain, which is also correctly configured and associated with our merchant ID in the Apple Developer portal.
Observed Behavior
When the same request is made from a local development environment, Apple responds immediately (under 1 second).
When the request is made from our AWS-hosted service, Apple responds with a valid session, but only after a consistent ~15-second delay.
The content and response are otherwise identical — only the timing differs.
We would appreciate any insights or suggestions from others who have faced similar behavior or from the Apple Pay team.
Thank you in advance!
Hi,
We’re implementing Apple Pay on the Web for a multi-tenant platform via a PSP. The PSP operates multiple HSM/clusters and gave us multiple CSRs, asking us to register all.
Our understanding: a Merchant ID can hold several PPCs over time, but only one is active at once.
Questions
Is there any supported way to keep more than one PPC active simultaneously for the same Merchant ID?
If not, what does Apple recommend for web-only, multi-tenant setups: a single MID with PSP-side decryption & sub-merchant separation, or separate MIDs per brand/region?
Any official guidance on PPC rotation and handling many domains for Apple Pay on the Web?
links to official docs or prior Apple responses would be appreciated.
We are experiencing intermittent 403 Forbidden errors during Apple Pay on web merchant validation in our production and sandbox environment.
Has anyone else started seeing 403 Forbidden errors recently (since mid-2025)?
Why would merchant validation be sometimes successful and sometimes fail with 403?
Could this be related to new Apple Pay gateway changes or stricter validation rules?
Any additional debug steps or permanent solutions we should try?
Thank you.
We are an acquirer/payment provider offering Apple Pay. Our merchants use our hosted checkout to accept payments. After a user pays with Apple Pay on our checkout, the Wallet transaction record shows our checkout domain as the payee. We would like it to display the merchant’s brand/name so users can recognize or contact the merchant.
Is there any parameter or configuration that controls what Wallet shows as the payee? For example, can this be set via a specific field/parameter, or is it strictly derived from the Merchant ID’s display name (or other Apple Pay configuration)? What is the correct approach for a PSP/acquirer to have the merchant’s brand shown in Wallet transaction record?
Additional detail: The field in question is the merchant/payee name shown in the Apple Wallet receipt—directly under the transaction amount at the top of the receipt, and again beneath the “Total” line.
{
"epochTimestamp": 1755169981033,
"expiresAt": 1755173581033,
"merchantSessionIdentifier": "SSH4ADF1D97A60B47FC8537037BE9892237_FF777A9CB5E9EDAB38A01E4EDF71CB5572F19153853DAC70ADC5AA3E75877CB4",
"nonce": "b6f1e016",
"merchantIdentifier": "7C52E6BFA112124092008236BE1EE49791E4E82E9082AD9AC98D55B03A088120",
"domainName": "1960-ikffk.checkout.trypeppr.com",
"displayName": "peppr",
"signature": "308006092a864886f70d010702a0803080020101310d300b0609608648016503040201308006092a864886f70d0107010000a080308203ee30820394a00302010202080e7210e510586e34300a06082a8648ce3d040302307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b3009060355040613025553301e170d3231303131303032313632395a170d3236303130393032313632395a306b3131302f06035504030c286563632d736d702d62726f6b65722d7369676e5f5543342d50524f445f4b727970746f6e5f45434331143012060355040b0c0b694f532053797374656d7331133011060355040a0c0a4170706c6520496e632e310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d0301070342000466e0ea0e787dcb3f66bc533189da2bda08ed9574e421117aa1af2cc310f6a8b19ca3e77ed00fa84e8df2ac8688e529866e76ebad89eda5b7c336e0f0d8a7d05da38202113082020d300c0603551d130101ff04023000301f0603551d2304183016801423f249c44f93e4ef27e6c4f6286c3fa2bbfd2e4b304506082b0601050507010104393037303506082b060105050730018629687474703a2f2f6f6373702e6170706c652e636f6d2f6f63737030342d6170706c65616963613330323082011d0603551d2004820114308201103082010c06092a864886f7636405013081fe3081c306082b060105050702023081b60c81b352656c69616e6365206f6e207468697320636572746966696361746520627920616e7920706172747920617373756d657320616363657074616e6365206f6620746865207468656e206170706c696361626c65207374616e64617264207465726d7320616e6420636f6e646974696f6e73206f66207573652c20636572746966696361746520706f6c69637920616e642063657274696669636174696f6e2070726163746963652073746174656d656e74732e303606082b06010505070201162a687474703a2f2f7777772e6170706c652e636f6d2f6365727469666963617465617574686f726974792f30340603551d1f042d302b3029a027a0258623687474703a2f2f63726c2e6170706c652e636f6d2f6170706c6561696361332e63726c301d0603551d0e0416041457c735942abd9ea2feccd3cbe7ede0a37c8cc5fa300e0603551d0f0101ff040403020780300f06092a864886f76364061d04020500300a06082a8648ce3d0403020348003045022100f2fa622622128cd1e1642084bc4117ccdede7289690e864cfb88abb43e04338e022065f85a90b82711d1fd762e0b59c45496e9e683c265c8279998e37872feae46ec308202ee30820275a0030201020208496d2fbf3a98da97300a06082a8648ce3d0403023067311b301906035504030c124170706c6520526f6f74204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b3009060355040613025553301e170d3134303530363233343633305a170d3239303530363233343633305a307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004f017118419d76485d51a5e25810776e880a2efde7bae4de08dfc4b93e13356d5665b35ae22d097760d224e7bba08fd7617ce88cb76bb6670bec8e82984ff5445a381f73081f4304606082b06010505070101043a3038303606082b06010505073001862a687474703a2f2f6f6373702e6170706c652e636f6d2f6f63737030342d6170706c65726f6f7463616733301d0603551d0e0416041423f249c44f93e4ef27e6c4f6286c3fa2bbfd2e4b300f0603551d130101ff040530030101ff301f0603551d23041830168014bbb0dea15833889aa48a99debebdebafdacb24ab30370603551d1f0430302e302ca02aa0288626687474703a2f2f63726c2e6170706c652e636f6d2f6170706c65726f6f74636167332e63726c300e0603551d0f0101ff0404030201063010060a2a864886f7636406020e04020500300a06082a8648ce3d040302036700306402303acf7283511699b186fb35c356ca62bff417edd90f754da28ebef19c815e42b789f898f79b599f98d5410d8f9de9c2fe0230322dd54421b0a305776c5df3383b9067fd177c2c216d964fc6726982126f54f87a7d1b99cb9b0989216106990f09921d00003182018930820185020101308186307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b300906035504061302555302080e7210e510586e34300b0609608648016503040201a08193301806092a864886f70d010903310b06092a864886f70d010701301c06092a864886f70d010905310f170d3235303831343131313330315a302806092a864886f70d010934311b3019300b0609608648016503040201a10a06082a8648ce3d040302302f06092a864886f70d010904312204209378ff57580c3205e9ea38d985a2e9ca2db7f06db29b7560f585561a23894402300a06082a8648ce3d04030204483046022100fad47e840779070d097ef91cd4bfa5381d77426071cb38c1cdc77ff9460ba1470221009215c246893bff0983052caaae610a16117237e73ab36d859008e7b234670eaa000000000000",
"operationalAnalyticsIdentifier": "peppr:7C52E6BFA112124092008236BE1EE49791E4E82E9082AD9AC98D55B03A088120",
"retries": 0,
"pspId": "7C52E6BFA112124092008236BE1EE49791E4E82E9082AD9AC98D55B03A088120"
}
This is generated in the onvalidatemerchant event handler, and passed into session.completeMerchantValidation.
Using a sandbox account with linked cards, the next thing that happens is a "payment not completed" message in the ApplePay popup on the page, and the oncancel event is hit
Inspecting the event, I don't see anything that hints at the issue. There is a sessionError object, but its code is "unknown" and the info object is empty.