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 iOS SDK version prior to 4.0.0, there are a few changes you need to make to upgrade and accept card present payments globally. For a detailed list of the changes from version 3.9.1 to 4.0.0, please reference the SDK changelog.
Update your minimum supported version to iOS 14 or higher
We regularly update the minimum supported version of our SDKs to streamline our developer support efforts.
Existing 3.X versions of the Terminal iOS SDK will continue to support devices running iOS 13 and higher.
Update 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
inSCPCollectConfiguration
. 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 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 SCPTerminal
’s collectSetupIntentPaymentMethod
, we removed the customerConsentCollected
parameter that was 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 SCPConnectionStatus 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 discoverReaders multiple times would queue the operations. Now, when a new discoverReaders is called while an existing one is already in progress, the SDK cancels the ongoing operation and returns a SCPErrorCanceledDueToIntegrationError error. The new discoverReaders operation then starts immediately.
Discovering smart and Tap to Pay readers now calls the
discoverReaders
completion block 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 previous reader connection methods (
connectBluetoothReader
,connectInternetReader
,connectLocalMobileReader
) into connectReader. The exact connection type is still determined by the passed in connection configuration.For mobile readers and Tap to Pay readers, the
ReaderDelegate
parameter has been removed from theconnectReader
method and instead moved into theconnectionConfig
, replacingSCPReconnectionDelegate
. Consistent with other reader types, smart readersInternetConnectionConfiguration
now also expects anInternetReaderDelegate
to be passed in, which will alert your integration of events, including when a reader disconnects.
Reader Type | Connection Configuration | Reader Delegate |
---|---|---|
Mobile Reader | SCPBluetoothConnectionConfiguration | SCPMobileReaderDelegate |
Smart Reader | SCPInternetConnectionConfiguration | SCPInternetReaderDelegate |
Tap to Pay | SCPTapToPayConnectionConfiguration | SCPTapToPayReaderDelegate |
Before
// Call `connectBluetoothReader` with the selected reader and a connection config // to register to a location as set by your app. let connectionConfig: BluetoothConnectionConfiguration do { connectionConfig = try BluetoothConnectionConfigurationBuilder(locationId:
).build() } catch { // Handle the error building the connection configuration return } Terminal.shared.connectBluetoothReader(selectedReader, delegate: readerDelegate, connectionConfig: connectionConfig) { reader, error in if let reader = reader { print("Successfully connected to reader: \(reader)") } else if let error = error { print("connectBluetoothReader failed: \(error)") } }"{{LOCATION_ID}}"
After
// Call `connectReader` with the selected reader and a connection config // to register to a location as set by your app. let connectionConfig: BluetoothConnectionConfiguration do { connectionConfig = try BluetoothConnectionConfigurationBuilder(delegate: yourMobileReaderDelegate, locationId:
) .build() } catch { // Handle the error building the connection configuration return } Terminal.shared.connectReader(selectedReader, connectionConfig: connectionConfig) { reader, error in if let reader = reader { print("Successfully connected to reader: \(reader)") } else if let error = error { print("connectReader failed: \(error)") } }"{{LOCATION_ID}}"
For more details, refer 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 a 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, we removed the
SCPReconnectionDelegate
. Its responsibilities have been integrated into the respective ReaderDelegates. UseMobileReaderDelegate
for mobile readers, andTapToPayReaderDelegate
for Tap to Pay readers to handle reconnection events.If you implemented your own reader reconnection logic and want to maintain this behavior, you can turn off auto reconnection by setting setAutoReconnectOnUnexpectedDisconnect to
false
.
Before
import StripeTerminal extension ReaderViewController: ReconnectionDelegate { // MARK: ReconnectionDelegate func terminal(_ terminal: Terminal, didStartReaderReconnect cancelable: Cancelable) { // 1. Notified at the start of a reconnection attempt // Use cancelable to stop reconnection at any time } func terminalDidSucceedReaderReconnect(_ terminal: Terminal) { // 2. Notified when reader reconnection succeeds // App is now connected } func terminalDidFailReaderReconnect(_ terminal: Terminal) { // 3. Notified when reader reconnection fails // App is now disconnected } }
After
import StripeTerminal extension ReaderViewController: MobileReaderDelegate { // MARK: MobileReaderDelegate func reader(_ reader: Reader, didStartReconnect cancelable: Cancelable, disconnectReason: DisconnectReason) { // 1. Notified at the start of a reconnection attempt // Use cancelable to stop reconnection at any time } func readerDidSucceedReconnect(_ reader: Reader) { // 2. Notified when reader reconnection succeeds // App is now connected } func readerDidFailReconnect(_ reader: Reader) { // 3. Notified when reader reconnection fails // App is now disconnected } }
For more details and code snippets, 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
terminal:didReportUnexpectedReaderDisconnect:
from theSCPTerminalDelegate
. Usereader:didDisconnect:
as part of the ReaderDelegates to be notified when a reader disconnects. For mobile readers, the SCPDisconnectReason can help identify the reason for the disconnection.
With auto-reconnection enabled, both -readerDidFailReconnect:
and reader:didDisconnect:
methods are called if the SDK fails to reconnect to the reader and it becomes disconnected.
Before
import StripeTerminal class ReaderViewController: UIViewController, TerminalDelegate { override func viewDidLoad() { super.viewDidLoad() Terminal.shared.delegate = self } // ... // MARK: TerminalDelegate func terminal(_ terminal: Terminal, didReportUnexpectedReaderDisconnect reader: Reader) { // Consider displaying a UI to notify the user and start rediscovering readers } }
After
import StripeTerminal class ReaderViewController: UIViewController, MobileReaderDelegate { override func viewDidLoad() { super.viewDidLoad() // Set the reader delegate when connecting to a reader } // ... func reader(_ reader: Reader, didDisconnect 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
confirmPaymentIntent
using the returnedCancelable
object. This is useful for QR code payments, which have an asynchronous confirmation process. Similarly,confirmSetupIntent
andconfirmRefund
are now cancelable as well. - We improved type safety and consistency between the mobile SDKs by updating the way
paymentMethodTypes
are specified inSCPPaymentIntentParameters
andSCPSetupIntentParameters
. Previously, this parameter was represented as an array of strings (for example, [“card_present”]). It now uses enum values fromSCPPaymentMethodType
. - To improve the cancelation 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 as.
separately before canceling the PaymentIntent.collectPaymentMethod SCPSetupIntent.
is now nullable to be consistent withstripeId SCPPaymentIntent.
. Although thestripeId stripeId
value will continue to exist, make sure your code safely handles the case whereSCPSetupIntent.
might bestripeId null
to avoid compiler errors.
Update usage for renaming and deprecation
BluetoothReaderDelegate
has been renamed toMobileReaderDelegate
.- In
SCPReaderSoftwareUpdate,
we renamedSCPUpdateTimeEstimate
toSCPUpdateDurationEstimate
andestimatedUpdateTime
todurationEstimate
to better represent their intent. - In
SCPOfflineDetails
, which represents payment details available when a payment is created or confirmed while offline, we renamed the time that the offline payment happened fromcollectedAt
tostoredAt
, aligning with the naming conventions in the Terminal Android SDK. - We renamed “local mobile” and “apple built in” to “Tap To Pay” in all SDK function names and error codes.