Skip to content
Create account
or
Sign in
The Stripe Docs logo
/
Ask AI
Create account
Sign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseManaged Payments
Use Payment Links
Build a checkout page
Build an advanced integration
Build an in-app integration
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment interfaces
Payment Links
Checkout
Web Elements
In-app Elements
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
In-person payments
Terminal
    Overview
    Accept in-person payments
    Integration design
    Select your reader
    Design an integration
    Quickstart
    Example applications
    Testing
    Terminal setup
    Set up your integration
    Connect to a reader
    Accepting a payment
    Collect card payments
    Additional payment methods
    Accept offline payments
    Mail order and telephone order payments
    Regional considerations
    During checkout
    Collect tips
    Collect and save payment details for future use
    Flexible authorizations
    After checkout
    Refund transactions
    Provide receipts
    Customize checkout
    Cart display
    Collect on-screen inputs
    Collect swiped data
    Collect tapped data for NFC instruments
    Apps on devices
      Build and test your app
      Prepare for app review
      Submit your app for review
      Deploy your app in the Dashboard
      Deploy your app with the API
      Monitor your deployment
      Troubleshooting
    Manage readers
    Order, return, replace readers
    Register readers
    Manage locations and zones
    Configure readers
    Monitor Readers
    Encryption
    References
    API references
    Mobile readers
    Smart readers
    SDK migration guide
    Deployment checklist
    Stripe Terminal reader product sheets
Beyond payments
Incorporate your company
Crypto
Financial Connections
Climate
HomePaymentsTerminalApps on devices

Build and test your app

Learn how to build and test your app using a DevKit.

Copy page

Sample integration

Access the Apps on Devices sample integration repository on GitHub.

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.

Set up the DevKit

Before you can use your DevKit for app development, you must do the following:

  1. Follow the on-screen prompts to connect to a network.
  2. Register the device to your Stripe account.
  3. 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
Kotlin
dependencies { implementation("com.stripe:stripeterminal-core:4.5.0") implementation("com.stripe:stripeterminal-handoffclient:4.5.0") }

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:4.5.0).

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

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <application android:name=".MyApp"> <!-- App manifest contents --> </application> </manifest>

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

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:

See more examples of how to discover and connect using handoff mode in the Apps on Devices sample integration repository on GitHub.

  1. Your app runs on your registered device.
  2. Your app discovers the reader by calling discoverReaders with HandoffDiscoveryConfiguration.
  3. 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
Kotlin
private fun discoverReaders() { Terminal.getInstance().discoverReaders( config = HandoffDiscoveryConfiguration(), discoveryListener = object : DiscoveryListener { override fun onUpdateDiscoveredReaders(readers: List<Reader>) { // In handoff 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, HandoffConnectionConfiguration( object : HandoffReaderListener { 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 Preview

Apps on Devices supports offline payment collection.

Device management
Client-side

You can access the device’s admin settings by launching the stripe://settings/ deep-link URI from your app.

See an example of launching the admin settings deep-link URI.

MyActivity.kt
Kotlin
startActivity( Intent(Intent.ACTION_VIEW) .setData(Uri.parse("stripe://settings/")) )

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 programatically using Activity::setRequestedOrientation in your Activity class.

MainActivity.kt
Kotlin
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 the user, 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 S700 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.

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.

Next steps

  • Prepare for app review
  • Submit your app
Was this page helpful?
YesNo
Need help? Contact Support.
Join our early access program.
Check out our changelog.
Questions? Contact Sales.
LLM? Read llms.txt.
Powered by Markdoc