# Terminal SDK migration guide

Learn how to migrate to version 6.0.0 of the Stripe Terminal SDK.

See [Design an integration](https://docs.stripe.com/terminal/designing-integration.md) to learn how to get started.

Version 6.0.0 of the Stripe Terminal iOS and Android SDKs includes breaking changes to APIs and behavior. Major versions can change how your integration works, which both keeps the SDKs consistent with each other and simplifies your application logic. This guide explains each change and how to update your integration.

Before you migrate, review the [Terminal SDK versioning and support policy](https://docs.stripe.com/terminal/references/sdk-versioning.md) to understand supported SDK versions, patch support timelines, and end-of-life enforcement.

To migrate from an earlier major version, first work through the [SDK v5 migration guide](https://docs.stripe.com/terminal/references/sdk-v5-migration-guide.md).

## Migrate to version 6.0.0

Here’s what you need to know about the version 6.0.0 Stripe Terminal iOS and Android SDKs:

- Deprecated APIs removed
  - The two-step in-person refund flow, the `Terminal.init` overload without a locale configuration, and the deprecated reader-update simulation APIs are gone. Their replacements shipped in 5.x.
- Dedicated listener for payment interactions that require your app’s UI
  - QR code display and payment method selection move off the reader listener onto `ReaderPaymentInteractionListener` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-reader-payment-interaction-listener/index.html)) (Android) and `ReaderPaymentInteractionDelegate` ([API reference](https://stripe.dev/stripe-terminal-ios/docs/Protocols/SCPReaderPaymentInteractionDelegate.html)) (iOS), which you supply when connecting.
- Object-specific card-present models
  - The card-present details on a `PaymentMethod` are now a separate type from the transaction snapshot on a `Charge`, so each model only exposes fields that apply to it.
- Capture method now defaults to automatic
  - `PaymentIntentParameters` defaults `captureMethod` to automatic-asynchronous instead of manual. Integrations that authorize and capture separately must set manual capture explicitly.
- Cancellation on the reader is reported separately from cancellation through the SDK
  - A dedicated error code distinguishes a customer canceling on the reader from your app canceling programmatically.
- Updates to minimum supported platform versions, from iOS 15.0 to iOS 16.0 and from Android `compileSdk` 34 to 35
- Terminal iOS SDK releases are no longer published to CocoaPods

# Android


If your application currently uses a Terminal Android SDK version earlier than 6.0.0, there are several changes you need to make to upgrade. For a detailed list of the changes from version 5.x to 6.0.0, see the [SDK changelog](https://github.com/stripe/stripe-terminal-android/blob/master/CHANGELOG.md).

## Update the dependency and build configuration

Update every Stripe Terminal artifact to `6.0.0`. A standard integration uses:

```kotlin
dependencies {
    implementation("com.stripe:stripeterminal:6.0.0")
}
```

An integration that includes [Tap to Pay on Android](https://docs.stripe.com/terminal/payments/setup-reader/tap-to-pay.md?platform=android) uses matching versions for all Terminal artifacts:

```kotlin
dependencies {
    implementation("com.stripe:stripeterminal-taptopay:6.0.0")
    implementation("com.stripe:stripeterminal-core:6.0.0")
    // Only if your app uses the Kotlin Coroutines module
    implementation("com.stripe:stripeterminal-ktx:6.0.0")
}
```

SDK 6.0 requires your application to set `compileSdk` to 35 (Android 15) or higher:

```kotlin
android {
    compileSdk = 35
}
```

The SDK is built with Kotlin `2.3.21`. Align the Kotlin toolchain in your application if dependency resolution reports a Kotlin version conflict.

Consumer Proguard rules are narrower in 6.0. If your app relied on the SDK’s previous broad keep rules for classes it accesses through reflection, add the required rules to your app and test a minified release build.

## Update Terminal initialization 

The `Terminal.init` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/core/com.stripe.stripeterminal/-terminal/-companion/init.html)) overload without a `LocaleConfig` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-locale-config/index.html)) is removed. Use the `Terminal.init` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/-companion/init.html)) overload that takes a `localeConfig` and choose the [locale behavior](https://docs.stripe.com/terminal/features/locale-config.md) explicitly.

*Before*

#### Kotlin

```kotlin
Terminal.init(applicationContext, LogLevel.VERBOSE, tokenProvider, terminalListener, offlineListener)
```

*After*

#### Kotlin

```kotlin
Terminal.init(
    context = applicationContext,
    logLevel = LogLevel.VERBOSE,
    tokenProvider = tokenProvider,
    listener = terminalListener,
    offlineListener = offlineListener,
    localeConfig = LocaleConfig.CardLanguagePreferenceIfAvailable,
)
```

Use `LocaleConfig.HardcodedLocale.Builder` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-locale-config/-hardcoded-locale/-builder/index.html)) (for example, `LocaleConfig.HardcodedLocale.Builder("en-US").build()`) when your app requires a fixed locale. `CardLanguagePreferenceIfAvailable` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-locale-config/-card-language-preference-if-available/index.html)) uses the cardholder’s language when it’s available, falling back to the device locale. Base your application logic on error codes instead of localized error message text.

## Update mobile reader payment interactions 

These methods are removed from `MobileReaderListener` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-mobile-reader-listener/index.html)):

- `onQrCodeDisplayRequired` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.callable/-mobile-reader-listener/on-qr-code-display-required.html))
- `onPaymentMethodSelectionRequired` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.callable/-mobile-reader-listener/on-payment-method-selection-required.html))

Implement `ReaderPaymentInteractionListener` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-reader-payment-interaction-listener/index.html)) instead, pass it as `readerPaymentInteractionListener` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-bluetooth-connection-configuration/reader-payment-interaction-listener.html)) in the reader connection configuration, and handle the concrete `PaymentInteraction` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-interaction/index.html)) type that `onInteractionRequired` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-reader-payment-interaction-listener/on-interaction-required.html)) receives: `PaymentInteraction.QrCodeDisplay` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-interaction/-qr-code-display/index.html)) or `PaymentInteraction.PaymentMethodSelection` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-interaction/-payment-method-selection/index.html)).

*Before*

#### Kotlin

```kotlin
class MyMobileReaderListener : MobileReaderListener {
    override fun onQrCodeDisplayRequired(
        paymentIntent: PaymentIntent,
        qrData: QrCodeDisplayData,
        callback: QrCodeDisplayCallback,
    ) {
        showQrCode(qrData) { callback.onSuccess() }
    }

    override fun onPaymentMethodSelectionRequired(
        paymentIntent: PaymentIntent,
        availablePaymentOptions: List<PaymentOption>,
        callback: PaymentMethodSelectionCallback,
    ) {
        showPaymentMethodOptions(availablePaymentOptions) { callback.onSuccess(it) }
    }
}

val connectionConfiguration = ConnectionConfiguration.BluetoothConnectionConfiguration(
    locationId = locationId,
    bluetoothReaderListener = mobileReaderListener,
)
```

*After*

#### Kotlin

```kotlin
class PaymentInteractionListener : ReaderPaymentInteractionListener {
    override fun onInteractionRequired(interaction: PaymentInteraction) {
        when (interaction) {
            is PaymentInteraction.QrCodeDisplay -> {
                showQrCode(interaction.qrData) {
                    interaction.callback.onSuccess()
                }
            }

            is PaymentInteraction.PaymentMethodSelection -> {
                showPaymentMethodOptions(interaction.availableOptions) { option ->
                    interaction.callback.onSuccess(option)
                }
            }
        }
    }
}

val connectionConfiguration = ConnectionConfiguration.BluetoothConnectionConfiguration(
    locationId = locationId,
    bluetoothReaderListener = mobileReaderListener,
    readerPaymentInteractionListener = PaymentInteractionListener(),
)
```

You can pass the same listener to `UsbConnectionConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-usb-connection-configuration/index.html)) and `ExternalUsbChannelConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-external-usb-channel-configuration/index.html)). Call the interaction callback’s `onSuccess` after the corresponding UI action succeeds. Call `onFailure` (`QrCodeDisplayCallback` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-qr-code-display-callback/on-failure.html)), `PaymentMethodSelectionCallback` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-payment-method-selection-callback/on-failure.html))) if you can’t display the UI or the customer cancels.

> #### Configure a payment interaction listener
> 
> If an interaction is required and you provide no listener, the transaction fails.

## Update refund APIs

Refund parameter types are renamed, and the deprecated two-step refund methods are removed.

### Rename RefundParameters 

`RefundParameters` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-refund-parameters/index.html)) and its builders are renamed to `ProcessRefundParameters` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-process-refund-parameters/index.html)). The `processRefund` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/process-refund.html)) behavior is unchanged. Update your imports and type references.

*Before*

#### Kotlin

```kotlin
val parameters = RefundParameters.ByChargeId(
    id = chargeId,
    amount = 1000,
    currency = "cad",
).build()
```

*After*

#### Kotlin

```kotlin
val parameters = ProcessRefundParameters.ByChargeId(
    id = chargeId,
    amount = 1000,
    currency = "cad",
).build()

Terminal.getInstance().processRefund(refundParams = parameters, callback = callback)
```

### Replace the removed two-step refund flow 

These deprecated in-person refund methods are removed:

- `Terminal.collectRefundPaymentMethod(...)` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/core/com.stripe.stripeterminal/-terminal/collect-refund-payment-method.html))
- the legacy `Terminal.confirmRefund(RefundCallback)` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/core/com.stripe.stripeterminal/-terminal/confirm-refund.html))

For `interac_present` transactions, use `Terminal.processRefund(...)` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/process-refund.html)), which performs the complete in-person refund flow.

> #### Confirm refunds without collecting a payment method
> 
> The 6.0 `Terminal.confirmRefund(ConfirmRefundParameters, RefundCallback)` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/confirm-refund.html)) method, which takes `ConfirmRefundParameters` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-confirm-refund-parameters/index.html)), isn’t a replacement for the removed overload. It belongs to a separate flow (Private preview) that creates a refund for a PaymentIntent without collecting a payment method. To request access, contact [Stripe Support](https://support.stripe.com/).

### Treat Refund.id as nullable

`Refund.id` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-refund/id.html)) is now nullable. Handle a missing ID in Kotlin, and a `null` value in Java, before you store, display, or dereference it.

#### Kotlin

```kotlin
val refundId = refund.id ?: return
saveRefundId(refundId)
```

## Update PaymentIntent and SetupAttempt models

Several `PaymentIntent`, `SetupAttempt`, and card-present model types and properties are removed, renamed, or split.

### Read the latest charge instead of the charges list

`PaymentIntent.getCharges()` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-payment-intent/get-charges.html)) is removed. Use the most recent charge or its ID.

#### Kotlin

```kotlin
val charge: Charge? = paymentIntent.latestCharge
val chargeId: String? = paymentIntent.latestChargeId
```

`latestCharge` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-intent/latest-charge.html)) is populated when the charge is expanded. Use `latestChargeId` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-intent/latest-charge-id.html)) when only the ID is available.

`PaymentIntent.invoice` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-payment-intent/invoice.html)) is also removed. Retrieve the PaymentIntent’s invoice relationship from your server using the Stripe API.

### Update SetupAttempt type names

The setup attempt models are renamed to reflect the Stripe API object they describe.

| 5.x                                                                                                                                                                                                       | 6.0                                                                                                                                                                                                  |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SetupIntentPaymentMethodDetails` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-setup-intent-payment-method-details/index.html)) | `SetupAttemptPaymentMethodDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-setup-attempt-payment-method-details/index.html)) |
| `SetupIntentCardPresentDetails` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-setup-intent-card-present-details/index.html))     | `SetupAttemptCardPresentDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-setup-attempt-card-present-details/index.html))     |

Update your imports, type checks, and serialized model references. `SetupAttempt.paymentMethodDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-setup-attempt/payment-method-details.html)) now returns `SetupAttemptPaymentMethodDetails`, and its `type` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-setup-attempt-payment-method-details/type.html)) property is public.

### Move allowRedisplay into the setup intent collection configuration 

For `collectSetupIntentPaymentMethod` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/collect-setup-intent-payment-method.html)) and `processSetupIntent` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/process-setup-intent.html)), provide `allowRedisplay` when you build `CollectSetupIntentConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-setup-intent-configuration/index.html)) with `CollectSetupIntentConfiguration.Builder` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-setup-intent-configuration/-builder/index.html)) instead of as a separate method argument.

*Before*

#### Kotlin

```kotlin
val collectConfig = CollectSetupIntentConfiguration.Builder().build()

Terminal.getInstance().processSetupIntent(
    intent,
    AllowRedisplay.ALWAYS,
    collectConfig,
    callback,
)
```

*After*

#### Kotlin

```kotlin
val collectConfig = CollectSetupIntentConfiguration.Builder(
    allowRedisplay = AllowRedisplay.ALWAYS,
).build()

Terminal.getInstance().processSetupIntent(
    intent,
    collectConfig,
    callback,
)
```

Pass the same configuration to `collectSetupIntentPaymentMethod` if you collect and confirm the SetupIntent in separate steps. Payment collection is unchanged: `allowRedisplay` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/allow-redisplay.html)) remains a property of `CollectPaymentIntentConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-collect-payment-intent-configuration/index.html)).

### Split CardPresentDetails 

The top-level `CardPresentDetails` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-card-present-details/index.html)) type is removed. Use the type associated with the object that owns the card-present data.

| Parent object                                                                                                                                                                                                                                                                                                                                                                                                        | 6.0 type                                                                                                                                                                              | Use it for                                                                                                                                                                                                                                                                                                                                                                                              |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PaymentMethod.cardPresentDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/card-present-details.html)) or `interacPresentDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/interac-present-details.html))                               | `PaymentMethod.CardPresent` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/-card-present/index.html)) | Reusable payment method details, including `networks` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/-card-present/networks.html)) and `brandProduct` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/-card-present/brand-product.html)) |
| `Charge.paymentMethodDetails.cardPresentDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method-details/card-present-details.html)) or `interacPresentDetails` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method-details/interac-present-details.html)) | `Charge.CardPresent` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-charge/-card-present/index.html))                | Transaction snapshot, including receipt and authorization lifecycle details                                                                                                                                                                                                                                                                                                                             |

`PaymentMethod.CardPresent.expMonth` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/-card-present/exp-month.html)) and `expYear` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-method/-card-present/exp-year.html)) are nullable. Charge-only fields aren’t exposed on `PaymentMethod.CardPresent`, and `networks` isn’t exposed on `Charge.CardPresent`.

*Before*

#### Kotlin

```kotlin
val card: CardPresentDetails? = paymentMethod?.cardPresentDetails ?: paymentMethod?.interacPresentDetails
```

*After*

#### Kotlin

```kotlin
val card: PaymentMethod.CardPresent? = paymentMethod?.cardPresentDetails ?: paymentMethod?.interacPresentDetails
val expirationMonth: Int? = card?.expMonth
```

For [MOTO](https://docs.stripe.com/terminal/features/mail-telephone-orders/overview.md) transactions, `paymentMethodDetails.cardDetails.authorizationCode` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-card-details/authorization-code.html)) is now available. Smart reader integrations need reader software `2.45` or later to receive it.

## Update error and capture handling

SDK 6.0 narrows reader support errors, adds and replaces error codes, and changes the default capture method.

### Reader support errors

`ReaderSupportResult.NotSupported.error` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-reader-support-result/-not-supported/error.html)) is now always a `TerminalException` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-exception/index.html)). Remove casts or branches for other exception types.

### Handle cancellation on the reader separately 

`TerminalErrorCode.CANCELED_BY_READER` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-c-a-n-c-e-l-e-d_-b-y_-r-e-a-d-e-r/index.html)) is returned when the payment is canceled using the reader’s UI or physical cancel button. Programmatic cancellation through the SDK continues to return `TerminalErrorCode.CANCELED` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-c-a-n-c-e-l-e-d/index.html)).

#### Kotlin

```kotlin
when (exception.errorCode) {
    TerminalErrorCode.CANCELED -> onSdkCancellation()
    TerminalErrorCode.CANCELED_BY_READER -> onReaderCancellation()
    else -> onTerminalError(exception)
}
```

### Replace the printer battery error code

Replace `TerminalErrorCode.PRINTER_LOW_BATTERY` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-p-r-i-n-t-e-r_-l-o-w_-b-a-t-t-e-r-y/index.html)) with `TerminalErrorCode.READER_BATTERY_LOW` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-r-e-a-d-e-r_-b-a-t-t-e-r-y_-l-o-w/index.html)). `READER_BATTERY_LOW` covers operations such as [printing](https://docs.stripe.com/terminal/features/print-content.md) when the reader is still connected but its battery is too low to complete the operation.

### Set the capture method explicitly 

`PaymentIntentParameters.Builder` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-intent-parameters/-builder/index.html)) now defaults `captureMethod` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-payment-intent-parameters/-builder/set-capture-method.html)) to `CaptureMethod.AutomaticAsync` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-capture-method/-companion/-automatic-async.html)) instead of `CaptureMethod.Manual` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-capture-method/-companion/-manual.html)). If your integration requires separate authorization and capture—including [on-receipt tipping](https://docs.stripe.com/terminal/features/collecting-tips/on-receipt.md), [incremental authorizations](https://docs.stripe.com/terminal/features/incremental-authorizations.md), or [extended authorizations](https://docs.stripe.com/terminal/features/extended-authorizations.md)—set the capture method explicitly.

*Before*

#### Kotlin

```kotlin
// captureMethod defaulted to CaptureMethod.Manual
val parameters = PaymentIntentParameters.Builder()
    .setAmount(1000)
    .setCurrency("cad")
    .build()
```

*After*

#### Kotlin

```kotlin
val parameters = PaymentIntentParameters.Builder()
    .setAmount(1000)
    .setCurrency("cad")
    .setCaptureMethod(CaptureMethod.Manual)
    .build()
```

Review any code that relied on the previous default, even if it doesn’t reference `captureMethod` directly.

## Update your Tap to Pay on Android integration

Tap to Pay on Android requires an additional manifest permission and uses renamed connection and UX configuration APIs.

### Add the MODIFY_AUDIO_SETTINGS permission 

Tap to Pay now requires `MODIFY_AUDIO_SETTINGS` so payment audio isn’t muted. Verify that the permission is present in the merged manifest. You can declare it explicitly in your app:

```xml
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
```

This is a normal manifest permission and doesn’t require a runtime permission prompt.

### Update the connection configuration 

The `TapToPayConnectionConfiguration` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-connection-configuration/-tap-to-pay-connection-configuration/-tap-to-pay-connection-configuration.html)) constructor that accepted a location ID is removed. Construct `TapToPayConnectionConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-tap-to-pay-connection-configuration/index.html)) with a `TapUseCase` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-use-case/index.html)) instead.

*Before*

#### Kotlin

```kotlin
ConnectionConfiguration.TapToPayConnectionConfiguration(
    locationId,
    autoReconnectOnUnexpectedDisconnect,
    tapToPayReaderListener,
)
```

*After*

#### Kotlin

```kotlin
ConnectionConfiguration.TapToPayConnectionConfiguration(
    useCase = TapUseCase.Pay(locationId),
    tapToPayReaderListener = tapToPayReaderListener,
)
```

Use `TapUseCase.Pay` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-use-case/-pay/index.html)) to collect payments, or `TapUseCase.Verify()` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-use-case/-verify/index.html)) for a verification-only flow.

### Update the UX configuration 

The `TapToPayUxConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/index.html)) API is renamed and is no longer `Parcelable`.

| 5.x                                                                                                                                                                                                           | 6.0                                                                                                                                                                                                 |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TapToPayUxConfiguration.DarkMode` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-dark-mode/index.html)) | `TapToPayUxConfiguration.Theme` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-theme/index.html))     |
| `TapToPayUxConfiguration.colors`                                                                                                                                                                              | `TapToPayUxConfiguration.colorScheme`                                                                                                                                                               |
| `TapToPayUxConfiguration.darkMode`                                                                                                                                                                            | `TapToPayUxConfiguration.theme`                                                                                                                                                                     |
| `Builder.colors(...)` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-builder/colors.html))               | `Builder.colorScheme(...)` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-builder/color-scheme.html)) |
| `Builder.darkMode(...)` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-builder/dark-mode.html))          | `Builder.theme(...)` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-builder/theme.html))              |

The default theme changed from `DarkMode.LIGHT` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-dark-mode/-l-i-g-h-t/index.html)) to `Theme.SYSTEM` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-ux-configuration/-theme/-s-y-s-t-e-m/index.html)). Apply the configuration with `Terminal.setTapToPayUxConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/set-tap-to-pay-ux-configuration.html)).

#### Kotlin

```kotlin
val uxConfiguration = TapToPayUxConfiguration.Builder()
    .colorScheme(colorScheme)
    .theme(TapToPayUxConfiguration.Theme.SYSTEM)
    .build()

Terminal.getInstance().setTapToPayUxConfiguration(uxConfiguration)
```

If your app stores this configuration in an `Intent`, `Bundle`, or saved state, update that code. `TapToPayUxConfiguration` and its nested types now implement `Serializable` instead of `Parcelable`. Persist the values your app needs and rebuild the configuration instead of relying on `Parcelable`.

### Handle device update notifications and attestation errors

Implement `TapToPayReaderListener.onUpdateRequirementsAvailable` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-tap-to-pay-reader-listener/on-update-requirements-available.html)) if your app should warn users about upcoming Android OS, security patch, or SDK update requirements. Each `TapToPayUpdateRequirement` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-tap-to-pay-update-requirement/index.html)) carries the earliest version the device should upgrade to, along with the timestamp at which enforcement begins. The callback is advisory: it doesn’t install an update or block payments.

An expired session token that causes an attestation failure during `connectReader` ([API reference](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/connect-reader.html)) now returns `TerminalErrorCode.SESSION_EXPIRED` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-s-e-s-s-i-o-n_-e-x-p-i-r-e-d/index.html)) instead of `TerminalErrorCode.STRIPE_API_CONNECTION_ERROR` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-terminal-error-code/-s-t-r-i-p-e_-a-p-i_-c-o-n-n-e-c-t-i-o-n_-e-r-r-o-r/index.html)). Update your error handling and the user-facing recovery path accordingly.

## Update reader update simulations 

`SimulatorConfiguration.update` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-simulator-configuration/update.html)) and `SimulateReaderUpdate` ([5.x API reference](https://stripe.dev/stripe-terminal-android/v5/external/com.stripe.stripeterminal.external.models/-simulate-reader-update/index.html)) are removed. To simulate reader software updates, set a `TestReaderUpdate` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-test-reader-update/index.html)) as `testReaderUpdate` on the relevant `BluetoothConnectionConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-bluetooth-connection-configuration/test-reader-update.html)) or `UsbConnectionConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-connection-configuration/-usb-connection-configuration/test-reader-update.html)) in test mode. `SimulatorConfiguration` ([API reference](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.models/-simulator-configuration/index.html)) continues to configure simulated cards, tips, input collection, and offline behavior.

*Before*

#### Kotlin

```kotlin
Terminal.getInstance().simulatorConfiguration = SimulatorConfiguration(
    update = SimulateReaderUpdate.LOW_BATTERY,
)
```

*After*

#### Kotlin

```kotlin
ConnectionConfiguration.UsbConnectionConfiguration(
    locationId = locationId,
    usbReaderListener = mobileReaderListener,
    testReaderUpdate = TestReaderUpdate.lowBattery(),
)
```

> #### Use simulated reader updates in test mode only
> 
> `testReaderUpdate` is for test mode connections only. Don’t pass it when connecting to a live mode reader.

## Validation checklist

Before you ship the migration, verify that:

- Your app builds with `compileSdk = 35` or higher, and all Terminal artifacts use `6.0.0`.
- `Terminal.init` supplies a `LocaleConfig`.
- Every mobile reader connection that can require QR or payment method UI supplies a `ReaderPaymentInteractionListener`.
- Refund, setup intent, charge, invoice, card-present, and nullable ID call sites compile and behave as you intend.
- Payment flows that require manual capture set `CaptureMethod.Manual` explicitly.
- Tap to Pay works with the manifest permission, the `TapUseCase` configuration, the updated UX names, and rebuilt saved state.
- Reader cancellation, low battery, session expiration, and reader update paths are covered.
- Minified release builds pass with the narrower consumer Proguard rules.
- Offline mode upgrades are tested with representative existing app data, including any stored offline payments.

