Apple Pay - Payment Not Completed Error

I’m attempting to integrate Apple Pay with the existing Web Payments SDK, and I’m facing an issue.

Sandbox Application ID: sandbox-sq0idb-Cy6QuV_eqqgldwD2kwrABQ
Location ID: 733JJPMXQA97X
Apple Merchant ID: merchant.io.applova.square.733JJPMXQA97X

I have added my Sandbox Domain and have verified it.

When attempting to make the payment, the Apple Pay Payment dialog pops up. When biometric authorisation is given, then I see a “Payment not completed” message on the Apple Pay pop-up, and it dismisses automatically.

{
function loadSquareSdkAndInitApplePay(sdkUrl, applicationId, locationId) {
debugLog(‘Loading Square Web Payments SDK from: ’ + sdkUrl, ‘info’);
var script = document.createElement(‘script’);
script.src = sdkUrl;
script.onload = function() {
debugLog(‘Square Web Payments SDK loaded successfully’, ‘info’);
initializeSquareApplePay(applicationId, locationId);
};
script.onerror = function() {
debugLog(‘Failed to load Square Web Payments SDK’, ‘error’);
var wrapper = document.querySelector(’.apple-pay-button-wrapper’);
if (wrapper) { wrapper.style.display = ‘none’; }
};
document.head.appendChild(script);
}

function initializeSquareApplePay(applicationId, locationId) {
    debugLog('Initializing Square Apple Pay - AppId: ' + applicationId + ', LocationId: ' + locationId, 'info');

    var requestId = $('#apple-pay-request-id').val();
    var amount = parseFloat($('#apple-pay-amount').val());
    var currency = $('#apple-pay-currency').val();
    var tipAmount = parseFloat($('#apple-pay-tip').val() || '0');
    var subTotal = parseFloat($('#apple-pay-subtotal').val() || amount.toString());
    var completeUrl = $('#apple-pay-complete-url').val();
    var billingRequiredVal = $('#apple-pay-billing-address-required').val();
    var billingRequired = billingRequiredVal === 'true' || billingRequiredVal === true;

    debugLog('Square Apple Pay params — requestId: ' + requestId + ', amount: ' + amount
        + ', currency: ' + currency + ', tip: ' + tipAmount + ', subTotal: ' + subTotal, 'info');

    if (applicationId && applicationId.indexOf('sandbox-') === 0) {
        debugLog('⚠️ SANDBOX mode detected (appId starts with "sandbox-"). '
            + 'Apple Pay requires Apple Pay sandbox test cards — real cards will show "payment not completed". '
            + 'Add sandbox tester cards via Apple Developer portal to test end-to-end.', 'warn');
    }

    if (!window.Square) {
        debugLog('Square SDK not available after load — hiding Apple Pay button', 'error');
        var wrapper = document.querySelector('.apple-pay-button-wrapper');
        if (wrapper) { wrapper.style.display = 'none'; }
        return;
    }

    var payments;
    try {
        payments = Square.payments(applicationId, locationId);
        debugLog('Square.payments() initialized', 'info');
    } catch (e) {
        debugLog('Failed to initialize Square.payments(): ' + e.message, 'error');
        var wrapper = document.querySelector('.apple-pay-button-wrapper');
        if (wrapper) { wrapper.style.display = 'none'; }
        return;
    }

    var lineItems = [];
    if (subTotal > 0) {
        lineItems.push({ label: 'Subtotal', amount: subTotal.toFixed(2), pending: false });
    }
    if (tipAmount > 0) {
        lineItems.push({ label: 'Tip', amount: tipAmount.toFixed(2), pending: false });
    }

    var paymentRequestConfig = {
        countryCode: 'US',
        currencyCode: currency,
        lineItems: lineItems,
        total: { label: 'Total', amount: amount.toFixed(2), pending: false }
    };
    debugLog('Square paymentRequest config: ' + JSON.stringify(paymentRequestConfig), 'info');

    var squarePaymentRequest = payments.paymentRequest(paymentRequestConfig);

    var squareApplePay = null;
    payments.applePay(squarePaymentRequest).then(function(applePay) {
        squareApplePay = applePay;
        debugLog('Square applePay instance ready — showing button', 'info');

        var wrapper = document.querySelector('.apple-pay-button-wrapper');
        if (wrapper) { wrapper.style.display = 'block'; }

        // Define the global startApplePaySession so the button onclick calls it
        window.startApplePaySession = function() {
            var billingModal = document.getElementById('apple-pay-billing-modal');
            if (billingModal && billingRequired) {
                debugLog('Billing address required — showing modal before Square Apple Pay', 'info');
                pendingApplePayBilling = null;
                $('#apple-pay-billing-address').val('');
                $('#apple-pay-billing-zip').val('');
                $('#apple-pay-billing-address-error').text('');
                $('#apple-pay-billing-zip-error').text('');
                $('#apple-pay-billing-address').removeClass('billing-input-error');
                $('#apple-pay-billing-zip').removeClass('billing-input-error');
                $('#apple-pay-billing-modal').addClass('is-visible').css('display', 'flex');
                return;
            }
            triggerSquareApplePay(squareApplePay, completeUrl, requestId);
        };

        // Wire the billing modal submit button to continue to Square tokenization
        window.beginApplePaySession = function() {
            triggerSquareApplePay(squareApplePay, completeUrl, requestId);
        };

    }).catch(function(e) {
        debugLog('Square applePay() not available: ' + e.message, 'warn');
        var wrapper = document.querySelector('.apple-pay-button-wrapper');
        if (wrapper) { wrapper.style.display = 'none'; }
    });
}

function triggerSquareApplePay(squareApplePay, completeUrl, requestId) {
    debugLog('Triggering Square Apple Pay tokenization...', 'info');
    // NOTE: Do NOT show the processing overlay before tokenize() on mobile.
    // Showing a full-page overlay before the Apple Pay sheet can interfere with
    // the user gesture chain and cause the sheet to be dismissed immediately.
    // The overlay is shown only after the user authorizes (status OK).

    squareApplePay.tokenize().then(function(tokenResult) {
        // Log the full result — this is our primary diagnostic tool
        try {
            debugLog('Square tokenize() full result: ' + JSON.stringify(tokenResult), 'info');
        } catch (jsonErr) {
            debugLog('Square tokenize() status: ' + tokenResult.status + ' (could not serialize full result)', 'info');
        }

        if (tokenResult.status === 'OK') {
            debugLog('Square Apple Pay authorized — showing processing overlay', 'info');
            $('#processing-view').show();
            $('.overlay').show();
            var requestData = { squareNonce: tokenResult.token };
            if (pendingApplePayBilling) {
                requestData.billingAddress = pendingApplePayBilling.address;
                requestData.billingZip = pendingApplePayBilling.zip;
                pendingApplePayBilling = null;
            }
            debugLog('Sending Square nonce to backend: ' + completeUrl, 'info');
            sendSquareApplePayNonce(completeUrl, requestData);

        } else if (tokenResult.status === 'Cancel') {
            // User dismissed the Apple Pay sheet — restore UI without an error message
            debugLog('Apple Pay sheet dismissed (status: Cancel) — restoring UI', 'info');
            $('#processing-view').hide();
            $('.overlay').hide();

        } else {
            // Actual tokenization failure — extract every detail Square provides
            debugLog('Square tokenize() error — status: ' + tokenResult.status, 'error');
            $('#processing-view').hide();
            $('.overlay').hide();
            var errMsg = 'Apple Pay failed. Please try again.';
            if (tokenResult.errors && tokenResult.errors.length > 0) {
                tokenResult.errors.forEach(function(err, idx) {
                    debugLog('  Error[' + idx + '] field: ' + (err.field || 'n/a')
                        + ' | type: ' + (err.type || 'n/a')
                        + ' | message: ' + (err.message || 'n/a'), 'error');
                });
                errMsg = tokenResult.errors[0].message || errMsg;
            } else {
                debugLog('  No error details provided by Square SDK for status: ' + tokenResult.status, 'warn');
            }
            showError(errMsg, true);
        }
    }).catch(function(e) {
        debugLog('Square tokenize() threw an exception: ' + (e.message || e), 'error');
        if (e.stack) {
            debugLog('Exception stack: ' + e.stack, 'error');
        }
        $('#processing-view').hide();
        $('.overlay').hide();
        var msg = (e.message || '').toLowerCase();
        if (msg.indexOf('cancel') !== -1 || msg.indexOf('dismiss') !== -1) {
            debugLog('Apple Pay cancelled (surfaced as exception)', 'info');
        } else {
            showError('Apple Pay failed. Please try again.', true);
        }
    });
}

function sendSquareApplePayNonce(completeUrl, requestData) {
    var xhr = new XMLHttpRequest();
    xhr.open('POST', completeUrl, true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.timeout = 30000;

    xhr.onload = function() {
        debugLog('Square Apple Pay completion response - HTTP ' + xhr.status, 'info');
        var response = null;
        try { response = JSON.parse(xhr.responseText); } catch (e) { /* non-JSON */ }

        if (xhr.status >= 200 && xhr.status < 300 && response && response.status === 'success') {
            debugLog('Square Apple Pay payment successful — redirecting', 'info');
            $('#processing-view').hide();
            $('.overlay').hide();
            $('#apple-pay-billing-modal').removeClass('is-visible').css('display', 'none');
            window.location.href = response.redirectUrl;
        } else {
            debugLog('Square Apple Pay payment failed', 'error');
            $('#processing-view').hide();
            $('.overlay').hide();
            var msg = (response && response.error) ? response.error : 'Payment failed. Please try again.';
            showError(msg, true);
        }
    };

    xhr.onerror = function() {
        $('#processing-view').hide();
        $('.overlay').hide();
        showError('Network error. Please check your connection and try again.', true);
    };

    xhr.ontimeout = function() {
        $('#processing-view').hide();
        $('.overlay').hide();
        showError('Request timed out. Please try again.', true);
    };

    xhr.send(JSON.stringify(requestData));
}

}

Front End Logs:

[12:06:29 AM] [INFO] Digital Wallet module loaded
[12:06:29 AM] [INFO] Debug log panel found: yes
[12:06:29 AM] [INFO] Debug log content found: yes
[12:06:29 AM] [INFO] Running in regular browser (not WebView)
[12:06:29 AM] [INFO] Platform: iPad
[12:06:29 AM] [INFO] isSimulator() result: false
[12:06:29 AM] [INFO] Checking Apple Pay availability… Provider: squareup
[12:06:29 AM] [INFO] Checking Apple Pay availability…
[12:06:29 AM] [INFO] ApplePaySession API found (Safari)
[12:06:29 AM] [INFO] ApplePaySession.canMakePayments() = true
[12:06:29 AM] [INFO] User Agent: Mozilla/5.0 (iPad; CPU OS 26_3_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/142.0.7444.128 Mobile/15E148 Safari/604.1
[12:06:29 AM] [INFO] isWebView() result: true
[12:06:29 AM] [INFO] ReactNativeWebView available: false
[12:06:29 AM] [INFO] webkit.messageHandlers available: true
[12:06:29 AM] [WARN] Apple Pay: Running in WebView - Apple Pay may be restricted by Apple security policies
[12:06:29 AM] [INFO] Square provider: loading Square Web Payments SDK for Apple Pay
[12:06:29 AM] [INFO] Loading Square Web Payments SDK from: https://sandbox.web.squarecdn.com/v1/square.js
[12:06:29 AM] [INFO] Google Pay initialization starting (non-digital-wallet page)…
[12:06:29 AM] [INFO] Environment: PRODUCTION
[12:06:29 AM] [INFO] User Agent: Mozilla/5.0 (iPad; CPU OS 26_3_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/142.0.7444.128 Mobile/15E148 Safari/604.1
[12:06:29 AM] [INFO] isWebView() result: true
[12:06:29 AM] [INFO] ReactNativeWebView available: false
[12:06:29 AM] [INFO] webkit.messageHandlers available: true
[12:06:29 AM] [INFO] WebView detected: true
[12:06:29 AM] [INFO] Platform: iPad
[12:06:29 AM] [INFO] isSimulator() result: false
[12:06:29 AM] [INFO] Simulator detected: false
[12:06:29 AM] [INFO] :white_check_mark: Google Pay JS API loaded successfully
[12:06:29 AM] [INFO] Testing Google Pay in simulators:
[12:06:29 AM] [INFO] - Android Emulator: Requires Google Play Services and test account
[12:06:29 AM] [INFO] - iOS Simulator: Use Chrome browser, may have limitations
[12:06:29 AM] [INFO] - Best practice: Test on real devices for production
[12:06:29 AM] [INFO] Initializing Google Pay…
[12:06:29 AM] [INFO] Google Pay config - RequestId: 69f1ad01e60a3f0d9d95396e, Amount: 6.36, Currency: USD, Tip: 0, SubTotal: 6.36, Type: GATEWAY, Environment: PRODUCTION
[12:06:29 AM] [INFO] Google Pay Type: GATEWAY - Using payment gateway tokenization
[12:06:29 AM] [WARN] :warning: Google Pay Merchant ID is missing. Google Pay will not be available.
[12:06:29 AM] [INFO] Square Web Payments SDK loaded successfully
[12:06:29 AM] [INFO] Initializing Square Apple Pay - AppId: sandbox-sq0idb-Cy6QuV_eqqgldwD2kwrABQ, LocationId: 733JJPMXQA97X
[12:06:29 AM] [INFO] Square Apple Pay params — requestId: 69f1ad01e60a3f0d9d95396e, amount: 6.36, currency: USD, tip: 0, subTotal: 6.36
[12:06:29 AM] [WARN] :warning: SANDBOX mode detected (appId starts with “sandbox-”). Apple Pay requires Apple Pay sandbox test cards — real cards will show “payment not completed”. Add sandbox tester cards via Apple Developer portal to test end-to-end.
[12:06:29 AM] [INFO] Square.payments() initialized
[12:06:29 AM] [INFO] Square paymentRequest config: {“countryCode”:“US”,“currencyCode”:“USD”,“lineItems”:[{“label”:“Subtotal”,“amount”:“6.36”,“pending”:false}],“total”:{“label”:“Total”,“amount”:“6.36”,“pending”:false}}
[12:06:29 AM] [INFO] Square applePay instance ready — showing button
[12:06:36 AM] [INFO] Triggering Square Apple Pay tokenization…
[12:06:45 AM] [INFO] Square tokenize() full result: {“status”:“Cancel”}
[12:06:45 AM] [INFO] Apple Pay sheet dismissed (status: Cancel) — restoring UI

The device we are using is a Sandbox Account. And we have added Test Cards from Apple.

There’s no other information on why the payment doesn’t go through.

Please assist.

@Bryan-Square Any assistance here would be appreciated,

@nHiRanZ If you clone the Web Payments SDK quickstart project, are you getting the same erroneous behavior in there?

Hi @josh-square, I followed the instructions on the repo. The same issue occurs. I’m attaching a screen recording below.

Please assist. We’re stuck here.

Only console log we see is:

ERROR: Tokenization failed with status: Cancel

@josh-square @Bryan-Square Any update on this, guys? We’re blocked here. The React Native App with the Square SDK for Apple Pay with the same credentials works fine.

@josh-square @Bryan-Square any update guys?

Hi @nHiRanZ, apologies for the delay here. I’ve been unable to reproduce this issue in my own test environment, using a real card. With the information we have so far, it looks like the issue may be with the test cards you’re using. If you try another card, are you able to successfully complete a payment with Apple Pay?

Hi @josh-square, nope. We tried multiple cards. Same issue. The thing is, the same cards that get declines like this on the Square Apple Pay Web work fine with the Square Apple Pay on Mobile React Native SDK.

Were you able to test with the credentials I provided?

@nHiRanZ Unfortunately I’m not able to test with your credentials myself. That said, it doesn’t sound like there are issues with your Square account setup (e.g. with the domain verification part of this). If the Apple Pay dialog is opening but the payment attempt is failing before the payment token gets generated through Web Payments SDK, that indicates the issue is likely either with the Apple account or the card.