Apple Pay

Apple Pay allows shoppers to pay with a credit or debit card using their Apple devices. Apple Pay is compatible with these devices.

Note: When returning the details of an order the actual credit or debit card is shown as payment method (e.g. "MAESTRO") instead of Apple Pay.

The used (sample) scripts can be downloaded from the sandbox environment:

Prerequisites

For Apple Pay the following prerequisites need to be fulfilled:

  • The shopper needs an Apple Pay compatible device.
  • Apple Pay (and relevant credit and debit card payment methods) needs to be enabled on your account. Contact us if this not yet the case.

Apple Pay in the Menu

Apple Pay is available in the menu if the prerequisites are fulfilled. No additional information is required in the create-request.

Apple Pay on your checkout page

This rest of this page covers how to implement Apple Pay on your own checkout page.

Besides, implementing two additional requests (Initialize an Apple Pay session and Authorize an Apple Pay payment) to the Payment Service, the Apple Pay JS API has to be used.

Merchant Enrollment

Apple Pay can only be used on your own checkout page after you have been enrolled as merchant at Apple. Part of the enrollment is the verification of your domain by Apple. We handle setting up the required IDs and certificates.

Contact us for details on the Enrollment as Apple Pay Merchant.

Apple Pay button

Apple has described how to display the Apple Pay Button using CSS templates in Safari.

Apple has strict requirements on the look, size and placement on the Apple Pay button. See the Human Interface Guidelines > Apple Pay for more details.

Payment Flow

The following diagram shows the payment flow when using Apple Pay on your checkout page.

Apple Pay Payment Flow

Creating an Order

An order has to be created before Apple Pay can be used. (See Create a new order.)

Checking for Apple Pay availability

Before showing the Apple Pay button to the shopper the availability of Apple Pay needs to be checked.

For more details see: Checking for Apple Pay Availability

Example javascript:

function canMakePaymentsWithApplePay() {
    if (window.ApplePaySession) {
        try {
            if (ApplePaySession.canMakePayments()) {
                return true;
            } else {
                console.log("Can not make Apple Pay payments.");
            }
        }
        catch (e) {
            console.log("Starting an Apple Pay session requires an secure document.", e);
        }
    } else {
        console.log("Apple Pay JS API is not available.");
    }

    return false;
}

Creating an Apple Pay session

After the shopper clicks on the Apple Pay button a session has to be created specifying the payment details.

The following payments details need to be provided in the request:

Field Type M Description
countryCode Country M The country of the merchant.
currencyCode Currency M The currency for the payment.
supportedNetworks String[] M The payment networks supported by the merchant. The supported values are 'visa', 'masterCard', 'maestro', 'vPay'. (Depending on the payment methods enabled on your account.)
merchantCapabilities String[] M The payment capabilities supported by the merchant. The only supported value is 'supports3DS'.
total Block M A line item representing the total for the payment.
+ label String(1, 128) M The name of the shop that is shown to the shopper.
+ amount float M The payment amount in major unit, i.e. including a decimal point.

The supported networks can be determined using: List payment methods of an Order

For more details see: Creating an Apple Pay Session

Example javascript:

    var request = {
        countryCode: 'NL',
        currencyCode: 'EUR',
        supportedNetworks: ['visa', 'masterCard', 'maestro', 'vPay'],
        merchantCapabilities: ['supports3DS'],
        total: { label: 'My Shop', amount: '10.00' }
    };

    var session = new ApplePaySession(4, request);

After the session is created, call its begin method to show the payment sheet.

Example javascript:

    session.begin()

Validating the merchant

Apple initiates the validation of the merchant when the payment sheet is shown using the On Validate Merchant event. The event parameter contains the validation URL attribute, which should be send to the Payment System in the Initialize an Apple Pay session request.

The returned response is the opaque Apple Pay merchant session in string format. This string needs to be converted to a JavaScript object before it can be passed to the Apple device.

If successful the returned merchant session must be used to complete the merchant validation. Otherwise, the session must be aborted.

Example javascript:

    session.onvalidatemerchant = function(event) {

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState === 4) {
                if (this.status === 201) {
                    session.completeMerchantValidation(JSON.parse(this.responseText));
                } else {
                    session.abort();
                }
            }

        };

        xhttp.open("POST", baseUrl + "/initialize", true);
        xhttp.setRequestHeader("Content-type", "application/json");
        xhttp.send('{ "validationUrl":"' + event.validationURL + '"' +
                   ', "displayName": "' + merchantDisplayName + '"' +
                   ', "domainName": "' + window.location.hostname + '"}');
    };

Authorizing the payment

Apple initiates the authorization of the payment when the shopper authenticates the payment with Touch ID or Face ID, using the On Payment Authorized event. The event parameter contains the payment attribute containing the encrypted card details. The payment attribute should be send as-is to the Payment System in the Authorize an Apple Pay payment request.

After the Payment System authorizes the payment the result must be used to complete the payment. This will show the result of the authorization on the payment sheet, and close the payment sheet after 2 minutes automatically.

Example javascript:

    session.onpaymentauthorized = function(event) {

        var xhttp = new XMLHttpRequest();

        xhttp.onreadystatechange = function() {
            if (this.readyState === 4) {
                try {
                    if (this.status === 200) {
                        session.completePayment({status: ApplePaySession.STATUS_SUCCESS});
                    } else {
                        session.completePayment({status: ApplePaySession.STATUS_FAILURE});
                    }
                }
                catch (e) {
                    // Ignore, canceling during the authorization will invalidate the session object,
                    // resulting in an InvalidAccessError.
                } finally {
                    setTimeout(function() { window.pollOrderStatus(); }, 2000);
                }

            }
        };

        xhttp.open("POST", baseUrl + "/authorize", true);
        xhttp.setRequestHeader("Content-type", "application/json");
        xhttp.send(JSON.stringify(event.payment));
    };

Note: The window.pollOrderStatus(); method is only available in the menu, and used to get the details of the order and redirect the shopper back to the webshop if appropriate. For your own menu, you should implement a similar function. The poll method is called after a 2000 ms delay. In our experience this is necessary to let the payment sheet close automatically reliable. Without this delay the payment sheet did not close on all devices.

When the shopper dismisses the payment sheet instead of authenticating the payment, the On Cancel event is called by Apple.

Example javascript:

    session.oncancel = function() {
        window.pollOrderStatus();
    };

Determining the status of the order

The Payment System sends status change notifications to the customer service agent application during the authorization of the payment, which should be used to get the order details from the Payment System.

The order details should be used to determine if the shopper has paid the order or that another payment attempt can be made by the shopper.

Full javascript example

Below is the full JavaScript that is used by the menu to support Apple Pay.

/**
 * Check that the Apple Pay JS API is available in the browser,
 * and that payments with Apple Pay are possible.
 *
 * @returns {boolean} true if Apple Pay payments are possible, false otherwise.
 * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/checking_for_apple_pay_availability">Checking for Apple Pay Availability</a>
 */
function canMakePaymentsWithApplePay() {
    if (window.ApplePaySession) {
        try {
            if (ApplePaySession.canMakePayments()) {
                return true;
            } else {
                console.log("Can not make Apple Pay payments.");
            }
        }
        catch (e) {
            console.log("Starting an Apple Pay session requires an secure document.", e);
        }
    } else {
        console.log("Apple Pay JS API is not available.");
    }

    return false;
}

/**
 * Authorize an Apple Pay payment.
 *
 * @param merchantKey The merchant key.
 * @param merchantDisplayName The name of the merchant to display.
 * @param orderKey The order key.
 * @param serverUrl The url of the ApplePayServer.
 * @param request The <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaypaymentrequest">ApplePayPaymentRequest</a> as JSON
 * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api">Apple Pay JS API</a>
 */
function authorizeApplePayPayment(merchantKey, merchantDisplayName, orderKey, serverUrl, request) {

    if (!canMakePaymentsWithApplePay()) return;

    var baseUrl = serverUrl + "/mobile/applepay/merchants/" + merchantKey + "/payments/" + orderKey;
    var session = new ApplePaySession(4, JSON.parse(request));

    /**
     * An event handler that is called when the payment sheet is displayed.
     *
     * @param event ApplePayValidateMerchantEvent, An event object that contains the validation URL (event.validationURL).
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778021-onvalidatemerchant">ApplePaySession.onvalidatemerchant</a>
     */

    session.onvalidatemerchant = function(event) {

        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState === 4) {
                if (this.status === 201) {
                    session.completeMerchantValidation(JSON.parse(this.responseText));
                } else {
                    session.abort();
                }
            }

        };

        xhttp.open("POST", baseUrl + "/initialize", true);
        xhttp.setRequestHeader("Content-type", "application/json");
        // Send the validation URL as received from the Apple device
        // Send the text for on the pay button
        // Send the current domain name of the website/shop
        xhttp.send('{ "validationUrl":"' + event.validationURL + '"' +
                   ', "displayName": "' + merchantDisplayName + '"' +
                   ', "domainName": "' + window.location.hostname + '"}');
    };

    /**
     * An event handler that is called when a new payment method is selected.
     *
     * Note: event.completePaymentMethodSelection() requires an ApplePayPaymentMethodUpdate instance as parameter with a newTotal.
     *
     * @param event ApplePayPaymentMethodSelectedEvent, An event object that contains the payment method (event.paymentMethod).
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778013-onpaymentmethodselected">ApplePaySession.onpaymentmethodselected</a>
     */
    // session.onpaymentmethodselected = function(event) {
    //     var update = {newTotal_to_be_defined};
    //     event.completePaymentMethodSelection(update);
    // };

    /**
     * An event handler that is called when a shipping method is selected.
     *
     * Note: event.completeShippingContactSelection() requires an ApplePayShippingMethodUpdate instance as parameter with a newTotal.
     *
     * @param event ApplePayShippingMethodSelectedEvent, An event object that contains the shipping method (event.shippingMethod).
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778028-onshippingmethodselected">ApplePaySession.onshippingmethodselected</a>
     */
    // session.onshippingcontactselected = function(event) {
    //     var update = {newTotal_to_be_defined};
    //     event.completeShippingContactSelection(update);
    // };

    /**
     * An event handler that is called when a shipping method is selected.
     *
     * Note: event.completeShippingMethodSelection() requires an ApplePayShippingMethodUpdate instance as parameter with a newTotal.
     *
     * @param event ApplePayShippingMethodSelectedEvent, An event object that contains the shipping method (event.shippingMethod).
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778028-onshippingmethodselected">ApplePaySession.onshippingmethodselected</a>
     */
    // session.onshippingmethodselected = function(event) {
    //     var update = {newTotal_to_be_defined};
    //     event.completeShippingMethodSelection(null);
    // };

    /**
     * event handler that is automatically called when the payment UI is dismissed.
     *
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778029-oncancel">oncancel</a>
     */
    session.oncancel = function() {
        window.pollOrderStatus();
    };

    /**
     * An event handler that is called when the user has authorized the Apple Pay payment with Touch ID, Face ID, or passcode.
     *
     * @param event ApplePayPaymentAuthorizedEvent, An event object that contains the token used to authorize a payment (event.payment).
     * @see <a href="https://developer.apple.com/documentation/apple_pay_on_the_web/applepaysession/1778020-onpaymentauthorized">ApplePaySession.onpaymentauthorized</a>
     */
    session.onpaymentauthorized = function(event) {

        var xhttp = new XMLHttpRequest();

        xhttp.onreadystatechange = function() {
            if (this.readyState === 4) {
                try {
                    if (this.status === 200) {
                        session.completePayment({status: ApplePaySession.STATUS_SUCCESS});
                    } else {
                        session.completePayment({status: ApplePaySession.STATUS_FAILURE});
                    }
                }
                catch (e) {
                    // Ignore, canceling during the authorization will invalidate the session object,
                    // resulting in an InvalidAccessError.
                } finally {
                    setTimeout(function() { window.pollOrderStatus(); }, 2000);
                }

            }
        };

        xhttp.open("POST", baseUrl + "/authorize", true);
        xhttp.setRequestHeader("Content-type", "application/json");
        xhttp.send(JSON.stringify(event.payment));
    };

    session.begin();
}