> ## Documentation Index
> Fetch the complete documentation index at: https://primer.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless mobile v2.16 to v2.17

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.

<Tabs>
  <Tab title="Android">
    ## Starting Headless Universal Checkout

    Like before, you still prepare the `PrimerHeadlessUniversalCheckoutListener` and start headless universal checkout with your client token.

    `onAvailablePaymentMethodsLoaded` now returns a list of payment methods with improved functionality.

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

    * `paymentMethodType`
      a unique string identifier for the payment method.
    * `paymentMethodManagerCategories`
      a list that defines the payment method managers that can be used with this payment method (i.e. `NATIVE_UI` or `RAW_DATA`).
    * \[Optional] `requiredInputDataClass`
      this is provided when `paymentMethodManagerCategories` contains `RAW_DATA` and indicates the type of data that should be captured for the payment method.
    * `supportedPrimerSessionIntents`
      a list of `PrimerSessionIntent` which defines what intents can be used with this payment method (i.e. `CHECKOUT` or `VAULT`).

    See an example below:

    ```kotlin KOTLIN theme={"dark"}
    class CheckoutActivity : AppCompatActivity() {
      private val listener = object : PrimerHeadlessUniversalCheckoutListener {
        override fun onAvailablePaymentMethodsLoaded(paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>) {
          // Primer will return the available payment methods based on configuration.
          // Use it to enable users to select a payment method.
            paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) }
        }
        override fun onCheckoutCompleted(checkoutData: PrimerCheckoutData) {
          // Primer checkout has been completed
          // checkoutData contains the payment that has been created
          // show an order confirmation screen
        }
        override fun onFailed(error: PrimerError, checkoutData: PrimerCheckoutData?) {
          // your custom method to show an error view
        }
      }
        // your custom method to render the list of payment method buttons UI.
        private fun setupPaymentMethod(paymentMethodType: String) {
          // implement payment method UI
        }
    }
    ```

    ## Building your UI

    Before when building your UI, you could create your own buttons using `headlessUniversalCheckout.makeView` like in the example below:

    ```kotlin KOTLIN theme={"dark"}
    private val listener = object : PrimerHeadlessUniversalCheckoutListener {
      override fun onAvailablePaymentMethodsLoaded(
        paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>
      ) {
        paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) }
      }
    }
    // your custom method to render the list of payment method buttons
    private fun setupPaymentMethod(paymentMethodType: String) {
      val containerView = findViewById<ViewGroup>(R.id.container)
      val view = headlessUniversalCheckout.makeView(paymentMethodType)
      view?.apply {
        containerView.addView(this)
        setOnClickListener {
          // TODO
        }
      }
    }
    ```

    You can now import the `PrimerHeadlessUniversalCheckoutAssetsManager` that provides payment method assets per payment method type. See below:

    ```kotlin KOTLIN theme={"dark"}
    private val listener = object : PrimerHeadlessUniversalCheckoutListener {
      override fun onAvailablePaymentMethodsLoaded(
        paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>
      ) {
        paymentMethods.forEach { setupPaymentMethod(it.paymentMethodType) }
      }
    }
    // your custom method to render the list of payment method buttons
    private fun setupPaymentMethod(paymentMethodType: String) {
        val paymentMethodAsset = try {
            PrimerHeadlessUniversalCheckoutAssetsManager.getPaymentMethodAsset(this, paymentMethodType)
          } catch (e: SdkUninitializedException) {
            null
          }
    }
    ```

    The payment method asset contains the following:

    * `paymentMethodType`
      a unique string identifier for the payment method.
    * `paymentMethodName`
      a user friendly English localized string identifier for the payment method (e.g. `Google Pay`)
    * `paymentMethodLogo`
      an instance of the PrimerPaymentMethodLogo
    * `paymentMethodBackgroundColor`
      an instance of the `PrimerPaymentMethodBackgroundColor`

    The `PrimerPaymentMethodLogo` holds `Drawable` objects for different scenarios

    * \[Optional] `colored`
      a `Drawable` to be used anywhere
    * \[Optional] `dark`
      a `Drawable` to be used in dark mode
    * \[Optional] `light`
      a `Drawable` to be used in light mode

    The `PrimerPaymentMethodBackgroundColor` holds `@ColorInt` objects for different scenarios

    \[Optional] `colored`
    a `@ColorInt` to be used anywhere
    \[Optional] `dark`
    a `@ColorInt` to be used in dark mode
    \[Optional] `light`
    a `@ColorInt` 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 Google Pay. See example integration below:

    ```kotlin KOTLIN theme={"dark"}
    class CheckoutActivity : AppCompatActivity() {
      // other code goes here
        private fun onPaymentMethodSelected(paymentMethodType: String) {
            try {
                val nativeUiManager = PrimerHeadlessUniversalCheckoutNativeUiManager.newInstance(paymentMethodType)
                nativeUiManager.showPaymentMethod(this, PrimerSessionIntent.CHECKOUT)
            } catch (e: SdkUninitializedException) {
                        // handle exception
            } catch (e: UnsupportedPaymentIntentException) {
                        // handle exception
            } catch (e: UnsupportedPaymentMethodException) {
                        // handle exception
                }
        }
    }
    ```

    ### 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 example integration below:

    ```kotlin KOTLIN theme={"dark"}
    class CheckoutActivity : AppCompatActivity() {
        // Enable your pay button
      val submitButton = findViewById<Button>(R.id.pay_with_card)
      private lateinit var rawDataManager: PrimerHeadlessUniversalCheckoutRawDataManagerInterface
      private val rawDataManagerListener: PrimerHeadlessUniversalCheckoutRawDataManagerListener =
        object : PrimerHeadlessUniversalCheckoutRawDataManagerListener {
          override fun onValidationChanged(
            isValid: Boolean,
            errors: List<PrimerInputValidationError>
          ) {
            // modify your UI
            submitButton.isEnabled = isValid
          }
          override fun onMetadataChanged(metadata: PrimerPaymentMethodMetadata) {
            // show card icon
          }
        }
    }
    private fun setupManager(paymentMethodType: String) {
                try {
                    rawDataManager =
                        PrimerHeadlessUniversalCheckoutRawDataManager.newInstance(paymentMethodType)
                    rawDataManager.setListener(rawDataManagerListener)
              } catch (e: SdkUninitializedException) {
                    // handle exception
                } catch (e: UnsupportedPaymentMethodException) {
                    // handle exception
                }
        }
    ```

    ## Other changes

    #### PrimerHeadlessUniversalCheckoutUiListener addition

    We have created new listener in order to separate payment events and UI ones. You can attach a listener by calling `PrimerHeadlessUniversalCheckout.current.start(uiListener = )`.

    #### PrimerHeadlessUniversalCheckoutListener updates

    Some listener functions have been renamed.

    | Before v2.17.0                 | After 2.17.0                                  |
    | ------------------------------ | --------------------------------------------- |
    | `fun onResumeSuccess`          | Renamed to `onCheckoutResume`                 |
    | `fun onAdditionalInfoReceived` | Renamed to `onCheckoutAdditionalInfoReceived` |

    Some listener functions have been removed and moved to different classes.

    | Before v2.17.0                                          | After 2.17.0                                         |
    | ------------------------------------------------------- | ---------------------------------------------------- |
    | `func onPreparationStarted(paymentMethodType: String)`  | Moved to `PrimerHeadlessUniversalCheckoutUiListener` |
    | `func onPaymentMethodShowed(paymentMethodType: String)` | Moved to `PrimerHeadlessUniversalCheckoutUiListener` |

    **Resume handler updates**
    Some listener functions provide a decision handler.

    You can process the data provided and once you’re ready you can call the decision handler with your relevant decision. Once you do, the SDK will continue the flow. We have changed the handler class name and signature of following functions have changed:

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```kotlin KOTLIN theme={"dark"}
        fun onTokenizeSuccess(
          paymentMethodTokenData: PrimerPaymentMethodTokenData,
          decisionHandler: PrimerResumeDecisionHandler
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        fun onResumeSuccess(
          resumeToken: String,
          decisionHandler: PrimerResumeDecisionHandler
        )
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```kotlin KOTLIN theme={"dark"}
        fun onTokenizeSuccess(
          paymentMethodTokenData: PrimerPaymentMethodTokenData,
          decisionHandler: PrimerHeadlessUniversalCheckoutResumeDecisionHandler
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        fun onCheckoutResume(
          resumeToken: String,
          decisionHandler: PrimerHeadlessUniversalCheckoutResumeDecisionHandler
        )
        ```
      </div>
    </div>

    **Miscellaneous changes** <br />

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

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerRawCardData(
          val cardNumber: String,
          val expirationMonth: String,
          val expirationYear: String,
          val cvv: String,
          val cardHolderName: String? = null,
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerRawBancontactCardData(
          val cardNumber: String,
          val expirationMonth: String,
          val expirationYear: String,
          val cardHolderName: String,
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerRawPhoneNumberData(
            val phoneNumber: String
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerRawRetailerData(val id: String)
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerCardData(
          val cardNumber: String,
          val expiryDate: String,
          val cvv: String,
          val cardHolderName: String? = null,
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerBancontactCardData(
          val cardNumber: String,
          val expiryDate: String,
          val cardHolderName: String,
        )
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerPhoneNumberData(val phoneNumber: String)
        ```

        ```kotlin KOTLIN theme={"dark"}
        data class PrimerRetailerData(val id: String)
        ```
      </div>
    </div>
  </Tab>

  <Tab title="iOS">
    ## 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:

    ```swift SWIFT theme={"dark"}
    import UIKit
    // 👇 Import the SDK
    import 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) {
        }
    }
    ```

    ## Building your UI

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

    ```swift SWIFT theme={"dark"}
    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
      }
    }
    ```

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

    ```swift SWIFT theme={"dark"}
    do {
            let paymentMethodAsset = try PrimerHeadlessUniversalCheckout.AssetsManager.getPaymentMethodAsset(for: paymentMethod.paymentMethodType)
    } catch {
            // Handle error
    }
    ```

    The payment method asset contains the following:

    * `paymentMethodType`
      a unique string identifier for the payment method.

    * `paymentMethodName`
      a 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:

    ```swift SWIFT theme={"dark"}
    import UIKit
    import 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
            }
        }
    }
    ```

    ### 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:

    ```swift theme={"dark"}
    import UIKit
    import 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()
        }
    }
    ```

    ### 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

    ```swift SWIFT theme={"dark"}
    PrimerHeadlessUniversalCheckout.current.start(..., uiDelegate: self, ...)
    ```

    #### PrimerHeadlessUniversalCheckoutDelegate updates

    Some delegate functions have been renamed:

    | Before v2.17.0                                                                                     | After 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.0                                                                            | After 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:

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```swift SWIFT theme={"dark"}
        func primerHeadlessUniversalCheckoutDidTokenizePaymentMethod(
            _ paymentMethodTokenData: PrimerPaymentMethodTokenData,
            decisionHandler: @escaping (PrimerResumeDecision) -> Void
        )
        ```

        ```swift SWIFT theme={"dark"}
        func primerHeadlessUniversalCheckoutDidResumeWith(
            _ resumeToken: String,
            decisionHandler: @escaping (PrimerResumeDecision) -> Void
        )
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```swift SWIFT theme={"dark"}
        func primerHeadlessUniversalCheckoutDidTokenizePaymentMethod(
            _ paymentMethodTokenData: PrimerPaymentMethodTokenData,
            decisionHandler: @escaping (PrimerHeadlessUniversalCheckoutResumeDecision) -> Void
        )
        ```

        ```swift SWIFT theme={"dark"}
        func primerHeadlessUniversalCheckoutDidResumeWith(
            _ resumeToken: String,
            decisionHandler: @escaping (PrimerHeadlessUniversalCheckoutResumeDecision) -> Void
        )
        ```
      </div>
    </div>

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

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```swift SWIFT theme={"dark"}
        class PrimerCardData(
          var cardNumber: String,
          var expirationMonth: String,
          var expirationYear: String,
          var cvv: String,
          var cardHolderName: String?
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerBancontactCardRedirectData(
          var cardNumber: String,
          var expirationMonth: String,
          var expirationYear: String,
          var cardHolderName: String
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerPhoneNumberData(
            var phoneNumber: String
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerRawRetailerData(
            id: String
        )
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```swift SWIFT theme={"dark"}
        class PrimerCardData(
          var cardNumber: String,
          var expirationDate: String,
          var cvv: String,
          var cardHolderName: String?
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerBancontactCardData(
          var cardNumber: String,
          var expiryDate: String,
          var cardHolderName: String
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerPhoneNumberData(
            var phoneNumber: String
        )
        ```

        ```swift SWIFT theme={"dark"}
        class PrimerRetailerData(
            id: String
        )
        ```
      </div>
    </div>
  </Tab>

  <Tab title="React Native">
    ## 🚀 Starting Headless Universal Checkout

    As before, you still set Headless Universal Checkout callbacks to handle events during the checkout’s lifecycle.

    Previously you passed all the individual callbacks in `PrimerSettings`, like below:

    ```typescript TypeScript theme={"dark"}
    const settings: PrimerSettings = {
        // Any other settings & callbacks (see the Quick Start Guide
        // and the SDK API reference)
        onAvailablePaymentMethodsLoad: onAvailablePaymentMethodsLoad,
        onPrepareStart: onPrepareStart,
        onPaymentMethodShow: onPaymentMethodShow,
        onTokenizeStart: onTokenizeStart,
        onCheckoutComplete: onCheckoutComplete,
    }
    ```

    Now these callbacks can be set on the `headlessUniversalCheckoutCallbacks` property of `PrimerSettings`:

    ```typescript TypeScript theme={"dark"}
    import { HeadlessUniversalCheckout } from '@primer-io/react-native';
    export const HeadlessUniversalCheckoutScreen = () => {
            useEffect(() => {
                    const settings: PrimerSettings = {
                            //...
                            headlessUniversalCheckoutCallbacks: {
                                    onCheckoutComplete: (checkoutData) => {
                                // Here you will receive the checkout data of the payment.
                            }
                            }
                    }
                const availablePaymentMethods = await HeadlessUniversalCheckout.startWithClientToken(clientToken, settings);
                // Store the available payment methods for the session.
            }, [clientToken]);
    }
    ```

    In addition, for the `availablePaymentMethods` returned when headless universal checkout is created, the payload will change.

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

    * `paymentMethodType`
      a unique string identifier for the payment method.
    * `paymentMethodManagerCategories`
      an array which defines the payment method managers that can be used with this payment method (i.e. NATIVE\_UI or RAW\_DATA). Use this to know which payment method managers to create.
    * \[Optional] `requiredInputDataClass`
      this is provided with the RAW\_DATA payment method manager and indicates the type of data that should be captured for the payment method.
    * `supportedPrimerSessionIntents`
      an array of `SessionIntent` which defines what intents can be used with this payment method (i.e. `.checkout` or `.vault`).

    ## Building your UI

    You can build your UI by using the AssetsManager. You can access the payment methods’ assets like below:

    ```typescript TypeScript theme={"dark"}
    const getPaymentMethodAssets = (): Promise<Asset[]> => {
        const assetsManager = new AssetsManager()
        const assets: Asset[] = await assetsManager.getPaymentMethodAssets()
        return assets
    }
    ```

    The payment method asset contains the following:

    * `paymentMethodType`: a unique string identifier for the payment method.

    * `paymentMethodName`
      a user friendly English localized string identifier for the payment method (e.g. `Apple Pay`)
      `paymentMethodLogo` which contains the logos’ local URLs

      * `colored?: string`: Local URL for the colored value of the logo
      * `dark?: string`: Local URL for the dark value of the logo
      * `light?: string`: Local URL for the light value of the logo

    * `paymentMethodBackgroundColor` which contains the background colors hex values
      * `colored?: string`: Color hex value for the colored background color
      * `dark?: string`: Color hex value for the dark mode background color
      * `light?: string`: Color hex value for the light mode background color
        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 example integration below:

    ```typescript TypeScript theme={"dark"}
    const payWithPaymentMethod = async (paymentMethodType: string) => {
        const nativeUIManager = new NativeUIManager()
        await nativeUIManager.configure({ paymentMethodType: paymentMethod.paymentMethodType })
        await nativeUIManager.showPaymentMethod(SessionIntent.CHECKOUT)
    }
    ```

    ## 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:

    ```typescript TypeScript theme={"dark"}
    const rawDataManager = new RawDataManager();
    const initialize = async (paymentMethod: PaymentMethod) => {
        await rawDataManager.configure({
            paymentMethodType: paymentMethod.paymentMethodType,
            onMetadataChange: (data => {
                // For example card number detected to be Visa
            }),
            onValidation: ((isVallid, errors) => {
                // Show on your UI if the card data aren't valid
            })
        });
        const requiredInputElementTypes = await rawDataManager.getRequiredInputElementTypes();
        setRequiredInputElementTypes(requiredInputElementTypes);
    }
    // ....
    // Build your own Pay button and call "submit"
    const pay = async () => {
        await rawDataManager.submit();
    }
        
    ```

    ## Other changes

    ### Callback updates

    Some callbacks have been renamed:

    | Before v2.17.0                       | After 2.17.0                               |
    | ------------------------------------ | ------------------------------------------ |
    | `onHUCAvailablePaymentMethodsLoaded` | Renamed to `onAvailablePaymentMethodsLoad` |
    | `onHUCPrepareStart`                  | Renamed to `onPreparationStart`            |
    | `onHUCTokenizeStart`                 | Renamed to `onTokenizationStart`           |
    | `onHUCPaymentMethodShow`             | Renamed to `onPaymentMethodShow`           |
    | `onResumePending`                    | Renamed to `onCheckoutPending`             |
    | `onCheckoutReceivedAdditionalInfo`   | Renamed to `onCheckoutAdditionalInfo`      |

    **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:

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```typescript theme={"dark"}
        onTokenizationSuccess?: (
            paymentMethodTokenData: PrimerPaymentMethodTokenData,
            handler: PrimerTokenizationHandler
        ) => void;
        ```

        ```typescript theme={"dark"}
        onResumeSuccess?: (
            resumeToken: string,
            handler: PrimerResumeHandler
        ) => void;
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```typescript Typescript theme={"dark"}
        onTokenizeSuccess?: (
            paymentMethodTokenData: PrimerPaymentMethodTokenData,
            handler: PrimerHeadlessUniversalCheckoutResumeHandler
        ) => void;
        ```

        ```typescript Typescript theme={"dark"}
        onCheckoutResume?: (
            resumeToken: string,
            handler: PrimerHeadlessUniversalCheckoutResumeHandler
        ) => void;
        ```
      </div>
    </div>

    **Miscellaneous changes** <br />
    The interfaces that need to be passed to the SDK when using Raw Data Managers have changed structures and names:

    <div style={{ display: 'flex', gap: '24px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
      <div style={{ flex: 1, minWidth: '300px' }}>
        #### Before v2.17.0

        ```typescript Typescript theme={"dark"}
        interface PrimerRawCardData {
            cardNumber: string
            expiryMonth: string
            expiryYear: string
            cvv: string
            cardholderName?: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface PrimerBancontactCardRedirectData {
            cardNumber: string
            expiryMonth: string
            expiryYear: string
            cardholderName: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface PrimerRawPhoneNumberData {
            phoneNumber: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface PrimerRawRetailerData {
            id: string
        }
        ```
      </div>

      <div style={{ flex: 1, minWidth: '300px' }}>
        #### After 2.17.0

        ```typescript Typescript theme={"dark"}
        interface CardData {
            cardNumber: string
            expiryDate: string
            cvv: string
            cardholderName?: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface BancontactCardData {
            cardNumber: string
            expiryDate: string
            cardholderName: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface PhoneNumberData {
            phoneNumber: string
        }
        ```

        ```typescript Typescript theme={"dark"}
        interface RetailerData {
            id: string
        }
        ```
      </div>
    </div>
  </Tab>
</Tabs>
