Apple Pay

Integration in a Web-Page and App using Web-View

Here is the step-by-step integration guide for accepting Apple Pay on the Web or in hybrid App using web view.

  1. Confirm that the use of Apple Pay is acceptable.

  2. Confirm that the pay-page layout comply with the Human Interface Guidelines.

  3. Confirm that the pay-page is fulfilling the requirements for accepting Apple Pay.

  4. There are two certificates options:

    • Use our certificate and identity merchant.com.unzer.austria.test with validated domain as described in this guide.
    • Provide us with your own identity and processing certificates which are registered and validated with your domain. We need private keys for both certificates (identity and processing).
  5. Implement the CreateApplePayToken operation.
    The operation is similar to the CreatePaymentToken but the amount and currency should be provided for the Apple Pay session.

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:etp="https://www.mpay24.com/soap/etp/1.5/ETP.wsdl">
  <soap:Body>
    <etp:CreateApplePayToken>
      <merchantID>92883</merchantID>
      <amount>10</amount>
      <currency>EUR</currency>
      <domain>https://test.mpay24.com</domain>
      <order>
        <description>ApplepayExample</description>
      </order>
    </etp:CreateApplePayToken>
  </soap:Body>
</soap:Envelope>
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                   xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" 
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                   xmlns:etp="https://www.mpay24.com/soap/etp/1.5/ETP.wsdl">
    <SOAP-ENV:Body>
        <etp:CreateApplePayTokenResponse>
            <status>OK</status>
            <returnCode>OK</returnCode>
            <token>EYPoIyp2sF4YqiZzG2x1rG9AQkkFU8uw5upbVysiPdU=</token>
            <apiKey>810232bfb087480b4559dfd1beb76a3efb5d8721157478aad0311316c5d4be60</apiKey>
        </etp:CreateApplePayTokenResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The returned token is used for the AcceptPayment operation (the actual payment) and the apiKey is used to initialize the ApplePayAPI class in the client browser.

  1. Integrate the ApplePayAPI in the payment page.
  • Include the API JavaScript in the pay-page
<script src="https://www.mpay24.com/app/tokenizer/default/js/applepay.js"></script>
  • Check if the customer can use Apple Pay (payments are possible). See here for details.
var api = new ApplePayAPI('merchant.com.unzer.austria.test', 'https://test.mpay24.com/app/bin/tokenizer/api/v1/applepay');

async function onLoad() {
  try {
    let available = await api.isAvailable();
    if (available) {
      // show the Apple Pay button
    }
  }
  catch (err) {
    ...
  }
};
  • Initialize the API with the apiKey created in step 5. This should be done before the Apple Pay button is activated or shown.
async function initialize() {
  try {
    let initialized = await api.init(apiKey);
    if (initialized) {
      // Enable Apple Pay button
    }
  }
  catch (err) {
    ...
  } 
}
  • Authorize the payment when the Apple Pay button is clicked.
async function onApplePayButtonClicked() {
  try {
    await api.authorisePayment();
    // the payment was authorized proceed with AcceptPayment
  }
  catch (err) {
    ...
  }
}
  1. When the payment is authorized by the customer proceed with AcceptPayment as with credit-cards. The amount and currency should be the same as in the CreateApplePayToken operation (step 5) or the payment request will be declined.

📘

In iOS, Apple Pay is supported in Safari and in SFSafariViewController objects.

🚧

For development use our test identity merchant.com.unzer.austria.test available on our test system

Integration in native iOS App

Here is the step-by-step integration guide for accepting Apple Pay in an native iOS App.
Please consult the official page for detailed information. There is also an example project here which can be used as a starting point. Note the changes in the PaymentHandler.swift file below.

  1. The requirements for iOS application are the same (see step 1, 2 and 3 above). Apple will reject the App if they are not met.

  2. Create and provide us your processing certificate which is used to create the app. We need also the private key.

  3. Implement the CreateApplePayToken operation in your back-end (see step 5 above). The application should call your back-end to retrieve the apiKey for the payment.

  4. The API is accessible under following url:

https://www.mpay24.com/app/bin/tokenizer/api/v1/applepay/{resource}
  1. To call the API the client should be authenticated using following HTTP headers and the apiKey from step 3.
Content-Type: application/json;charset=utf-8
Api-Key: f720b61277546ad090dd4625465cfce4df2cfc6802a936aabaa397a35e834013
  1. Following resources can be used with the POST method.
  • getSessionRequest (optional) can be used for creation of the PKPaymentRequest according to the merchant configured payment methods and the data provided in the CreateApplePayToken call. Alternatively generate it in the App but currency and amount should match.
{
    "merchantCapabilities": [
        "supports3DS"
    ],
    "supportedNetworks": [
        "amex",
        "discover",
        "electron",
        "jcb",
        "Maestro",
        "MasterCard",
        "Visa",
        "vPay"
    ],
    "countryCode": "AT",
    "total": {
        "label": "Demo (card not charged)",
        "type": "final",
        "amount": "0.10"
    },
    "currencyCode": "EUR"
}
  • completePayment (required) Creates the PKPaymentAuthorizationResult by validating and decoding the PKPayment data.
    Example request Generation (completePaymentRequest) and token submission (submitToken) based on the sample code from Apple (PaymentHandler.swift file):
class PaymentHandler: NSObject {
...
    func postRequest(url: String, payload: String, apiKey: String, completion: @escaping (String?) -> Void) {
        let url = URL(string: url)!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue(apiKey, forHTTPHeaderField: "Api-Key")
        request.setValue("application/json;charset=utf-8", forHTTPHeaderField: "Content-Type")
        request.httpBody = payload.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if (data != nil) {
                completion(String(data: data!, encoding: .utf8))
            }
            else {
                if (error != nil) {
                    print("Error: \(error.debugDescription)")
                }
                completion(nil)
            }
        }
        task.resume()
    }
  
    func completePaymentRequest(merchantIdentifier: String, payment: PKPayment) -> String? {
        let paymentData = String(data: payment.token.paymentData, encoding: .utf8)
        if (paymentData == nil) {
            return nil
        }
        let displayName = payment.token.paymentMethod.displayName ?? "unknown"
        let network = payment.token.paymentMethod.network?.rawValue ?? "unknown"
        let type = payment.token.paymentMethod.type
        let txId = payment.token.transactionIdentifier
        return """
        {\"merchantIdentifier\":\"\(merchantIdentifier)\",\
        \"payment\":{\"token\":{
        \"paymentData\":\(paymentData!),\
        \"paymentMethod\":{\"displayName\":\"\(displayName)\",\"network\":\"\(network)\",\"type\":\"\(type)\"},\
        \"transactionIdentifier\":\"\(txId)\"}}}
        """
    }
        
    func submitToken(apiKey: String, payment: PKPayment, completion: @escaping (PKPaymentAuthorizationResult) -> Void) {
        print("submitToken")
        let result = PKPaymentAuthorizationResult(status: .failure, errors: nil)
        if let request = self.completePaymentRequest(merchantIdentifier: Configuration.Merchant.identifier, payment: payment) {
            print("request:\n\(request)")
            let apiUrl = "https://test.mpay24.com/app/bin/tokenizer/api/v1/applepay/completePayment"
            self.postRequest(url: apiUrl, payload: request, apiKey: apiKey) { apiResponse in
                if apiResponse != nil {
                    print("completePayment response:\n\(apiResponse!)")
                    struct Response: Codable {
                        let status: String
                    }
                    if let jsonData = apiResponse?.data(using: .utf8) {
                        do {
                            let response = try JSONDecoder().decode(Response.self, from: jsonData)
                            result.status = response.status == "0" ? .success : .failure
                            completion(result)
                        } catch {
                            print("error parsing completePaymentResponse: \(error.localizedDescription)")
                            completion(result)
                        }
                    }
                }
            }
        }
        completion(result)
    }
}
    
/*
    Convert the PKPaymentMethodType to string
    for the JSON generation in completePaymentRequest
 */
extension PKPaymentMethodType: CustomStringConvertible {
    public var description: String {
        switch self {
        case .credit: return "credit"
        case .debit: return "debit"
        case .prepaid: return "prepaid"
        case .store: return "store"
        default:
          return "unknown"
        }
    }
}

extension PaymentHandler: PKPaymentAuthorizationControllerDelegate {
...    
    func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, handler completion: @escaping (PKPaymentAuthorizationResult) -> Void) {    
    ...  
            // Here you would send the payment token to your server or payment provider to process
            // Once processed, return an appropriate status in the completion handler (success, failure, etc)
                 
            // get the apiKey from your back-end (call CreateApplePayToken operation)
            let apiKey = "... "
            self.submitToken(apiKey: apiKey, payment: payment) { submitTokenResponse in
                self.paymentStatus = submitTokenResponse.status
                completion(submitTokenResponse)
            }
     ...
     }
...
}

The response JSON object should be used to create a PKPaymentAuthorizationResult object and complete the payment by calling the completion handler.

{ 
  "merchantIdentifier": "merchant.com.yourdomain", 
  "payment": {
    "token": {
      "paymentData": {
        "data": "...",
        "signature": "...",
        "header": {
          "publicKeyHash": "...",
          "ephemeralPublicKey": "...",
          "transactionId": "..."
        },
        "version": "EC_v1"
      },
      "paymentMethod": {
        "displayName": "...",
        "network": "...",
        "type": "..."
      },
      "transactionIdentifier": "..."
    }
  }
}
{
    "status": "0"
}
  1. When the payment is authorized by the customer the App should proceed with AcceptPayment at the back-end as with credit-cards. The amount and currency should be the same as in the CreateApplePayToken (step 2) or the payment request will be declined.