Build and test your app
Learn how to build and test your app using a DevKit.
Use your SmartPOS DevKit device to test and iterate your application without going through the deployment, app review, or signing process.
If you need a DevKit device, you can order up to five per user from the Readers section in your Dashboard.
Verifone reader support
Verifone the related setting and the related setting are generally available in the United States. Verifone V660p and the related setting are in public preview for the United States and Canada, with V660p, the related setting, and the related setting also in public preview for Canada, Belgium, Italy, the Netherlands, New Zealand, Norway, Spain, and Sweden. V660p, the related setting, and the related setting are in private preview for Ireland and the United Kingdom, France, Singapore (V660p, the related setting), and Australia.
To order a Verifone reader or join a preview, you must contact the Sales team.
Set up the DevKit
Before you can use your DevKit for app development, you must do the following:
- Follow the on-screen prompts to connect to a network.
- Register the device to your Stripe account.
- Install all available updates.
After the initial setup, you can register your DevKit to another account or location at any time. To do so, connect the DevKit to the internet and follow the steps to register a reader.
While similar to production devices, DevKit devices:
- Can only operate in sandboxes .
- Ship with developer options and Android Debug Bridge ( adb ) enabled by default.
- Display an on-screen watermark to indicate that the device is only used for testing. The watermark moves around the screen while the device is in use so that you can see all parts of the screen.
The Terminal API supports targeting registered DevKit devices.
Develop your app for Stripe devices
Use the following steps to develop your app for Stripe Android devices, including setting up the app and handing it off to the Stripe Reader app.
Set up the app Client-side
First, set up your integration for in-person payments. Then, follow the guidance below for Apps on Devices integrations.
Add dependencies
Add the following dependencies to your project’s Gradle build script. Apps on Devices integrations require Terminal Android SDK version 2.22.0 or later. We recommend that you integrate with the latest version.
build.gradle.kts
Select a language
Kotlin
Groovy
No results
dependencies {
implementation("com.stripe:stripeterminal-core:5.8.1")
implementation("com.stripe:stripeterminal-appsondevices:5.8.1")
}
Make sure that you aren’t using any other Stripe Terminal SDK dependencies. For example, if you previously integrated the Terminal Android SDK, don’t use the top-level com.stripe:stripeterminal dependency (for example, com.stripe:stripeterminal:5.8.1).
See an example of including dependencies in your app’s build script.
Configure your application
To inform the Stripe SDK of lifecycle events, add a TerminalApplicationDelegate.onCreate() call to the onCreate() method for your application subclass.
MyApplication.kt
Select a language
Kotlin
Java
No results
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
TerminalApplicationDelegate.onCreate(this)
}
}
In your app manifest, specify the name of your Application subclass with the android:name attribute.
Warning
To ensure your Application supports devices running Android 15, set the targetSdkVersion to 24 or later.
AndroidManifest.xml
Learn more about setting up your integration or see the Apps on Devices sample app GitHub repository for an example of configuring the Application subclass.
Build the app Client-side
Follow the guidance below for Apps on Devices integrations.
Discover and connect a reader
Note
In version 5.0.0 of the Android SDK, you can use the easyConnect method to combine reader discovery and connection into a single API call to simplify integration. See the SDK migration guide for details.
You must register a new Stripe device to your account as a new Reader object. Use the pairing code provided in the device’s admin settings to create the Reader object. Your app uses the Stripe Terminal Android SDK to discover and connect to your device:
- Your app runs on your registered device.
- Your app discovers the reader by calling discoverReaders with AppsOnDevicesDiscoveryConfiguration .
- Your app connects to the reader by using connectReader .
The following example shows how to discover and connect to a Stripe reader using handoff mode in an Android app:
DiscoverReadersActivity.kt
Select a language
Kotlin
Java
No results
private fun discoverReaders() {
Terminal.getInstance().discoverReaders(
config = AppsOnDevicesDiscoveryConfiguration(),
discoveryListener = object : DiscoveryListener {
override fun onUpdateDiscoveredReaders(readers: List<Reader>) {
// In Apps on Devices discovery, the list will
// contain a single reader. Connect to
// the reader after it is discovered.
readers.firstOrNull()?.let { reader ->
connectReader(reader)
}
}
},
callback = object : Callback {
override fun onSuccess() {
// Handle successfully discovering readers
}
override fun onFailure(e: TerminalException) {
// Handle exception while discovering readers
}
}
)
}
private fun connectReader(reader: Reader) {
Terminal.getInstance().connectReader(
reader,
AppsOnDevicesConnectionConfiguration(
object : AppsOnDevicesReaderListener {
override fun onDisconnect(reason: DisconnectReason) {
// Optionally get notified about reader disconnects (for example, reader was rebooted)
}
override fun onReportReaderEvent(event: ReaderEvent) {
// Optionally get notified about reader events (for example, a card was inserted)
}
}
),
object : ReaderCallback {
override fun onSuccess(reader: Reader) {
// Handle successfully connecting to the reader
}
override fun onFailure(e: TerminalException) {
// Handle exception when connecting to the reader
}
}
)
}
Collect payments
After you connect to the reader using handoff mode, you can start collecting payments.
The Stripe Reader app handles payment collection and other payment operations, such as saving payment details. When initiating a payment operation, the Stripe Reader app becomes the primary and launches in full screen. Then, the Stripe Reader app guides the customer through the flow and returns control to your app after completion (success or failure) or customer cancellation. When control returns to your app, the Stripe Reader app continues to run in the background.
See an example of collecting payment in an Apps on Devices app.
Collect payments while offline
Apps on Devices supports offline payment collection.
Customize app transitions Client-side
When a payment operation starts, the Stripe Reader app comes to the foreground and your app transitions to the background. Unless specified, the transition uses the Android system default animation, which slides from the right.
Note
Custom transition animations require reader software version 2.42 or later.
You can customize the transition by passing an appTransitionAnimation parameter to AppsOnDevicesConnectionConfiguration when connecting to the reader.
Use a preset animation
The Terminal SDK bundles preset animations that require no additional setup. Use AppTransitionAnimation.Preset with an AppTransitionPreset:
DiscoverReadersActivity.kt
Select a language
Kotlin
Java
No results
private fun connectReader(reader: Reader) {
val config = AppsOnDevicesConnectionConfiguration(
appsOnDevicesListener = object : AppsOnDevicesReaderListener {
override fun onDisconnect(reason: DisconnectReason) {}
override fun onReportReaderEvent(event: ReaderEvent) {}
},
appTransitionAnimation = AppTransitionAnimation.Preset(AppTransitionPreset.SLIDE_FROM_BOTTOM)
)
Terminal.getInstance().connectReader(
reader,
config,
object : ReaderCallback {
override fun onSuccess(reader: Reader) {
// Handle successfully connecting to the reader
}
override fun onFailure(e: TerminalException) {
// Handle exception when connecting to the reader
}
}
)
}
If you use the the related setting preset, the Stripe Reader app slides up from the bottom of the screen.
Use a custom animation
You can define custom Android animation resources in the res/anim/ directory for your app. Then, pass the resource IDs to AppTransitionAnimation.Custom. The enterAnim controls how the Stripe Reader app enters the screen. The exitAnim controls how your app exits the screen.
DiscoverReadersActivity.kt
Select a language
Kotlin
Java
No results
val config = AppsOnDevicesConnectionConfiguration(
appsOnDevicesListener = object : AppsOnDevicesReaderListener {
override fun onDisconnect(reason: DisconnectReason) {}
override fun onReportReaderEvent(event: ReaderEvent) {}
},
appTransitionAnimation = AppTransitionAnimation.Custom(
enterAnim = R.anim.slide_in_up,
exitAnim = R.anim.slide_out_down
)
)
Disable the transition animation
You can disable the transition animation by passing AppTransitionAnimation.Custom.the related setting for both parameters. To disable the animation in only one direction, pass the related setting for either enterAnim or exitAnim.
DiscoverReadersActivity.kt
Select a language
Kotlin
Java
No results
val config = AppsOnDevicesConnectionConfiguration(
appsOnDevicesListener = listener,
appTransitionAnimation = AppTransitionAnimation.Custom(
enterAnim = AppTransitionAnimation.Custom.NO_ANIMATION,
exitAnim = AppTransitionAnimation.Custom.NO_ANIMATION
)
)
Note
If the animation resource IDs are invalid, the SDK throws an exception during connection in debug builds. In release builds, the SDK uses the system default transition.
Customize transitions when opening device settings
Your app can open the reader’s settings screen to let businesses configure Wi-Fi, check for software updates, or adjust device preferences. This uses the stripe://settings/ deeplink, which triggers a standard Android activity transition.
The appTransitionAnimation parameter configured during reader connection doesn’t apply to these transitions. It only controls animations the SDK triggers during payment operations. To create a consistent transition when navigating to device settings, use ActivityOptions.makeCustomAnimation with the SDK’s built-in animation presets.
The Terminal SDK includes animation resource files for each preset. You can access the enter and exit animation resource IDs from AppTransitionPreset.the related setting using .enterAnim and .exitAnim. Currently, the related setting is the only available preset:
MyActivity.kt
Select a language
Kotlin
Java
No results
import android.app.ActivityOptions
import com.stripe.stripeterminal.appsondevices.extensions.enterAnim
import com.stripe.stripeterminal.appsondevices.extensions.exitAnim
import com.stripe.stripeterminal.external.models.AppTransitionPreset
val options = ActivityOptions.makeCustomAnimation(
this,
AppTransitionPreset.SLIDE_FROM_BOTTOM.enterAnim,
AppTransitionPreset.SLIDE_FROM_BOTTOM.exitAnim,
)
startActivity(
Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("stripe://settings/")),
options.toBundle()
)
To disable the animation, pass 0 for both animation parameters:
MyActivity.kt
Select a language
Kotlin
Java
No results
val options = ActivityOptions.makeCustomAnimation(this, 0, 0)
startActivity(
Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("stripe://settings/")),
options.toBundle()
)
Device management Client-side
Your app can deep-link directly to specific device settings screens, allowing users to access the exact configuration they need without navigating the full admin menu. For example, add a “WiFi settings” button that opens network configuration, or let staff adjust screen brightness without needing to navigate through the top-level settings menu.
Available deep links
Launch any of these URIs using an Android the related setting intent:
| Destination | URI | Admin PIN required |
|---|---|---|
| All settings | stripe://settings/ | Always |
| Network | stripe://settings/network/ | Always |
| Advanced | stripe://settings/advanced/ | Always |
| Registration code | stripe://settings/registration_code/ | Always |
| Appearance | stripe://settings/appearance/ | Bypassable |
| Language | stripe://settings/language/ | Bypassable |
| Bug report | stripe://settings/bug_report/ | Bypassable |
Screens marked Bypassable prompt for the admin PIN by default, but your app can skip the prompt. See Bypass the admin PIN below.
- Network lets users select and configure WiFi networks, including static IP and custom DNS settings.
- Advanced provides access to additional settings such as diagnostics and factory reset.
- Registration code generates a pairing code to register the reader to a Stripe account.
- Appearance controls screen brightness and theme.
- Bug report collects device logs and diagnostic information and sends them to Stripe support for troubleshooting.
- Language controls the reader display language.
Launch a settings screen
Use a standard Android the related setting intent to open a settings screen. To customize the transition animation, pass an ActivityOptions bundle as described in Customize transitions when opening device settings.
See the Apps on Devices sample app for a complete working example.
MyActivity.kt
Select a language
Kotlin
Java
No results
startActivity(
Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("stripe://settings/network/"))
)
Bypass the admin PIN
For appearance, language, and bug report screens, the device prompts for the admin PIN by default. You can skip this prompt by adding the bypass_admin_menu_passcode extra to the intent. Use this for low-risk screens where you don’t want staff to enter a PIN every time.
MyActivity.kt
Select a language
Kotlin
Java
No results
startActivity(
Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("stripe://settings/appearance/"))
.putExtra("bypass_admin_menu_passcode", true)
)
Caution
Only bypass the admin PIN for non-sensitive screens. All settings, network, advanced, and registration code screens always require the PIN regardless of this flag.
Instrument the app Client-side
Stripe doesn’t provide an application-level instrumentation solution. To keep track of crashes and other logs from your application, you can use a third-party library such as Sentry or Crashlytics.
Set the device locale Client-side
The device user’s language selection (not country) informs the value returned by Locale.getDefault(). You can change the device language in the admin settings.
Screen orientation Client-side
Stripe Android devices have the Auto-rotate screen setting enabled by default. Your app can override this setting by locking the UI to a specific screen orientation.
This can be achieved by setting the screenOrientation attribute on the relevant <activity> tags in the manifest.
AndroidManifest.xml
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
</activity>
Alternatively, this can be set programmatically using Activity::setRequestedOrientation in your Activity class.
MainActivity.kt
Select a language
Kotlin
Java
No results
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Lock to portrait orientation
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
// Or, lock to landscape orientation
// requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
}
}
Limitations Client-side
Stripe Android devices don’t render a system UI, including a back button or status bar.
If your app needs to communicate battery level, charging state, and connectivity status to your users, refer to the following Android API docs for guidance:
- Monitor the Battery Level and Charging State
- Monitor connectivity status and connection metering
Working with device accessories Client-side
When the Stripe reader connects or disconnects from a dock, the Android operation system triggers a configuration change.
By default, your app’s activity is automatically recreated on a configuration change.
To disable automatic activity recreation when connecting to or disconnecting from a dock, add android:configChanges="uiMode" in the <activity> entry in your AndroidManifest.xml file.
AndroidManifest.xml
<activity
android:name=".MyActivity"
android:configChanges="uiMode" />
Your activity can be notified of configuration changes by implementing Activity::onConfigurationChanged. This method is only called if you’ve specified configurations you want to handle with the android:configChanges attribute in your manifest.
MainActivity.kt
class MainActivity : Activity() {
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// implement custom configuration change handling logic
}
}
Test your app
Use your the related setting DevKit device to test your app in the Stripe Dashboard or using the Android Debug Bridge ( adb).
You can connect your DevKit device to your computer using a USB-A to USB-C cable. Then, use adb to directly install your app’s assembled APK onto the DevKit device.
Post-transaction behavior
When you install your custom app directly, you can’t set the DevKit’s preferred kiosk app. When a transaction completes, the DevKit always returns to the default Stripe reader app. If you want to make your app the preferred kiosk app on a DevKit, you must use a deploy group as described in the Dashboard instructions.
The following examples assume your application’s package name is com.example.myapp and the main activity is MainActivity.
$ adb install myapp.apk
After installation completes, launch your app:
$ adb shell am start com.example.myapp/.MainActivity
Start admin settings:
$ adb shell am start -d "stripe://settings/"
If needed, uninstall your app:
$ adb uninstall com.example.myapp
Google’s Android Debug Bridge documentation provides a comprehensive guide to using adb.
Test payments
DevKit devices can process test payments using a Stripe physical test card, which you can order in the Dashboard. When testing payments, you can use decimal amounts to produce specific outcomes.
Warning
Don’t use real cards for test payments on DevKit devices.
