Terminal SDK migration guide
Learn how to migrate to the latest version of the Stripe Terminal SDK.
The Stripe Terminal iOS and Android SDKs have been updated with a number of breaking changes in APIs and behavior, some of which require you to update your integration with the Stripe Terminal SDK. To improve consistency between our SDKs and to simplify your application logic and integration, we regularly make changes in major version updates that might affect the way your integration works or behaves. This guide explains the latest changes to help you upgrade your integration.
Note
Building a new Stripe Terminal integration? Visit our Design an integration page to learn how to get started.
Migrate to version 4.0.0
Here are some things you need to know about the 4.0.0 Stripe Terminal iOS and Android SDKs:
- Save cards after payment globally
- Users can now save cards after payment outside of the US by updating the customer consent collection process for saving card details on point-of-sale devices.
- Support for Mail order and telephone order (MOTO) payments on smart readers Preview
- This feature is in preview. To request access, email stripe-terminal-betas@stripe.com.
- Updates to minimum supported iOS platform version
- Enables reader auto-reconnect on unexpected disconnects by default for mobile and Tap to Pay readers, enhancing reader resiliency
- Consolidates reader connection functionality and disconnect callbacks for all reader types
If your application currently uses an Terminal Android SDK version prior to 4.0.0, there are some changes you need to make to upgrade and accept card present payments globally. For a detailed list of the changes from version 3.10.0 to 4.0.0, reference the SDK changelog.
Update your saving cards after PaymentIntents integration
If you save a payment method after a successful in-person PaymentIntent, you need to make the following updates to your integration:
- When creating Terminal PaymentIntents, pass the setup_future_usage parameter, which informs Stripe that you want to make future payments with the same card.
- You also need to pass allow_redisplay as
ALWAYS
orLIMITED
inCollectConfiguration
. PassALWAYS
if you want the customer’s saved card to be presented to them in all future checkout flows, andLIMITED
if it can only be used in the context of the initially scoped use, such as a subscription.
Learn more about saving cards after a payment.
Update your saving cards without payment with SetupIntents integration
To ensure a consistent integration shape between SetupIntents and PaymentIntents, as well as in-person and online transactions, in Terminal
’s collectSetupIntentPaymentMethod
, we removed the customerConsentCollected
parameter previously required on all SetupIntent transactions, and replaced it with the allowRedisplay
parameter.
Learn more about saving directly without charging.
Update your discoverReaders usage
We added a new enum value,
DISCOVERING
, to ConnectionStatus to represent when reader discovery is running. Make sure your integration can handle this new state and provide relevant information to your customers.We improved the handling of multiple simultaneous reader discover operations. Previously, calling Terminal::discoverReaders multiple times would queue the operations, which we learned was undesirable. Now when a new
Terminal::discoverReaders
is called while an existing one is already in progress, the SDK will cancel the ongoing operation and returns a CANCELED_DUE_TO_INTEGRATION_ERROR error. The new discoverReaders operation then starts immediately.Discovering smart and Tap to Pay readers now calls the
Terminal::discoverReaders
completion callback when the operation ends. This change reflects the reality that reader discovery for these reader types isn’t a long-running operation.
Update your reader connection usage
- To ensure a consistent integration pattern across reader discovery and connection, we consolidated all reader connection methods (
connectBluetoothReader
,connectUsbReader
,connectInternetReader
,connectLocalMobileReader
,connectHandoffReader
) into Terminal::connectReader. The specific connection type is still determined by the provided connection configuration. - For mobile readers, the
readerListener
parameter has been removed from the oldconnectBluetoothReader
,connectUsbReader
methods and moved into the respectiveConnectionConfiguration
object, replacingReaderReconnectionListener
. For Tap to Pay readers, theTapToPayConnectionConfiguration
now takes in anTapToPayReaderListener
parameter, replacingReaderReconnectionListener
. - Consistent with other reader types, smart readers’s
InternetConnectionConfiguration
now also expects anInternetReaderListener
to be passed in, which alerts your integration of events including reader disconnects. - For Apps on devices in handoff mode,
HandoffReaderListener
has been removed from the oldconnectHandoffReader
method as a parameter, and moved into theHandoffConnectionConfiguration
object.
Reader Type | Connection Configuration | Reader Listener |
---|---|---|
Mobile Reader | BluetoothConnectionConfiguration | MobileReaderListener |
Smart Reader | InternetConnectionConfiguration | InternetReaderListener |
Tap to Pay | TapToPayConnectionConfiguration | TapToPayReaderListener |
Apps on Devices | HandoffConnectionConfiguration | HandoffReaderListener |
Before
val connectionConfig = ConnectionConfiguration.BluetoothConnectionConfiguration(
) Terminal.getInstance().connectBluetoothReader( selectedReader, connectionConfig, readerListener, object : ReaderCallback { override fun onSuccess(reader: Reader) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } )"{{LOCATION_ID}}"
After
// Implement your MobileReaderListener val mobileReaderListener = yourMobileReaderListener val connectionConfig = ConnectionConfiguration.BluetoothConnectionConfiguration(
, true, // autoReconnectOnUnexpectedDisconnect, default is true, mobileReaderListener ) Terminal.getInstance().connectReader( selectedReader, connectionConfig, object : ReaderCallback { override fun onSuccess(reader: Reader) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } )"{{LOCATION_ID}}"
For more details, refer to our documentation about connecting to a reader.
Auto reconnection is now enabled by default for mobile and Tap to Pay readers
- To increase the resiliency of your Terminal integration with mobile and Tap to Pay readers, we enabled auto reconnection by default when the reader unexpectedly disconnects.
- We recommend displaying notifications in your app to inform the users about the reader status throughout the reconnection process. To handle reader reconnection methods, the
ReaderReconnectionListener
has been inherited by the respective ReaderListeners. UseMobileReaderListener
for mobile readers, andTapToPayReaderListener
for Tap to Pay readers to handle reconnection events. - We removed the
ReaderReconnectionListener
parameter from the connection configurations:LocalMobileConnectionConfiguration
,BluetoothConnectionConfiguration
, andUsbConnectionConfiguration
, and replaced by the appropriateReaderListener
.
If you implemented your own reader reconnection logic and want to maintain this behavior, you can turn off auto reconnection by setting autoReconnectOnUnexpectedDisconnect to false
.
Before
class CustomReaderReconnectionListener : ReaderReconnectionListener { override fun onReaderReconnectStarted(reader: Reader, cancelReconnect: Cancelable, reason: DisconnectReason) { // 1. Notified at the start of a reconnection attempt // Use cancelable to stop reconnection at any time } override fun onReaderReconnectSucceeded(reader: Reader) { // 2. Notified when reader reconnection succeeds // App is now connected } override fun onReaderReconnectFailed(reader: Reader) { // 3. Notified when reader reconnection fails // App is now disconnected } }
After
class CustomMobileReaderListener : MobileReaderListener { // ... override fun onReaderReconnectStarted(reader: Reader, cancelReconnect: Cancelable, reason: DisconnectReason) { // 1. Notified at the start of a reconnection attempt // Use cancelable to stop reconnection at any time } override fun onReaderReconnectSucceeded(reader: Reader) { // 2. Notified when reader reconnection succeeds // App is now connected } override fun onReaderReconnectFailed(reader: Reader) { // 3. Notified when reader reconnection fails // App is now disconnected } // ... }
For more details, refer to our documentation about automatically attempting to reconnect.
Update your reader disconnect handling
- To be informed when a reader disconnects, we consolidated the reader disconnect callbacks for all reader types by removing
TerminalListener::onUnexpectedReaderDisconnect
. Going forward, implementonDisconnect
on any of the following listeners to be informed of their corresponding reader disconnects:InternetReaderListener
,MobileReaderListener
,TapToPayReaderListener
, orHandoffReaderListener
. For mobile readers, theDisconnectReason
can help identify the reason for the disconnection.
When auto-reconnect is enabled, both onDisconnect
and onReaderReconnectFailed
methods are called if the SDK fails to reconnect to the reader and it becomes disconnected.
Before
class ReaderActivity : AppCompatActivity(), TerminalListener { // ... Terminal.getInstance().setTerminalListener(this) // ... override fun onUnexpectedReaderDisconnect(reader: Reader) { // Consider displaying a UI to notify the user and start rediscovering readers } // ... }
After
class ReaderActivity : AppCompatActivity(), MobileReaderListener { // ... override fun onDisconnect(reason: DisconnectReason) { // Consider displaying a UI to notify the user and start rediscovering readers } // ... }
For more details, refer to our documentation about handling disconnects manually.
Update your payment acceptance integration
- You can now cancel
Terminal::confirmPaymentIntent
using the returnedCancelable
object. This is useful for QR code payments, which have an asynchronous confirmation process. Similarly,Terminal::confirmSetupIntent
andTerminal::confirmRefund
are now cancelable as well. - To improve the cancellation flow for PaymentIntents and SetupIntents, calling
Terminal::cancelPaymentIntent
orTerminal::cancelSetupIntent
now also cancels any ongoing payment processing. You no longer need to cancel payment operations such asTerminal::collectPaymentMethod
separately before canceling the PaymentIntent. SetupIntent.
is now nullable to be consistent withid PaymentIntent.
. Although theid id
value is still present, make sure your code safely handles the case whereSetupIntent.
might beid null
to avoid compiler error.
Update error handling
- We moved
TerminalException.
to a standalone enum,TerminalErrorCode TerminalErrorCode
. Make sure to update the import statements and Terminal error code definition to maintain functionality. - We added a new Terminal error code
TerminalErrorCode.
, which can happen when the SDK is out of date, and can’t recognize the error returned by back the smart reader. To remediate this error, update your Terminal SDK.GENERIC_ READER_ ERROR - For Tap to Pay on Android,
Terminal::collectPaymentMethod
andTerminal::collectSetupIntentPaymentMethod
now time out after 60 seconds for Tap to Pay on Android transactions. ATerminalException
is raised with the error codeTerminalErrorCode.
.CARD_ READ_ TIMED_ OUT - For Tap to Pay on Android, when PIN collection is requested for a payment, a
TerminalException
is raised with the error codeFEATURE_
instead ofNOT_ ENABLED_ ON_ ACCOUNT DECLINED_
with anBY_ STRIPE_ API ONLINE_
OR_ OFFLINE_ PIN_ REQUIRED ApiError
.
Update usage for renaming and refactoring
ReaderListener
has been renamed toMobileReaderListener
.- We renamed the
allowedPaymentMethodTypes
parameter topaymentMethodTypes
in thePaymentIntentParameters.
andBuilder SetupIntentParameter.
constructors.Builder - In
ReaderSoftwareUpdate,
we renamedUpdateTimeEstimate
toUpdateDurationEstimate
andestimatedUpdateTime
todurationEstimate
to better represent their intent. - We converted
java.
references to timestamps in milliseconds for the following fields:util. Date ReaderSoftwareUpdate::requiredAt
,OfflineDetails::storedAt
andOfflineSetupIntentDetails::storedAt
. Make sure your application interprets these timestamps correctly. - Fields on the
Location
object are no longer mutable.
Update your Tap to Pay on Android integration
- The Maven coordinates for the Tap to Pay on Android feature have changed to
com.
. Update your build dependencies to point to the new artifact name. The old one will no longer be updated.stripe:stripeterminal-taptopay:4. 0. 0 - We renamed all
LocalMobile
function and field names toTapToPay
. For example,LocalMobileDiscoveryConfiguration
has been renamed toTapToPayDiscoveryConfiguration
. TapToPayConnectionConfiguration
now takes aTapToPayReaderListener
parameter. This listener inherits events from bothReaderReconnectionListener
andReaderDisconnectionListener
, providing a unified mechanism for handling reader events.- We renamed the background application process used for collecting Tap to Pay transactions to use your application’s id, suffixed with
:stripetaptopay
.