Apple Pay Integration

Prerequisite

  • Create Apple Pay merchant ID.
  • Create a Payment Processing certificate.
  • Enable Apple Pay in Xcode.

For instructions on these Apple Pay setups, see:

Apple servers use the certificate to encrypt payment data and Netaxept to decrypt and process payment.
For further information about getting Netaxept CSR certificate, please refer to files below:

Netaxept - Apple Pay Payment Flow

Netaxept - Apple Pay Integration doc

Step-by-step process

  1. In your Apple Developer Account site, get your Merchant ID (not your Netaxept Merchant ID).
  2. In your Netaxept ADMIN site, get Apple Pay certificate following the instructions given.
  3. In your project, enable Apple Pay capability with the correct Apple Pay Merchant ID you just created.
  4. Navigate to your Apple Pay certificate obtained in step 1 and add the certificate to KeyChain (e.g. by double-clicking the file).
  5. Use Pia SDK for Apple Pay according to the development guide shown below and in the PiaSample project.

Apple Pay - Checkout Overview

Apple Pay with PiA SDK

Step 1: Check Apple Pay Support

First, check if Apple Pay is supported by the device or that user is not restricted to use Apple Pay due to e.g. Parental control settings. The app should also check supported networks which user can make payments through.

/// Apple's UI design guidelines encourage checking this condition 
/// before displaying 'Buy with  Pay' button. 
guard PKPaymentAuthorizationViewController.canMakePayments() else {
    return // Not supported on device / User is restricted
}

guard PKPaymentAuthorizationViewController.canMakePayments(
    usingNetworks: supportedApplePayNetworks) else {
        presentAppleWalletSetupEnquiry()
        return
}

If the user does not have a supported card for the payment, the application may lead user to a different payment method or open Wallet app so that the user can add a card in Wallet as follows:


//  MARK: Apple Wallet Setup

func presentAppleWalletSetupEnquiry() {
    let alert = UIAlertController(
        title: .titleAppleWalletNotSetup,
        message: .messageOpenAppleWalletApp,
        preferredStyle: .alert)
    let cancel = UIAlertAction(title: .actionCancel, style: .cancel, handler: nil)
    let openWalletsApp = UIAlertAction(title: .actionSetup, style: .default) { _ in
        if let walletAppURL = URL(string: "shoebox://url-scheme"),
            UIApplication.shared.canOpenURL(walletAppURL) {
            UIApplication.shared.openURL(walletAppURL)
        } else {
            self.navigationController.showAlert(
                title: .titleCannotOpenAppleWallet,
                message: .messageManuallyOpenAppleWallet)
        }
    }
    [cancel, openWalletsApp].forEach(alert.addAction(_:))
    self.navigationController.present(alert, animated: true, completion: nil)
}

Step 2: Present Apple Pay Payment Authorization Sheet

Start by creating a payment request (an instance of PKPaymentRequest from Apple’s PassKit framework) using PiaSDK’s helper. The helper covers all the mandatory parameters for a valid payment request. Based on the requirements of an application, the request can be modified to include more information. e.g. The sample app further modifies the request by including shipping address in the payment request.

let request = PiaSDK.makeApplePayPaymentRequest(
    for: supportedApplePayNetworks,
    countryCode: "NO", // Norway
    applePayMerchantID: "ApplePay merchant ID",
    merchantCapabilities: .capability3DS,
    currencyCode: "EUR",
    summeryItems: [
        PKPaymentSummaryItem(label: "Item name", amount: itemCost)
    ]
)

guard let controller = PKPaymentAuthorizationViewController(paymentRequest: request) else {
    return
}

controller.delegate = self 
present(controller, animated: true, completion: nil)

Step 3: Implement The Payment Authorization Delegate

The next step is to implement the two required delegate methods in PKPaymentAuthorizationViewControllerDelegate. Following user’s approval to proceed with the payment, didAuthorizePayment delegate method is called with the payment object (an instance of PKPayment). Pia SDK provides a helper to obtain a token (UTF-8 string) parsing this object into the accepted format by Netaxept SOAP API. Pass this payment data to your merchant backend and essentially to Netaxept.

The sample app implements the delegate method as follows:

func paymentAuthorizationViewController(
    _ controller: PKPaymentAuthorizationViewController,
    didAuthorizePayment payment: PKPayment,
    completion: @escaping (PKPaymentAuthorizationStatus) -> Void) {

    let token = PiaSDK.netaxeptSOAPPaymentData(from: payment.token)

    api.registerApplePay(for: orderDetails, token: token) { [weak self] result in
        guard case .success(let transaction) = result else {
            self?.transaction = nil
            completion(PKPaymentAuthorizationStatus.failure)
            return
        }

        self?.api.commitTransaction(transaction.transactionId , commitType: .payment) { result in
            switch result {
            case .success(_):
                self?.transaction = transaction
                completion(.success)
            case .failure(_):
                self?.transaction = nil
                completion(.failure)
            }
        }
    }
}

Following invoking of the completion block in didAuthorizePayment delegate method, PassKit notifies completion via paymentAuthorizationViewControllerDidFinish delegate call. The authorization payment sheet should be dismissed in this delegate call.

func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
    defer { self.transaction = nil }
    controller.presentingViewController?.dismiss(animated: true, completion: nil)
}

Note: This delegate is called directly (without didAuthorizePayment preceding delegate call) if user cancels payment in the payment authorization sheet.

(If the payment process contains shipping contact address, its necessary to implement the associated delegate methods in the protocol in order to adjust shipping cost accordingly)

Netaxept backend integration request body - Apple Pay payment registration:
{
    "paymentData" : "string",
    "paymentMethodActionList" : { 
        "PaymentMethod" : "ApplePay" 
    }
}

The paymentData should contain th encrypted Payment Data from Apple pay of the following format:

{
    "paymentData" : {
        "version" : "string",
        "data" : "string",
        "signature" : "string", 
        "header" : {
            "ephemeralPublicKey" : "string", 
            "publicKeyHash" : "string",
            "transactionId" : "string"
        }
    },
    "paymentMethod" : {
        "displayName" : "string",
        "network" : "string", 
        "type" : "string"
    },
    "transactionIdentifier" : "string"
}

Note: Netaxept backend integration tips can be found in 5.4 Backend Tips, Request body - Apple Pay payment registration section