Headless Universal Checkout has changed to solidify the integration experience and make the interfaces clearer and more consistent.

Below is a summary of the changes and examples of how to migrate to this new integration, however we recommend you consult the full documentation during integration.

Starting Headless Universal Checkout

Like before, you still set Headless Universal Checkout delegate, conform to PrimerHeadlessUniversalCheckoutDelegate to handle the callbacks that happen during the checkout’s lifecycle, and start headless universal checkout with your client token.

The completion handler returns the available payment methods for the session when you start PrimerHeadlessUniversalCheckout.

Instead of just a string, each payment method returned contains the following:

  • paymentMethodType
    a unique string identifier for the payment method.
  • paymentMethodManagerCategories
    an array that defines the payment method managers that can be used with this payment method (i.e. .cardComponents, .nativeUI or .rawData). Use this to know which payment method managers to create.
  • [Optional] requiredInputDataClass
    this is provided when paymentMethodManagerCategories contains .rawData and indicates the type of data that should be captured for the payment method.
  • supportedPrimerSessionIntents
    an array of PrimerSessionIntent which defines what intents can be used with this payment method (i.e. .checkout or .vault).

See an example below:

12345678910111213141516171819202122232425262728293031323334
import UIKit// 👇 Import the SDKimport PrimerSDK
class ViewController: UIViewController {
        // ...
        var availablePaymentMethods: [PrimerHeadlessUniversalCheckout.PaymentMethod]?
    override func viewDidLoad() {        super.viewDidLoad()
                // ...
                // 👇 Start Headless Universal Checkout with your session's client token        PrimerHeadlessUniversalCheckout.current.start(withClientToken: clientToken, delegate: self) { availablePaymentMethods, err in            if let err = err {                // Handle error            } else if let availablePaymentMethods = availablePaymentMethods {                // Payment methods that are available for this session                self.availablePaymentMethods = availablePaymentMethods            }        }    }}
extension ViewController: PrimerHeadlessUniversalCheckoutDelegate {
        // 👇 [Required] This function will return the checkout data once the payment is finished    func primerHeadlessUniversalCheckoutDidCompleteCheckoutWithData(_ data: PrimerCheckoutData) {
    }}
swift
copy

Building your UI

Before, when building your UI you could create your own buttons using PrimerHeadlessUniversalCheckout.makeButton like in the example below:

123456789101112131415161718192021222324
extension UIViewController: UITableViewDataSource, UITableViewDelegate {
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {    return self.paymentMethods.count  }
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {    let paymentMethod = self.paymentMethods[indexPath.row]    let cell = tableView.dequeueReusableCell(withIdentifier: "MerchantPaymentMethodCell", for: indexPath) as! MerchantPaymentMethodCell    cell.configure(paymentMethodType: paymentMethod)
    // Primer SDK can provide you with Payment Method buttons that follow    // the payment methods UI guidelines.    // Example given for Apple Pay payment method    // https://developer.apple.com/design/human-interface-guidelines/technologies/apple-pay/introduction    // let paymentMethodButton = PrimerHeadlessUniversalCheckout.makeButton(for: paymentMethod)
    return cell  }
  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {    // The user has selected a payment method  }}
swift
copy

PrimerHeadlessUniversalCheckout now includes an AssetsManager that provides payment method assets per payment method type. See below:

12345
do {        let paymentMethodAsset = try PrimerHeadlessUniversalCheckout.AssetsManager.getPaymentMethodAsset(for: paymentMethod.paymentMethodType)} catch {        // Handle error}
swift
copy

The payment method asset contains the following:

  • paymentMethodType
    a unique string identifier for the payment method.
  • paymentMethodName
    an user friendly English localized string identifier for the payment method (e.g. Apple Pay)
  • paymentMethodLogo
    an instance of the PrimerPaymentMethodLogo (see more information below)
  • paymentMethodBackgroundColor
    an instance of the PrimerPaymentMethodBackgroundColor

The PrimerPaymentMethodLogo holds UIImage objects for different scenarios

  • [Optional] colored
    a UIImage to be used anywhere
  • [Optional] dark
    a UIImage to be used in dark mode
  • [Optional] light
    a UIImage to be used in light mode

The PrimerPaymentMethodBackgroundColor holds UIColor objects for different scenarios

  • [Optional] colored
    a UIColor to be used anywhere
  • [Optional] dark
    a UIColor to be used in dark mode
  • [Optional] light
    a UIColor to be used in light mode

With the above images and colors, you can build your own payment method buttons 💪

Handling Payment Methods

Before you had to call showPaymentMethod directly for some payment methods while having managers for others. Now each payment method belongs to a payment method manager, as indicated by paymentMethodManagerCategories on the list of available payment methods.

Native UI Manager

Used for any payment method that needs to present its own UI, like Apple Pay. See an example integration below:

1234567891011121314151617181920
import UIKitimport PrimerSDK
class ViewController: UIViewController {
    // ...
    @IBAction func paymentMethodButtonTapped(_ sender: UIButton) {        do {            // 👇 Create the payment method manager            let nativeUIPaymentMethodManager = try PrimerHeadlessUniversalCheckout.NativeUIManager(paymentMethodType: paymentMethod.paymentMethodType)
            // 👇 Show the payment method            try nativeUIPaymentMethodManager.showPaymentMethod(intent: .checkout)
        } catch {            // Handle error        }    }}
swift
copy

Raw Data Manager

Used for payment methods that require you to pass data to the SDK, for example for cards. As before, you have to render your own input elements and capture the required data before finally calling submit() on the raw data manager. See an example integration below:

1234567891011121314151617181920212223242526272829
import UIKitimport PrimerSDK
class ViewController: UIViewController {
    // ...
    var rawDataManager: PrimerHeadlessUniversalCheckout.RawDataManager!
    override func viewDidLoad() {        super.viewDidLoad()
        // ...
        do {            // 👇 Optionally, you can also set its delegate to get notified about data and validation changes            self.rawDataManager = try PrimerHeadlessUniversalCheckout.RawDataManager(paymentMethodType: paymentMethod.paymentMethodType)
            // Capture required inputs...
        } catch {            // Handle error        }    }
    @IBAction func payButtonTapped(_ sender: UIButton) {        self.rawDataManager.submit()    }}
swift
copy

Other changes

PrimerHeadlessUniversalCheckoutUIDelegate addition

New delegates have been introduced to separate payment events from UI events.

You can set the UI delegate in the start function

1
PrimerHeadlessUniversalCheckout.current.start(..., uiDelegate: self, ...)
swift
copy

PrimerHeadlessUniversalCheckoutDelegate updates

Some delegate functions have been renamed:

Before v2.17.0After 2.17.0

func primerHeadlessUniversalCheckoutTokenizationDidStart(for paymentMethodType: String)

Renamed to func primerHeadlessUniversalCheckoutDidStartTokenization(for paymentMethodType: String)

func primerHeadlessUniversalCheckoutClientSessionWillUpdate()

Renamed to func primerHeadlessUniversalCheckoutWillUpdateClientSession()

func primerHeadlessUniversalCheckoutClientSessionDidUpdate(_ clientSession: PrimerClientSession)

Renamed to func primerHeadlessUniversalCheckoutDidUpdateClientSession(_ clientSession: PrimerClientSession)

Some delegate functions have been renamed and moved to other delegates:

Before v2.17.0After 2.17.0

func primerHeadlessUniversalCheckoutPreparationDidStart(for paymentMethodType: String)

Moved to PrimerHeadlessUniversalCheckoutUIDelegate as func primerHeadlessUniversalCheckoutUIDidStartPreparation(for paymentMethodType: String)

func primerHeadlessUniversalCheckoutPaymentMethodDidShow(for paymentMethodType: String)

Moved to PrimerHeadlessUniversalCheckoutUIDelegate as func primerHeadlessUniversalCheckoutUIDidShowPaymentMethod(for paymentMethodType: String)

Resume handler updates

Some listener functions provide a decision handler that you can call with the relevant decision to continue the flow.

The handler class name and signature of the following functions have changed:

Before v2.17.0After 2.17.0
1234
func primerHeadlessUniversalCheckoutDidTokenizePaymentMethod(    _ paymentMethodTokenData: PrimerPaymentMethodTokenData,    decisionHandler: @escaping (PrimerResumeDecision) -> Void)
swift
copy
1234
func primerHeadlessUniversalCheckoutDidTokenizePaymentMethod(    _ paymentMethodTokenData: PrimerPaymentMethodTokenData,    decisionHandler: @escaping (PrimerHeadlessUniversalCheckoutResumeDecision) -> Void)
swift
copy
1234
func primerHeadlessUniversalCheckoutDidResumeWith(    _ resumeToken: String,    decisionHandler: @escaping (PrimerResumeDecision) -> Void)
swift
copy
1234
func primerHeadlessUniversalCheckoutDidResumeWith(    _ resumeToken: String,    decisionHandler: @escaping (PrimerHeadlessUniversalCheckoutResumeDecision) -> Void)
swift
copy

Miscellaneous changes

Models that need to be passed to the SDK when using Raw Data Managers have changed structures and naming:

Before v2.17.0After 2.17.0
1234567
class PrimerCardData(  var cardNumber: String,  var expirationMonth: String,  var expirationYear: String,  var cvv: String,  var cardHolderName: String?)
swift
copy
123456
class PrimerCardData(  var cardNumber: String,  var expirationDate: String,  var cvv: String,  var cardHolderName: String?)
swift
copy
123456
class PrimerBancontactCardRedirectData(  var cardNumber: String,  var expirationMonth: String,  var expirationYear: String,  var cardHolderName: String)
swift
copy
12345
class PrimerBancontactCardData(  var cardNumber: String,  var expiryDate: String,  var cardHolderName: String)
swift
copy
123
class PrimerPhoneNumberData(    var phoneNumber: String)
swift
copy
123
class PrimerPhoneNumberData(    var phoneNumber: String)
swift
copy
123
class PrimerRawRetailerData(    id: String)
swift
copy
123
class PrimerRetailerData(    id: String)
swift
copy