Swift SDK
Use our native Swift SDK to establish a secure channel between your iOS app and our server while guaranteeing a safe transfer of your customers' data.
Our native SDK helps you communicate with the Client API. It offers:
- Convenient wrappers for API responses.
- Handling of all the details concerning the encryption of payment details.
- Caching of payment product logos and images to offer additional information about payment products.
- User-friendly formatting of payment data, such as card numbers and expiry dates.
- Input validation.
- Checks to determine to which issuer a card number is associated.
Our example app simulates the user interface for the whole payment flow based on the interaction between the app and our platform. Find the source code of the SDK and the example app on GitHub, including installation instructions.
To understand how to use this SDK, look at the following documentation:
- Mobile/Client Integration – Familiarise yourself with various concepts.
- Client API Reference – The SDK wraps the Client API and (among other things) exposes the responses of the web service calls as objects. Understanding the Client API will help you understand these SDK objects as well.
- The SDK on GitHub – The SDK contains a working example application, which can help you understand how to best use it.
- This current document will help you understand the global flow when creating payment pages using the SDK.
Why use the Swift SDK
Our Swift SDK helps you integrate payments into iOS applications faster and with less effort. It handles many technical details for you, so you do not have to work directly with the Client API for common tasks. The main advantages of using the SDK are:
- Less code to write and maintain – The SDK includes ready-made functionality, which reduces development time and ongoing maintenance.
- Simple and secure authentication – The SDK takes care of authentication and security-related logic, making setup faster and safer.
- More stable integration over time – Most platform changes are handled within the SDK, minimising the impact on your application code.
- Faster setup and easier support – Using the SDK creates more standardised integrations, making onboarding quicker and support more efficient.
If you require tight dependency control, minimal features, or a lightweight setup, the SDK may add code and functionality you do not need. In these cases, working directly with the API is simpler and more efficient.
SDK integration
To create payments, you first need to integrate the SDK with your project. You can find all the versions of the SDK in our repository. We have prepared the requirements and installation instructions for the SDK below.
Requirements
The minimal Swift version the library supports is 5.5. However, since the Swift SDK library is built for distribution, you can also use it with all the later Xcode and Swift versions.
Installation
You can install the SDK in several ways:
Swift Package Manager (Recommended)
You can add the Swift SDK with Swift Package Manager by configuring your project as follows:
- Go to your project's settings and click the "Package Dependencies" tab.
- Click "+" to add a new Swift Package dependency.
- Enter the following GitHub URL in the search bar: https://github.com/wl-online-payments-direct/sdk-client-swift
- You can also set a version of the package you wish to include. The default option is the latest version from the main branch.
- Click "Add package".
The package will be added automatically as a dependency to your targets as well.
CocoaPods (obsolète)
We no longer release our library to CocoaPods due to technical issues. However, you can still use an old version released there. Keep in mind that we do not provide support for it anymore, so we cannot guarantee it will work.
You can add the Swift SDK to your project as a pod by adding the following to your Podfile:
pod 'OnlinePaymentsKit'
The podspec automatically handles dependencies.
Afterwards, run the following command:
pod install
XCFramework
For direct XCFramework integration:
- Download the XCFramework from the releases page.
- Add the XCFramework to your project:
- Drag OnlinePaymentsKit.xcframework into the "Frameworks, Libraries and Embedded Content" section of your target.
- Set it to "Embed & Sign".
All dependencies (Alamofire, CryptoSwift) are statically linked into the XCFramework, so you do not need to add them separately.
Carthage
Add the following to your Cartfile to add the Swift SDK with Carthage:
github "wl-online-payments-direct/sdk-client-swift"
Afterwards, run the following command:
carthage update --use-xcframeworks
Then, navigate to the Carthage/Build directory (located in the same place as .xcodeproj or .xcworkspace). You will find the .xcframework bundle inside.
Drag the .xcframework into the "Framework, Libraries, and Embedded Content" section of the desired target. Make sure that it is set to "Embed & Sign".
Objective-C compatibility
You can also use the Swift SDK in Objective-C projects by using CocoaPods or Carthage. When you add the Online Payments Kit as a dependency, you can easily use it by adding the following import statement where you want to use the SDK: @import OnlinePaymentsKit;
Example apps
We have provided an example application in both SwiftUI and UIKit that you can use as a basis for your own implementation. If you like how it looks and feels, you do not need to make any changes at all. You can get the example apps below:
After you successfully integrate the SDK with your project, you can proceed to integrate it with the entire payment system. The complete payment process consists of these steps:
- Initialisation of the SDK
- Fetching possible payment methods
- Fetching and displaying payment method details
- Validation of the provided data
- Encryption and transfer of payment data
- Finalising transaction
1. Initialise SDK
Firstly, you need to create an instance of the OnlinePaymentsSdk, enabling communication between the Server API and the client. Your app must have its own server, acting as an intermediary between our Client and Server API.
Since the customer initiates the payment in your app, your Client application asks your Server application to create a Session. When a Server application receives a request, it can create a Session via CreateSession from the Server SDK.
Try our API Explorer to send a CreateSession request.
After configuring and connecting your application to the Server API, you receive a response containing information about the created Session. A typical response looks like this:
{clientSessionId: "47e9dc332ca24273818be2a46072e006",customerId: "9991-0d93d6a0e18443bd871c89ec6d38a873",clientApiUrl: "https://clientapi.com",assetUrl: "https://assets.com"}
Each Session has a fixed 3-hour lifespan. If it expires, you need to create a new Session.
After creating a SessionData, you will also need to configure your PaymentContext object, as shown below. It contains information like currency, country, amount, etc.
let sessionData = SessionData(clientSessionId: "47e9dc332ca24273818be2a46072e006",customerId: "9991-0d93d6a0e18443bd871c89ec6d38a873",clientApiUrl: "https://clientapi.com",assetUrl: "https://assets.com")let amountOfMoney = AmountOfMoney(amount: 1298, // in centscurrencyCode: "EUR" //three-letter currency code as defined in ISO 4217)let paymentContext = PaymentContext(amountOfMoney: amountOfMoney,isRecurring: false, // true, if it is a recurring paymentcountryCode: "NL" //two-letter country code as defined in ISO 3166-1 alpha-2)
You can use all this to create an instance of the SDK, which you will use for further interaction.
let configuration = SdkConfiguration(appIdentifier: "My Application/v2.0.4",loggingEnabled: true // set this to false in production)let sdk = try OnlinePaymentsSdk(sessionData: sessionData,configuration: configuration)
Different payment methods are available for different PaymentContext objects. If you change any variable, you must start the process again. Only the SessionData can remain the same if the same customer made the payment.
2. Fetch possible payment methods
The next step is to get and display the possible payment options. Since payment items are instances of BasicPaymentProduct, your app can use these items to create a screen that lists them. Just fetch and display the BasicPaymentProduct and AccountOnFile lists to let your customer select one.
Use our convenient example application as a basis for your own implementation.
sdk.basicPaymentProducts(forContext: paymentContext,success: { basicPaymentProducts in// Display the contents of basicPaymentProducts & accountsOnFile to your customer},failure: { error in// Inform the customer that something went wrong while retrieving the available Payment Products})
You can skip this step if you want to use a specific payment product.
3. Fetch and display payment method details
For certain payment products, customers can opt for our platform to store their credentials for recurring payments. We refer to the stored data as an account on file (Card On File) or a token. You can reuse this account on file/token for subsequent payments if your customers chose the same payment method.
The list of available payment products that the SDK receives from the Client API also contains the accounts on file for each payment product. Your application can present this list to the user.
Depending on the method the customer chooses, consider cases of different data flows:
If the customer chooses a native form of payment, you need to use the SDK of the payment provider. You will need to handle the response only in the last step to inform the customer of their payment status. Read more about native payments in this dedicated chapter.
For payments with a third-party payment provider, you receive data with the redirection address in the payment properties. Redirect your customers in their browser to the third-party payment portal to continue the payment process. After the successful payment, your app needs to handle the redirection to the Client app.
The standard payment process is a card payment. Once the customer selects the desired payment product, retrieve the enriched PaymentProduct detailing what information the customer needs to provide to authorise the payment. Then, display the required information fields to your customer.
sdk.paymentProduct(withId: 1, // replace with the id of the payment product that should be fetchedpaymentContext: paymentContext,success: { paymentProduct in// Display the fields to your customer},failure: { error in// Handle failure of retrieving a Payment Product by id})
Use our example app for inspiration to create your screen.
4. Validate provided data
After your customer enters their payment information, your application needs to validate the received data. But before validation, you will first need to save the customer's input for the required information fields in a PaymentRequest instance. This class has a tokenize property used to indicate whether the app should store the customer's credentials for recurring payments.
Use the following code sample for payment requests without accounts on file:
let paymentRequest = PaymentRequest(paymentProduct: paymentProduct)
Alternatively, adapt the code sample by supplying both the account on file and the corresponding payment product:
let paymentRequest = PaymentRequest(paymentProduct: paymentProduct)paymentRequest.accountOnFile = accountOnFile
Once you configure a payment request, supply the values for the payment product fields. Use the identifiers of the fields, such as "cardNumber", "cvv", "cardholderName", and "expiryDate", to set the field values for the payment request:
try paymentRequest.field(id: "cardNumber").setValue(value: "12451254457545")try paymentRequest.field(id: "cvv").setValue(value: "123")try paymentRequest.field(id: "expiryDate").setValue(value: "1230")try paymentRequest.field(id: "cardholderName").setValue(value: "John Doe")
Now you need to validate the received data using the available list of validators. Do that by performing validation on the PaymentRequest and validating both the field values and the payment request.
// validate all fields in the payment requestlet validationResult = paymentRequest.validate()// check if the payment request is validif validationResult.isValid {// payment request is valid} else {// payment request has errorsvalidationResult.errors.forEach { error in// do something with the ValidationError, like displaying it to the user}}
Remember that the data entry interface must be fully transparent and understandable for your customers. So if there are validation errors, you should provide the customer with feedback about them. You receive error information during the validation of a payment field or the validation of the payment request, so you can use it to display appropriate error messages. Each validation error has a reference to the corresponding faulty field.
5. Encrypt and transfer payment data
After the PaymentRequest validation, encrypt the request as illustrated in the snippet below:
sdk.encryptPaymentRequest(paymentRequest,success: { encryptedRequest in// Forward the encryptedRequest.encryptedCustomerInput to your server},failure: { error in// Handle failure of encrypting Payment Request})
See a more detailed description of the encryption process in this dedicated chapter.
6. Finalise transaction
After encrypting the customer data, send the encrypted object to your server and use it to make a CreatePayment request with the Server SDK. Then, provide it with the encrypted data to finalise the payment.
The response of the CreatePayment request may require additional actions from the Client, specified in the MerchantAction object. In most cases, this involves redirecting the customer to an external party (i.e. for a 3-D Secure check). Once your customers complete this check, our platform processes the actual transaction. Read the Server SDK documentation for more information.
Finally, you have to pass the information back to your Client application to display the transaction result to your customers.
Find a full overview of the payment flow in the Mobile/Client Integration guide.
SDK objects
The Swift SDK includes several objects. Choose the object of your interest from the list below to read more about it:
- OnlinePaymentsSdk
- PaymentContext
- BasicPaymentProducts
- BasicPaymentProduct
- AccountOnFile
- PaymentProduct
- PaymentProductField
- PaymentRequest
- StringFormatter
OnlinePaymentsSdk
An instance of OnlinePaymentsSdk is required for all interactions with the SDK. The following code snippet shows how to initialise OnlinePaymentsSdk. You obtain session details by performing a Create Client Session call using the Server API.
let sessionData = SessionData(clientSessionId: "47e9dc332ca24273818be2a46072e006",customerId: "9991-0d93d6a0e18443bd871c89ec6d38a873",clientApiUrl: "https://clientapi.com",assetUrl: "https://assets.com")let configuration = SdkConfiguration(appIdentifier: "Swift Example Application/v2.0.4")let sdk = try OnlinePaymentsSdk(sessionData: sessionData,configuration: configuration)
All methods the OnlinePaymentsSdk offers are wrappers around the Client API. They create the request and convert the response to Swift objects that may contain convenience functions.
PaymentContext
PaymentContext is an object that contains the context/settings of the upcoming payment. Some methods of the Session instance require it as an argument. This object can contain the following details:
public class PaymentContext {var countryCode: String // ISO 3166-1 alpha-2 country codevar amountOfMoney: AmountOfMoney // contains the total amount and the ISO 4217 currency codevar isRecurring: Bool // Set `true` when payment is recurring. Default false.}
BasicPaymentProducts
This object contains the available payment products for the current payment. Use the sdk.basicPaymentProducts function to request the data.
The object you will receive is BasicPaymentProducts, which contains a list of all available BasicPaymentProducts and their associated AccountOnFiles.
The code snippet below shows how to get the BasicPaymentProducts instance.
sdk.basicPaymentProducts(forContext: paymentContext,success: { basicPaymentProducts in// Display the contents of basicPaymentProducts & accountsOnFile to your customer},failure: { error in// Inform the customer that something went wrong while retrieving the available Payment Products})
BasicPaymentProduct
The SDK offers two types of objects to represent information about payment products:
- BasicPaymentProduct
- PaymentProduct
The instances of BasicPaymentProduct contain only the information required to display a simple list of payment products for the customer to choose from.
The object PaymentProduct contains additional information on each payment product. An example would be the specific form fields that the customer must fill out. You typically use this object when creating a form that asks for a customer's payment details. Read the PaymentProduct section for more info.
Below is an example of how to get display names and assets for the Visa product (id: 1).
let basicPaymentProduct = basicPaymentProducts.paymentProduct(withId: 1)let id = basicPaymentProduct.id // 1let label = basicPaymentProduct.label // VISAlet logoPath = basicPaymentProduct.logo // https://assets.com/path/to/visa/logo.gif
AccountOnFile
An instance of AccountOnFile represents information about a stored card product for the current customer. You must provide the available AccountOnFile IDs for the current payment in the request body of the Server API's CreateSession call if you want to let a customer use a previously tokenised payment method.
If the customer wants to use an existing AccountOnFile for a payment, you should add the selected AccountOnFile to the PaymentRequest. The code snippet below shows how to retrieve the display data for an account on file. You can show this label and the logo of the corresponding payment product to the customer.
// All available accounts on file for the payment productlet allAccountsOnFile = basicPaymentProduct.accountsOnFile// Get the specific account on file for the payment productlet accountOnFile = basicPaymentProduct.accountOnFile(withId: "123")// Shows a mask-based formatted value for the obfuscated cardNumber.// The mask that is used is defined in the displayHints of this accountOnFile// If the mask for the "cardNumber" field is {{9999}} {{9999}} {{9999}} {{9999}}, then the result would be **** **** **** 7412let maskedValue = accountOnFile.getValue(forField: "cardNumber")
PaymentProduct
BasicPaymentProduct only contains the basic payment product information that customers need to distinguish them. However, when they select a payment product or an account on file, they must provide additional information. The system needs mandatory info like the bank account number, credit card number, and expiry date to process the payment. The instances of BasicPaymentProduct do not contain any information about these fields.
So when you need detailed payment information, call the PaymentProduct object. This object contains several instances of PaymentProductField. Each PaymentProductField carries a piece of information required to process the payment (e.g. bank account number, credit card number).
Use the OnlinePaymentsSdk instance to retrieve the instance of PaymentProduct, as shown in the code snippet below.
sdk.paymentProduct(withId: 1, // replace with the id of the payment product that should be fetchedpaymentContext: paymentContext,success: { paymentProduct in// Display the fields to your customer},failure: { error in// Handle failure of retrieving a Payment Product by id})
PaymentProductField
PaymentProductField instances represent individual payment product fields (e.g., bank account number, credit card number). Each field has the following:
- An identifier
- A type
- A definition of restrictions that apply to the field's value
- Built-in validation for input values
- Information on how the field should be displayed to the customer
In the code example below, the system retrieves the field with the identifier "cvv" from a payment product. The system then checks the data restrictions to identify if it is a required field or an optional field. Finally, the system inspects whether the values the customer provided should be visible or hidden in the user interface.
let cvvField = paymentProduct.field(id: "cvv")let isRequired = cvvField.isRequired // states if value is required for this fieldlet shouldObfuscate = cvvField.shouldObfuscate // states if the field value should be obfuscated
PaymentRequest
Once the customer selects a payment product and the system retrieves an instance of PaymentProduct, a payment request can be constructed. You must use the PaymentRequest class as a container for all the values the customer provides.
let paymentRequest = PaymentRequest(paymentProduct: paymentProduct)
Tokenise payment request
A PaymentRequest has a property tokenize. You can use it to indicate whether a payment request should be stored as an account on file for future payments. The code snippet below shows how to construct a payment request when you want to store it as an account on file.
let paymentRequest = PaymentRequest(paymentProduct: paymentProduct) // when you do not pass the tokenize value, it will be false// you can supply tokenize via the constructorlet paymentRequest = PaymentRequest(paymentProduct: paymentProduct, tokenize: true)// or by accessing the request's tokenize propertypaymentRequest.tokenize = true
By default, tokenize is set to false.
If the customer selects an account on file, you must supply both the account on file and the corresponding payment product when constructing the payment request. You can retrieve the instances of AccountOnFile from instances of BasicPaymentProduct and PaymentProduct.
// you can supply accountOnFile via the constructorlet paymentRequest = PaymentRequest(paymentProduct: paymentProduct,accountOnFile: accountOnFile // when you do not pass the accountOnFile value, it will be nil)// or by accessing the request's accountOnFile propertypaymentRequest.accountOnFile = accountOnFile
Set field values for the payment request
Once you create a payment request, you can supply the values for the payment request fields as follows:
try paymentRequest.setValue(id: "cardNumber", value: "1245 1254 4575 45")try paymentRequest.setValue(id: "cvv", value: "123")try paymentRequest.setValue(id: "expiryDate", value: "12/25")
The identifiers of the fields, such as "cardNumber" and "cvv", are used to set the field values using the payment request.
setValue will throw an error if you provide an invalid field identifier.
You can also use the Fluent API to set a field value.
try paymentRequest.field(id: "cardNumber").setValue(value: "1245 1254 4575 45")
Validate payment request
Once the server receives all the values, it can validate the payment request. The validation uses the DataRestrictions defined in the fields of the PaymentProduct added to the PaymentRequest. The validate() function returns a validation result, indicating whether the request is valid and whether it contains validation errors.
If there are no errors, you can encrypt the payment request and send it to our platform via your server. If there are validation errors, you should provide the customer with feedback on these errors.
// validate all fields in the payment requestlet validationResult = paymentRequest.validate()// check if the payment request is validif validationResult.isValid {// payment request is valid} else {// payment request has errorsvalidationResult.errors.forEach { error in// do something with the ValidationError, like displaying it to the user}}
Encrypt payment request
The PaymentRequest is ready for encryption only after the following conditions have been met:
- The PaymentProduct is set
- The PaymentRequestField values have been provided and validated
- The selected AccountOnFile or tokenize properties have been set (optional)
The sdk.encryptPaymentRequest handles the PaymentRequest encryption. This will return an EncryptedRequest containing the encrypted customer input and encoded client meta info.
sdk.encryptPaymentRequest(paymentRequest,success: { encryptedRequest in// Forward the encryptedRequest.encryptedCustomerInput to your server},failure: { error in// Handle failure of encrypting Payment Request})
Although you can use your own encryption algorithms to encrypt a payment request, we advise you to use the encryption functionality offered by the SDK.
StringFormatter
The SDK offers the StringFormatter class to help in formatting field values based on masks. It allows you to format field values and apply and unapply masks on a string.
let formatter = StringFormatter()let mask = "{{9999}} {{9999}} {{9999}} {{9999}}"let value = "1234567890123456"// apply masked valuelet maskedValue = formatter.formatString(string: value, mask: mask) // "1234 5678 9012 3456"// remove masked valuelet unmaskedValue = formatter.unformatString(string: value, mask: mask) // "1234567890123456"
Additional features
The SDK has a lot more to offer. Have a look at the following features, as they will help you build the perfect solution.
Encrypt sensitive data
One of the biggest assets of the SDK is its encryption tool. It offers great security when transferring sensitive data (i.e. card numbers, expiry date, CVC code). An entire encryption/transfer flow looks like this:
The SDK is here to simplify this process. Here is what you need to do:
- Use the sdk.encryptPaymentRequest to encrypt the payment information provided in the PaymentRequest.
- The sdk.encryptPaymentRequest returns the EncryptedRequest containing the encrypted customer data.
- Retrieve the encrypted customer input from the EncryptedRequest.
- Send the encrypted customer input to your server.
- Send the encrypted data from your server using the CreatePayment request. Provide the encrypted data in the encryptedCustomerInput field.
- Send the transaction result to the client application.
Do not store the encrypted data. Transfer it via the Server API directly to our platform right after the encryption.
sdk.encryptPaymentRequest(paymentRequest,success: { encryptedRequest in// Forward the encryptedCustomerInput to your server},failure: { error in// Handle failure of encrypting Payment Request})
The SDK does all the heavy lifting, including:
- Requesting a public key from the Client API
- Performing the encryption
- BASE-64 encoding the result into one string
You only need to ensure that the PaymentRequest object contains all the information entered by the user.
Although the payment data is encrypted on your customers' devices, they are still out of scope for your PCI-DSS certification level, as you cannot be responsible for the security of a device you do not control.
To keep the risk to card data and level as low as possible, we strongly recommend complying with the following:
- Use our Client SDK's encryption mechanism (public and private keys), which is in line with the requirements in PCI DSS. Encrypting card data on your customers' devices using our platform's public key ensures your e-commerce server will not process plain card data. Consequently, your required PCI type for this integration method is SAQ A.
- Develop your mobile app according to the PCI Security Standards Council's requirements as described in this FAQ.
Validate data
Each PaymentProductField has appropriate DataRestrictions. The DataRestrictions object contains information about all mandatory fields and validates whether the values entered meet the correctness condition. Together with a list of abstract validators, it also has a property isRequired. This property informs whether given restrictions are required or not.
You can validate a particular input just as easily as through the PaymentRequest validation. In case of any errors, the Errors field will display a list of errors.
It contains the following validators:
- Expiration Date: Checks whether the entered card expiration date is not earlier than the current date and whether it is not beyond the range of twenty-five years ahead.
- Email Address: Checks the format of the email address the customer has provided.
- Fixed List: Checks whether the entered value is on the list of possibilities.
- IBAN: Validates the IBAN the customer has provided.
- Length: Checks if the entered value is longer than the minimum value and if it is not longer than the maximum value.
- Luhn: The checksum formula used to validate a variety of identification numbers, such as credit card numbers.
- Range: Checks if the value is greater than the minimum value and if it is not greater than the maximum value.
- Regex: Validates that the entered value matches the regular expression.
- TermsAndConditions: The boolean validator for the terms and conditions accept field.
Each validator returns an appropriate error, indicating a field that does not meet the conditions, and a message you can easily translate.
Apply IIN check
The first six digits of a payment card number are known as the Issuer Identification Number (IIN). You can check the payment product and network associated with the entered IIN as soon as the customer enters the first six digits of their card number. Use the sdk.iinDetails call to retrieve that information and verify if you can accept that card type.
You can use an instance of OnlinePaymentsSdk to check which payment product is associated with an IIN. You do that with the iinDetails function. The result of this check is an instance of IINDetailsResponse. This class has the following:
- A property status indicating the result of the check
- Property paymentProductId indicating which payment product is associated with the IIN.
You can use the returned paymentProductId to fetch the PaymentProduct and show the appropriate logo to the customer.
The IINDetailsResponse has a status property represented through the IINStatus enum. The IINStatus enum values are:
- supported indicates that the IIN is associated with a payment product supported by our platform.
- unknown indicates that the IIN is not recognised.
- notEnoughDigits indicates that fewer than six digits were provided, and that it is impossible to perform the IIN check.
- existingButNotAllowed indicates that the provided IIN is recognised, but that the corresponding product is not allowed for the current payment or merchant.
sdk.iinDetails(forPartialCardNumber: "123456",paymentContext: paymentContext,success: { iinDetailsResponse in// check the status of the associated payment productlet iinStatus = iinDetailsResponse.status},failure: { error in// Handle failure of retrieving IIN details})
Some cards are co-branded and can be processed as either a local card (with a local brand) or an international card (with an international brand). The details of the first payment product your customers can use for the payment are always stored in the top-level fields of the IINDetailsResponse.
However, if co-branding applies, the list of instances of IINDetail contains all brands associated with the card. That includes the payment product stored in the top-level fields. Use this list to let the customers choose their preferred brand. If you are not set up to process these local cards, the list of IINDetails will return empty.
Implement native payments
Our system supports native payments for mobile devices, specifically Google Pay for Android and Apple Pay for iOS. However, that does not mean they will be available on every device.
If the customer receives a payment product responsible for the native payment, the SDK automatically verifies whether the device can handle the payment. If the device does not meet the conditions, this payment is hidden. As the user of our product, this procedure means you do not have to worry about verifying the correctness of the operation.
For iOS devices, you first verify whether the system meets the minimum version (8.0) criterion. Then, you use the PKPaymentAuthorizationViewController to check whether it is possible to carry out the transaction.
Refer to our Apple Pay guide for more information.