This page contains samples of code in iOS apps that integrate with Radial payment APIs.

Technology Stack

The following technologies (both software and hardware) were used in order to do end-to-end testing for this iOS app

  • Xcode 8 IDE
  • iOS 10 Operation System
  • Swift 2.3 Programming Language
  • iPhone 6 Mobile Phone

Pay with ApplePay Button tap - Sample Code

 /*
    * This function is invoked when the user taps on the "Pay with ApplePay Button".
    * This function will show the ApplePay Payment Sheet.
    * PKPaymentAuthorizationViewController is a class from the PassKit framework which we have
    * imported into this class.
    * The main purpose of the controller is to show the ApplePay Payment Sheet.
    * You can change what tender types are allowed for display in the sheet by changing the
    * supportedNetworks attribute in the PKPaymentRequest object
    * that is passed to this controller.
    * We are setting the delegate attribute of PKPaymentAuthorizationViewController object to
    * self, which means that PKPaymentAuthorizationViewController
    * object will look for a PKPaymentAUthorizationViewControllerDelegate implementation in
    * this class.  The various functions in this delegate implementation
    * will get called at the various stages of the payment processing.
    * Finally the presentViewController call will show the Applepay Payment Sheet with the
    * various payment options.
    */
    @IBAction func purchase(sender: UIButton) {
        // TODO: - Fill in implementation
        let request = PKPaymentRequest()
        request.merchantIdentifier = ApplePaySwagMerchantId
        request.supportedNetworks = SupportedPaymentNetworks
        request.merchantCapabilities = PKMerchantCapability.Capability3DS
        request.countryCode = "US"
        request.currencyCode = "USD"
        var summaryItems = [PKPaymentSummaryItem]()
        summaryItems.append(PKPaymentSummaryItem(label: swag.title, amount: swag.price))
        if (swag.swagType == .Delivered) {
            summaryItems.append(PKPaymentSummaryItem(label: "Shipping", amount: swag.shippingPrice))
        }
        summaryItems.append(PKPaymentSummaryItem(label:"Apple Pay Demo", amount: swag.total()))
        request.paymentSummaryItems = summaryItems
        request.requiredBillingAddressFields = PKAddressField.All
        switch(swag.swagType) {
        case SwagType.Delivered:
            request.requiredShippingAddressFields = [PKAddressField.PostalAddress,PKAddressField.Phone]
        case SwagType.Electronic:
            request.requiredShippingAddressFields = PKAddressField.Email
        }

        let applePayController = PKPaymentAuthorizationViewController(paymentRequest: request)
        applePayController.delegate = self
        self.presentViewController(applePayController, animated: true, completion: nil)
    }

Apple Pay Authorization - Sample Code

/**
* Below class is an implementation of the PKPaymentAuthorizationViewControllerDelegate.
* The methods of this class get invoked when the apple pay authorization starts and finishes
* When the user has authorized the payment with touchId, the secure element on the
* mobile device retrieves the associated payment information and passes it to the
* Apple Pay Server.  In the server, the DPAN is encrypted with the merchant certificate.
* The merchant Id is an input passed here to look up the merchant certificate.
* The encrypted blob is received by the passkit API which then calls the below
* delegate class's paymentAuthorizationViewController method  passing
* the payment information in the PKPayment object.
* The PKPayment.token.paymentData object contains the encrypted payment blob.
* Rest of the information is in plain text.
* We pass this encrypted blob to our decryption service using a rest call.
* The result is a decrypted object in json format.
* The function then proceeds to pull out the values from this result
* and construct the payment service credit card auth request using the processPayment method.
*/
extension BuySwagViewController: PKPaymentAuthorizationViewControllerDelegate {

    /*
     * This is the first method to be called by the passkit framework once the encrypted
     * blob is received from the apple server.
     * Our implementation of the call back function below is calling payment service to
     * decrypt the encrypted blob.
     * It then proceeds to call processPayment method to send this data down to payment
     * service for authorization.
     */
    func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController,
            didAuthorizePayment payment: PKPayment,
            completion: (PKPaymentAuthorizationStatus) -> Void) {
        let publicApiUrl = "http://lvststwsv04-01.us.gspt.net:1801/public-api-service/
            v1.0/stores/SMTUS/payments/decryptblob.xml"
        let decryptUrl = NSURL(string: publicApiUrl)  // Decryption URL
        let decryptRequest = NSMutableURLRequest(URL: decryptUrl!)
        decryptRequest.HTTPMethod = "POST"
        decryptRequest.setValue("application/xml", forHTTPHeaderField: "Content-Type")
        let encryptedPaymentData = payment.token.paymentData
        let paymentMethod = payment.token.paymentMethod
        let decryptedPaymentData:NSString! = NSString(data: encryptedPaymentData,
            encoding: NSUTF8StringEncoding)

        //extract values from encrypted JSON string
        let decryptedJsonStr = JSON.parse(decryptedPaymentData as String)
        var encryptionHeader = "EncryptionHeader"
        var version = decryptedJsonStr["version"].stringValue
        var data = decryptedJsonStr["data"].stringValue
        var signature = decryptedJsonStr["signature"].stringValue
        var epk = decryptedJsonStr["header"]["ephemeralPublicKey"].stringValue
        var publicKeyHash = decryptedJsonStr["header"]["publicKeyHash"].stringValue
        var txId = decryptedJsonStr["header"]["transactionId"].stringValue


        let xmlRequest = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>" +
        "<DecryptBlobRequest xmlns=\"http://api.gsicommerce.com/schema/checkout/1.0\">" +
            "<AlgorithmVersion>pd</AlgorithmVersion>" +
            "<EncryptionHeader>" +
                 "<EphemeralPublicKey>" + epk + "</EphemeralPublicKey>" +
                 "<TransactionId>" + txId + "</TransactionId>" +
                 "<PublicKeyHash>" + publicKeyHash + "</PublicKeyHash>" +
            "</EncryptionHeader>" +
            "<Version>" + version + "</Version>" +
            "<Data>" + data + "</Data>" +
            "<Signature>" + signature + "</Signature>" +
            "</DecryptBlobRequest>"

        decryptRequest.HTTPBody = xmlRequest.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(decryptRequest) { data,
            response, error in
            guard error == nil && data != nil else {
                print("error=\(error)")
                return
            }
            if let httpStatus = response as? NSHTTPURLResponse where
            httpStatus.statusCode != 200 {
                print("statuscode should be 200, but is \(httpStatus.statusCode)")
            } else {
                let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
                let shippingAddress = self.createShippingAddressFromRef(
            payment.shippingAddress)
                let billingAddress = self.createBillingAddressFromRef(payment.billingAddress)
                self.processPayment(responseString, shippingAddress: shippingAddress,
            billingAddress: billingAddress, completion: completion)
            }
        }
        task.resume()
    }
}	          

Credit Card Authorization Call - Sample Code

/*
 * Below function houses the logic for constructing
 * credit card auth xml and calls payment service credit card auth api.
 */
func processPayment(ccAuthXmlRequest : NSString, shippingAddress: Address,
	billingAddress: Address, completion: (PKPaymentAuthorizationStatus) -> Void)  {
	do {
		let shipFname = shippingAddress.FirstName! as String
		let shipLname = shippingAddress.LastName! as String
		let shipLine1 = shippingAddress.Street! as String
		let shipCity = shippingAddress.City! as String
		let shipState = shippingAddress.State! as String
		let shipZip = shippingAddress.Zip! as String
		var shipCountry = "US"
		if shippingAddress.Country != nil {
			shipCountry = shippingAddress.Country! as String
		}
		let amount = self.swag!.total().description

		let billFname = billingAddress.FirstName! as String
		let billLname = billingAddress.LastName! as String
		let billLine1 = billingAddress.Street! as String
		let billCity = billingAddress.City! as String
		let billState = billingAddress.State! as String
		let billZip = billingAddress.Zip! as String
		var billCountry = "US"
		if billingAddress.Country != nil {
			billCountry = billingAddress.Country! as String
		}

		let visaCCAuthUrl = "http://lvststwsv04-01.us.gspt.net:1801/public-api-service/
            v1.0/stores/SMTUS/payments/creditcard/auth/VC.xml"
		let ccAuthUrl = NSURL(string: visaCCAuthUrl)
		let ccAuthRequest = NSMutableURLRequest(URL: ccAuthUrl!)
		ccAuthRequest.HTTPMethod = "POST"
		ccAuthRequest.setValue("application/xml", forHTTPHeaderField: "Content-Type")

		let text = String(ccAuthXmlRequest)

		var dan = ""
		var tenderType = ""
		var expDate = ""
		var txAmount = ""
		var onlinePaymentCryptogram = ""
		var eci = ""
		if let startIndex =
            text.rangeOfString("<DeviceAccountNumber isToken=\"false\">")?.endIndex,
			let endIndex = text.rangeOfString("</DeviceAccountNumber>")?.startIndex {
			dan = text.substringWithRange(startIndex..<endIndex)
		}
		if let startIndex = text.rangeOfString("<TenderType>")?.endIndex,
			let endIndex = text.rangeOfString("</TenderType>")?.startIndex {
			tenderType = text.substringWithRange(startIndex..<endIndex)
		}
		if let startIndex = text.rangeOfString("<ExpirationDate>")?.endIndex,
			let endIndex = text.rangeOfString("</ExpirationDate>")?.startIndex {
			expDate = text.substringWithRange(startIndex..<endIndex)
		}
		if let startIndex =
            text.rangeOfString("<TransactionAmount currencyCode=\"USD\">")?.endIndex,
			let endIndex = text.rangeOfString("</TransactionAmount>")?.startIndex {
			txAmount = text.substringWithRange(startIndex..<endIndex)
		}
		if let startIndex = text.rangeOfString("<OnlinePaymentCryptogram>")?.endIndex,
			let endIndex = text.rangeOfString("</OnlinePaymentCryptogram>")?.startIndex {
			onlinePaymentCryptogram = text.substringWithRange(startIndex..<endIndex)
		}
		if let startIndex = text.rangeOfString("<EciIndicator>")?.endIndex,
			let endIndex = text.rangeOfString("</EciIndicator>")?.startIndex {
			eci = text.substringWithRange(startIndex..<endIndex)
		}


		let body = ("<CreditCardAuthRequest xmlns=\"http://api.gsicommerce.com/
            schema/checkout/1.0\" requestId=\"1234567\">" +
			"<PaymentContext>" +
			"<OrderId>123456abcd</OrderId>" +
		   "<PaymentAccountUniqueId isToken=\"false\">" + dan + "</PaymentAccountUniqueId>" +
			"</PaymentContext>" +
			"<ExpirationDate>" + expDate + "</ExpirationDate>" +
			"<CardSecurityCode></CardSecurityCode>" +
			"<Amount currencyCode=\"USD\">" + txAmount + "</Amount>" +
			"<BillingFirstName>" + billFname + "</BillingFirstName>" +
			"<BillingLastName>" + billLname + "</BillingLastName>" +
			"<BillingPhoneNo>6101234567</BillingPhoneNo>" +
			"<BillingAddress>" +
			"<Line1>" + billLine1 + "</Line1>" +
			"<Line2></Line2>" +
			"<Line3></Line3>" +
			"<Line4></Line4>" +
			"<City>" + billCity + "</City>" +
			"<MainDivision>" + billState + "</MainDivision>" +
			"<CountryCode>" + billCountry + "</CountryCode>" +
			"<PostalCode>" + billZip + "</PostalCode>" +
			"</BillingAddress>" +
			"<CustomerEmail>customer@sample.com</CustomerEmail>" +
			"<CustomerIPAddress>208.247.73.130</CustomerIPAddress>" +
			"<ShipToFirstName>" + shipFname + "</ShipToFirstName>" +
			"<ShipToLastName>" + shipLname + "</ShipToLastName>" +
			"<ShipToPhoneNo>6101234567</ShipToPhoneNo>" +
			"<ShippingAddress>" +
			"<Line1>" + shipLine1 + "</Line1>" +
			"<Line2></Line2>" +
			"<Line3></Line3>" +
			"<Line4></Line4>" +
			"<City>" + shipCity + "</City>" +
			"<MainDivision>" + shipState + "</MainDivision>" +
			"<CountryCode>" + shipCountry + "</CountryCode>" +
			"<PostalCode>" + shipZip + "</PostalCode>" +
			"</ShippingAddress>" +
			"<POSMethod>ApplePay</POSMethod>" +
			"<isRequestToCorrectCVVOrAVSError>false</isRequestToCorrectCVVOrAVSError>" +
			"<SecureVerificationData>" +
			"<AuthenticationAvailable>Y</AuthenticationAvailable>" +
			"<AuthenticationStatus>Y</AuthenticationStatus>" +
			"<CavvUcaf>" + onlinePaymentCryptogram + "</CavvUcaf>" +
			"<TransactionId></TransactionId>" +
			"<ECI>" + eci + "</ECI>" +
			"<PayerAuthenticationResponse<>/PayerAuthenticationResponse>" +
			"</SecureVerificationData>" +
			"<SchemaVersion>1.1</SchemaVersion>" +
			"</CreditCardAuthRequest>")

		let requestXmlData = body.dataUsingEncoding(NSUTF8StringEncoding)
		ccAuthRequest.HTTPBody = requestXmlData
		let task1 = NSURLSession.sharedSession().dataTaskWithRequest(ccAuthRequest) {data,
		response, error in
			guard error == nil && data != nil else {
				print("error=\(error)")
				completion(PKPaymentAuthorizationStatus.Failure)
				return
			}
			if let httpStatus = response as? NSHTTPURLResponse
			where httpStatus.statusCode != 200 {
				print("statuscode should be 200, but is \(httpStatus.statusCode)")
				completion(PKPaymentAuthorizationStatus.Failure)
			} else {
				completion(PKPaymentAuthorizationStatus.Success)
			}
			let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
		}
		task1.resume()
	}
	catch let error as NSError {
		print (error.localizedDescription)
	}
}