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

# PrimerHeadlessUniversalCheckoutListener

export const TxnTag = ({status}) => {
  const getStyles = status => {
    const baseStyle = {
      display: 'inline-block',
      padding: '4px 8px',
      borderRadius: '4px',
      fontSize: '13px',
      fontWeight: '400'
    };
    switch (status) {
      case "PENDING":
        return {
          ...baseStyle,
          backgroundColor: '#ececec',
          color: '#9f9f9f'
        };
      case "AUTHORIZED":
        return {
          ...baseStyle,
          backgroundColor: '#ecfdf5',
          color: '#047857'
        };
      case "SETTLED":
      case "PARTIALLY_SETTLED":
        return {
          ...baseStyle,
          backgroundColor: '#ecfdf5',
          color: '#047857'
        };
      case "DECLINED":
      case "FAILED":
        return {
          ...baseStyle,
          backgroundColor: '#fef2f2',
          color: '#dc2626'
        };
      case "CANCELLED":
        return {
          ...baseStyle,
          backgroundColor: '#fefce8',
          color: '#d78203'
        };
      case "SETTLING":
        return {
          ...baseStyle,
          backgroundColor: '#e0f2fe',
          color: '#0c4a6e'
        };
      default:
        return {
          ...baseStyle,
          backgroundColor: '#f3f4f6',
          color: '#374151'
        };
    }
  };
  return <span style={getStyles(status)}>{status}</span>;
};

## Overview

Set the `PrimerHeadlessUniversalCheckoutListener` in order to receive different callbacks from Primer SDK.

Callbacks can be used for managing the customer journey and trigger actions after specific events
throughout the payment journey. See below for a breakdown of all callbacks supported within the Primer SDK.

## onAvailablePaymentMethodsLoaded

This method will return the payment methods that should be displayed based on the current client session data.

```kotlin KOTLIN theme={"dark"}
fun onAvailablePaymentMethodsLoaded(
  paymentMethods: List<PrimerHeadlessUniversalCheckoutPaymentMethod>
)
```

### Parameters

<Expandable title="Parameters" defaultOpen>
  <ResponseField name="paymentMethods" type="List<PrimerHeadlessUniversalCheckoutPaymentMethod>" required>
    <Expandable title="PrimerHeadlessUniversalCheckoutPaymentMethod" defaultOpen>
      <ResponseField name="paymentMethodType" type="String" required>
        A unique string identifier for the payment method.
      </ResponseField>

      <ResponseField name="supportedPrimerSessionIntents" type="List<PrimerSessionIntent>" required>
        A list of PrimerSessionIntent which defines what intents can be used with this payment method.

        <Expandable title="PrimerSessionIntent" defaultOpen={props.openGroup}>
          <ResponseField name="PrimerSessionIntent.CHECKOUT">
            {}
          </ResponseField>

          <ResponseField name="PrimerSessionIntent.VAULT">
            {}
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="paymentMethodManagerCategories" type="PrimerPaymentMethodManagerCategory" required>
        A list which defines the payment method managers that can be used with this payment method.

        <Expandable title="PrimerPaymentMethodManagerCategory" defaultOpen={props.openGroup}>
          <ResponseField name="PrimerPaymentMethodManagerCategory.NATIVE_UI">
            Indicates that the supported payment method manager for the payment method is [PrimerHeadlessUniversalCheckoutNativeUiManager](/sdk/android/v2.x.x/primer-headless-checkout/native-ui-manager/newInstance).
          </ResponseField>

          <ResponseField name="PrimerPaymentMethodManagerCategory.RAW_DATA">
            Indicates that the supported payment method manager for the payment method is [PrimerHeadlessUniversalCheckoutRawDataManager](/sdk/android/v2.x.x/primer-headless-checkout/raw-data-manager/newInstance).
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="requiredInputDataClass" type="KClass<out PrimerRawData>?">
        Indicates the subclass of the PrimerRawData that must be set using the [PrimerHeadlessUniversalCheckoutRawManager](/sdk/android/v2.x.x/primer-headless-checkout/raw-data-manager/setRawData).
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

## onCheckoutCompleted

This method will be called when the payment has been completed, returning the payment' data.

<Warning>
  This method **won't** be called when you are using
  `PrimerPaymentHandling.MANUAL`
  [flow](/sdk/android/v2.x.x/common-objects/PrimerSettings), or the
  `PrimerSessionIntent.VAULT` [session
  intent](/sdk/android/v2.x.x/common-objects/PrimerSessionIntent).
</Warning>

```kotlin KOTLIN theme={"dark"}
fun onCheckoutCompleted(checkoutData: PrimerCheckoutData)
```

### Parameters

<Expandable defaultOpen title="Parameters">
  <ResponseField name="checkoutData" type="PrimerCheckoutData" required>
    <Expandable defaultOpen>
      <ResponseField name="payment" type="Payment" required>
        <Expandable name="Properties" defaultOpen>
          <ResponseField name="id" type="String" required>
            ID of created payment.
          </ResponseField>

          <ResponseField name="orderId" type="String" required>
            Order ID of created payment.
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="additionalInfo" type="PrimerCheckoutAdditionalInfo?">
        <Expandable title="direct subclasses" defaultOpen>
          <ResponseField name="XenditCheckoutVoucherAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="couponCode" type="String" required />

              <ResponseField name="retailerName" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="PromptPayCheckoutAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="qrCodeUrl" type="String?" />

              <ResponseField name="qrCodeBase64" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="MultibancoCheckoutAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="entity" type="String" required />

              <ResponseField name="reference" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="AchAdditionalInfo">
            <Expandable title="direct subclasses" defaultOpen>
              <ResponseField name="ProvideActivityResultRegistry">
                <Expandable title="Properties" defaultOpen>
                  <ResponseField name="provide" type="(ActivityResultRegistry) -> Unit" required>
                    Provides an ActivityResultRegistry to be used for ACH bank account
                    selection.
                  </ResponseField>
                </Expandable>
              </ResponseField>

              <ResponseField name="DisplayMandate">
                <Expandable title="Properties" defaultOpen>
                  <ResponseField name="onAcceptMandate" type="suspend () -> Unit" required>
                    Accepts the ACH mandate, completing the payment.
                  </ResponseField>

                  <ResponseField name="onDeclineMandate" type="suspend () -> Unit" required>
                    Declines the ACH mandate, cancelling the payment.
                  </ResponseField>
                </Expandable>
              </ResponseField>
            </Expandable>
          </ResponseField>
        </Expandable>
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

## onBeforePaymentCreated

This method will be called just before the payment gets created, and lets you decide whether you want to proceed
with the payment creation.

<Warning>
  This method will be called only when using the `PrimerPaymentHandling.AUTO`
  [flow](/sdk/android/v2.x.x/common-objects/PrimerSettings). Please note,
  that if you `override` this method, you **must** call one of the
  decisionHandler's methods.
</Warning>

```kotlin KOTLIN theme={"dark"}
fun onBeforePaymentCreated(
  paymentMethodData: PrimerPaymentMethodData,
  decisionHandler: PrimerPaymentCreationDecisionHandler
)
```

### Parameters

<Expandable defaultOpen title="Parameters">
  <ResponseField name="paymentMethodData" type="PrimerPaymentMethodData" required>
    <Expandable defaultOpen>
      <ResponseField name="paymentMethodType" type="String" required>
        A unique string identifier for the payment method. (e.g. `PAYPAL`, `GOOGLE_PAY`)
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="decisionHandler" type="PrimerPaymentCreationDecisionHandler" required>
    <Expandable title="Methods">
      <ResponseField name="continuePaymentCreation(idempotencyKey: String? = null)">
        Call `continuePaymentCreation()` when you want to continue with the payment creation.
        Optionally provide an `idempotencyKey` to prevent duplicate payments. The SDK attaches it as `X-Idempotency-Key` header on payment creation and resume requests. The same key is reused for the entire payment lifecycle and automatically cleared on completion or failure.
      </ResponseField>

      <ResponseField name="abortPaymentCreation(errorMessage)">
        Call `abortPaymentCreation(errorMessage)` when you want to abort the payment. Optionally you can provide an error message to get presented on the error screen.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

### Example

```kotlin KOTLIN theme={"dark"}
class CheckoutActivity : AppCompatActivity() {
  // 👇 Add this
  private val listener = object : PrimerCheckoutListener {
    // 👇 Add this
    override fun onBeforePaymentCreated(
      paymentMethodData: PrimerPaymentMethodData,
      decisionHandler: PrimerPaymentCreationDecisionHandler
    ) {
      decisionHandler.continuePaymentCreation()
    }
  }
}
```

### Example with Idempotency Key

```kotlin KOTLIN theme={"dark"}
class CheckoutActivity : AppCompatActivity() {
  private val listener = object : PrimerCheckoutListener {
    override fun onBeforePaymentCreated(
      paymentMethodData: PrimerPaymentMethodData,
      decisionHandler: PrimerPaymentCreationDecisionHandler
    ) {
      val idempotencyKey = "${UUID.randomUUID()}"
      decisionHandler.continuePaymentCreation(idempotencyKey = idempotencyKey)
    }
  }
}
```

## onCheckoutAdditionalInfoReceived

This callback is triggered when the payment is not authorized as it's an asynchronous alternative payment method, such as a voucher payment method.

```kotlin KOTLIN theme={"dark"}
fun onCheckoutAdditionalInfoReceived(additionalInfo: PrimerCheckoutAdditionalInfo)
```

<Expandable title="Parameters" defaultOpen>
  <ResponseField name="additionalInfo" type="PrimerCheckoutAdditionalInfo" required>
    <Expandable title="direct subclasses" defaultOpen>
      <ResponseField name="XenditCheckoutVoucherAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="couponCode" type="String" required />

          <ResponseField name="retailerName" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="PromptPayCheckoutAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="qrCodeUrl" type="String?" />

          <ResponseField name="qrCodeBase64" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="MultibancoCheckoutAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="entity" type="String" required />

          <ResponseField name="reference" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="AchAdditionalInfo">
        <Expandable title="direct subclasses" defaultOpen>
          <ResponseField name="ProvideActivityResultRegistry">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="provide" type="(ActivityResultRegistry) -> Unit" required>
                Provides an ActivityResultRegistry to be used for ACH bank account
                selection.
              </ResponseField>
            </Expandable>
          </ResponseField>

          <ResponseField name="DisplayMandate">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="onAcceptMandate" type="suspend () -> Unit" required>
                Accepts the ACH mandate, completing the payment.
              </ResponseField>

              <ResponseField name="onDeclineMandate" type="suspend () -> Unit" required>
                Declines the ACH mandate, cancelling the payment.
              </ResponseField>
            </Expandable>
          </ResponseField>
        </Expandable>
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

## onTokenizeSuccess

This method will be called with the when the payment method has been is tokenized,
returning the payment method's tokenization data. Use the `token` to create a payment on your backend.
Make sure that you call the `decisionHandler` once your operation has been completed.

<Warning>
  This method **will** be called when you are using
  `PrimerPaymentHandling.MANUAL`
  [flow](/sdk/android/v2.x.x/common-objects/PrimerSettings), or the
  `PrimerSessionIntent.VAULT` [session
  intent](/sdk/android/v2.x.x/common-objects/PrimerSessionIntent).
</Warning>

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

### Parameters

<Expandable defaultOpen>
  <ResponseField name="paymentMethodTokenData" type="PrimerPaymentMethodTokenData" required>
    <Expandable title="Properties">
      <ResponseField name="token" type="String" required>
        {}
      </ResponseField>

      <ResponseField name="tokenType" type="TokenType" required>
        <Expandable title="Cases" defaultOpen>
          <ResponseField name="MULTI_USE">
            {}
          </ResponseField>

          <ResponseField name="SINGLE_USE">
            {}
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="analyticsId" type="String" required>
        {}
      </ResponseField>

      <ResponseField name="paymentInstrumentType" type="String" required>
        {}
      </ResponseField>

      <ResponseField name="paymentInstrumentData" type="PaymentInstrumentData?">
        <Expandable title="Properties">
          <ResponseField name="network" type="String?">
            The human readable representation of card network (e.g., Visa, Mastercard).
          </ResponseField>

          <ResponseField name="cardholderName" type="String?">
            The name of the cardholder.
          </ResponseField>

          <ResponseField name="first6Digits" type="Int?">
            The first 6 digits of the card number.
          </ResponseField>

          <ResponseField name="last4Digits" type="Int?">
            The last 4 digits of the card number.
          </ResponseField>

          <ResponseField name="accountNumberLast4Digits" type="Int?">
            The last 4 digits of the account number.
          </ResponseField>

          <ResponseField name="expirationMonth" type="Int?">
            The expiration month of the card, in 2-digit format.
          </ResponseField>

          <ResponseField name="expirationYear" type="Int?">
            The expiration year of the card, in 4-digit format.
          </ResponseField>

          <ResponseField name="externalPayerInfo" type="ExternalPayerInfo?">
            External information about the payer associated with the transaction.

            <Expandable title="Properties" defaultOpen>
              <ResponseField name="email" type="String">
                The payer's email address.
              </ResponseField>

              <ResponseField name="externalPayerId" type="String?">
                The payer's unique ID.
              </ResponseField>

              <ResponseField name="firstName" type="String?">
                The payer's given name.
              </ResponseField>

              <ResponseField name="lastName" type="String?">
                The payer's given surname.
              </ResponseField>
            </Expandable>
          </ResponseField>

          <ResponseField name="klarnaCustomerToken" type="String?" />

          <ResponseField name="sessionData" type="SessionData?" />

          <ResponseField name="paymentMethodType" type="String?">
            A unique string identifier for the payment method. (e.g. `PAYPAL`,
            `GOOGLE_PAY`)
          </ResponseField>

          <ResponseField name="binData" type="BinData?">
            Additional BIN data.

            <Expandable title="Properties" defaultOpen>
              <ResponseField name="network" type="String?">
                The card network (e.g., VISA, MASTERCARD, AMEX).
              </ResponseField>
            </Expandable>
          </ResponseField>

          <ResponseField name="bankName" type="String?">
            The name of the bank.
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="vaultData" type="VaultData?">
        {}
      </ResponseField>

      <ResponseField name="threeDSecureAuthentication" type="AuthenticationDetails?">
        {}
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="decisionHandler" type="PrimerResumeDecisionHandler" required>
    <Expandable title="Methods">
      <ResponseField name="handleSuccess()">
        Call `handleSuccess` when you want to show the success screen, or finalize the flow successfully in case you have hidden the success screen.
      </ResponseField>

      <ResponseField name="handleFailure(errorMessage)">
        Call `handleFailure` when you want to show the error screen, or finalize the flow with error in case you have hidden the error screen.
      </ResponseField>

      <ResponseField name="continueWithNewClientToken(clientToken)">
        Call `continueWithNewClientToken` when the payment has entered in a <TxnTag status="PENDING" /> state and a required action client token has been provided.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

### Example

```kotlin KOTLIN theme={"dark"}
class CheckoutActivity : AppCompatActivity() {
  // 👇 Add this
  private val listener = object : PrimerCheckoutListener {
    // 👇 Add this
    override fun onTokenizeSuccess(
      paymentMethodTokenData: PrimerPaymentMethodTokenData,
      decisionHandler: PrimerResumeDecisionHandler
    ) {
      // Create your payment
      val paymentResponse =  //...
      if (paymentResponse.isSuccessful()) {
        // 👇 Call the decisionHandler to show the success screen
        decisionHandler.handleSuccess()
      } else if (paymentResponse.isPending()) {
        // 👇 Call the decisionHandler with the new client token to continue the flow
        decisionHandler.continueWithNewClientToken(paymentResponse.requiredAction.clientToken)
      } else {
        // 👇 Call the decisionHandler to show the error screen with your custom error message
        decisionHandler.handleFailure("Your error message.")
      }
    }
  }
}
```

## onCheckoutResume

This method will be called providing a `resumeToken` so you can [resume the payment](/api-reference/v2.4/api-reference/payments-api/resume-a-payment).

<Warning>
  This method **will** be called when you are using
  `PrimerPaymentHandling.MANUAL`
  [flow](/sdk/android/v2.x.x/common-objects/PrimerSettings) and when the
  payment is in a <TxnTag status="PENDING" /> state.
</Warning>

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

### Parameters

<Expandable title="parameters" defaultOpen>
  <ResponseField name="resumeToken" type="String" required>
    {}
  </ResponseField>

  <ResponseField name="decisionHandler" type="PrimerResumeDecisionHandler" required>
    <Expandable title="Methods">
      <ResponseField name="handleSuccess()">
        Call `handleSuccess` when you want to show the success screen, or finalize the flow successfully in case you have hidden the success screen.
      </ResponseField>

      <ResponseField name="handleFailure(errorMessage)">
        Call `handleFailure` when you want to show the error screen, or finalize the flow with error in case you have hidden the error screen.
      </ResponseField>

      <ResponseField name="continueWithNewClientToken(clientToken)">
        Call `continueWithNewClientToken` when the payment has entered in a <TxnTag status="PENDING" /> state and a required action client token has been provided.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

### Example

```kotlin KOTLIN theme={"dark"}
class CheckoutActivity : AppCompatActivity() {
  // 👇 Add this
  private val listener = object : PrimerCheckoutListener {
    // 👇 Add this
    override fun onResumeSuccess(
      resumeToken: String,
      decisionHandler: PrimerResumeDecisionHandler
    ) {
      // Resume your payment
      val paymentResponse =  //...
      if (paymentResponse.isSuccessful()) {
        // 👇 Call the decisionHandler to show the success screen
        decisionHandler.handleSuccess()
      } else if (paymentResponse.isPending()) {
        // 👇 Call the decisionHandler with the new client token to continue the flow
        decisionHandler.continueWithNewClientToken(paymentResponse.requiredAction.clientToken)
      } else {
        // 👇 Call the decisionHandler to show the error screen with your custom error message
        decisionHandler.handleFailure("Your error message.")
      }
    }
  }
}
```

## onResumePending

This callback is trigger when the payment is not authorized as it's an asynchronous alternative payment method, such as a voucher payment method.

<Warning>
  This method will be called only when using the `PrimerPaymentHandling.MANUAL`
  [flow](/sdk/android/v2.x.x/common-objects/PrimerSettings).
</Warning>

```kotlin KOTLIN theme={"dark"}
fun onResumePending(additionalInfo: PrimerCheckoutAdditionalInfo)
```

### Parameters

<Expandable defaultOpen>
  <ResponseField name="additionalInfo" type="PrimerCheckoutAdditionalInfo" required>
    <Expandable title="direct subclasses" defaultOpen>
      <ResponseField name="XenditCheckoutVoucherAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="couponCode" type="String" required />

          <ResponseField name="retailerName" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="PromptPayCheckoutAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="qrCodeUrl" type="String?" />

          <ResponseField name="qrCodeBase64" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="MultibancoCheckoutAdditionalInfo">
        <Expandable title="Properties" defaultOpen>
          <ResponseField name="expiresAt" type="String" required />

          <ResponseField name="entity" type="String" required />

          <ResponseField name="reference" type="String" required />
        </Expandable>
      </ResponseField>

      <ResponseField name="AchAdditionalInfo">
        <Expandable title="direct subclasses" defaultOpen>
          <ResponseField name="ProvideActivityResultRegistry">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="provide" type="(ActivityResultRegistry) -> Unit" required>
                Provides an ActivityResultRegistry to be used for ACH bank account
                selection.
              </ResponseField>
            </Expandable>
          </ResponseField>

          <ResponseField name="DisplayMandate">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="onAcceptMandate" type="suspend () -> Unit" required>
                Accepts the ACH mandate, completing the payment.
              </ResponseField>

              <ResponseField name="onDeclineMandate" type="suspend () -> Unit" required>
                Declines the ACH mandate, cancelling the payment.
              </ResponseField>
            </Expandable>
          </ResponseField>
        </Expandable>
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

## onBeforeClientSessionUpdated

This method will be called to notify you that the client session will be updated, e.g.
a surcharge needs to be applied when a payment method has been chosen.

```kotlin KOTLIN theme={"dark"}
fun onBeforeClientSessionUpdated()
```

## onClientSessionUpdated

This method will be called to notify you that the client session has been updated, e.g.
surcharge has been applied when a payment method has been chosen.

```kotlin KOTLIN theme={"dark"}
fun onClientSessionUpdated(clientSession: PrimerClientSession)
```

### Parameters

<Expandable defaultOpen>
  <ResponseField name="clientSession" type="PrimerClientSession" required>
    {}
  </ResponseField>
</Expandable>

## onFailed

This method will be called when an error occurs. It may return `PrimerCheckoutData` if the error occurs after the payment creation.

<Warning>
  Please note, that if you `override` this method, you *must* call the `errorHandler` to finalize the flow.
</Warning>

```kotlin KOTLIN theme={"dark"}
fun onFailed(error: PrimerError, checkoutData: PrimerCheckoutData?
```

### Parameters

<Expandable defaultOpen>
  <ResponseField name="error" type="PrimerError" required>
    <Expandable title="Properties">
      <ResponseField name="errorId" type="String" required>
        A unique error identifier.
      </ResponseField>

      <ResponseField name="errorCode" type="String?">
        A unique error code.
      </ResponseField>

      <ResponseField name="description" type="String" required>
        A error description.
      </ResponseField>

      <ResponseField name="recoverySuggestion" type="String?">
        A recovery suggestion for the given error. In case it's present, use it to try
        to recover from error.
      </ResponseField>

      <ResponseField name="diagnosticsId" type="String" required>
        A unique diagnostics id for the given error.
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="checkoutData" type="PrimerCheckoutData?">
    <Expandable title="Properties">
      <ResponseField name="payment" type="Payment" required>
        <Expandable name="Properties" defaultOpen>
          <ResponseField name="id" type="String" required>
            ID of created payment.
          </ResponseField>

          <ResponseField name="orderId" type="String" required>
            Order ID of created payment.
          </ResponseField>
        </Expandable>
      </ResponseField>

      <ResponseField name="additionalInfo" type="PrimerCheckoutAdditionalInfo?">
        <Expandable title="direct subclasses" defaultOpen>
          <ResponseField name="XenditCheckoutVoucherAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="couponCode" type="String" required />

              <ResponseField name="retailerName" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="PromptPayCheckoutAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="qrCodeUrl" type="String?" />

              <ResponseField name="qrCodeBase64" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="MultibancoCheckoutAdditionalInfo">
            <Expandable title="Properties" defaultOpen>
              <ResponseField name="expiresAt" type="String" required />

              <ResponseField name="entity" type="String" required />

              <ResponseField name="reference" type="String" required />
            </Expandable>
          </ResponseField>

          <ResponseField name="AchAdditionalInfo">
            <Expandable title="direct subclasses" defaultOpen>
              <ResponseField name="ProvideActivityResultRegistry">
                <Expandable title="Properties" defaultOpen>
                  <ResponseField name="provide" type="(ActivityResultRegistry) -> Unit" required>
                    Provides an ActivityResultRegistry to be used for ACH bank account
                    selection.
                  </ResponseField>
                </Expandable>
              </ResponseField>

              <ResponseField name="DisplayMandate">
                <Expandable title="Properties" defaultOpen>
                  <ResponseField name="onAcceptMandate" type="suspend () -> Unit" required>
                    Accepts the ACH mandate, completing the payment.
                  </ResponseField>

                  <ResponseField name="onDeclineMandate" type="suspend () -> Unit" required>
                    Declines the ACH mandate, cancelling the payment.
                  </ResponseField>
                </Expandable>
              </ResponseField>
            </Expandable>
          </ResponseField>
        </Expandable>
      </ResponseField>
    </Expandable>
  </ResponseField>

  <ResponseField name="decisionHandler" type="PrimerErrorDecisionHandler?">
    <Expandable title="Methods">
      <ResponseField name="showErrorMessage(errorMessage: String | null)">
        Call with your custom error message.
      </ResponseField>
    </Expandable>
  </ResponseField>
</Expandable>

### Example

```kotlin KOTLIN theme={"dark"}
class CheckoutActivity : AppCompatActivity() {
    // 👇 Add this
    private val listener = object : PrimerCheckoutListener {
        // 👇 Add this
        override fun onFailed(
            error: PrimerError,
            checkoutData: PrimerCheckoutData?,
            errorHandler: PrimerErrorDecisionHandler?
        ) {
            errorHandler?.showErrorMessage(null)
        }
    }
}
```
