Getting started with the Android SDK

    Set up the Stripe Terminal Android SDK so that you can begin accepting in-person payments.

    Getting started with the Android SDK requires five steps:

    1. Install the SDK in your app
    2. Configure your app
    3. Set up the connection token endpoint in your app and backend
    4. Initialize the SDK in your app
    5. Connect your app to the simulated reader

    Step 1: Install the SDK Client-side

    The Android SDK is compatible with apps supporting Android API level 21 and above. Apps can be written using Kotlin or Java 8, but must use AndroidX.

    To install the SDK, add stripeterminal to the dependencies block of your app/build.gradle file:

    apply plugin: 'com.android.application' android { ... } dependencies { implementation "com.stripe:stripeterminal:1.0.17" // ... }

    Step 2: Configure your app Client-side

    You must enable location access in order to use the Android SDK.

    Add the ACCESS_FINE_LOCATION permission to your app’s manifest:

    <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.stripe.example.app"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Change `StripeTerminalApplication` to your application name --> <application android:name=".StripeTerminalApplication"> <!-- Your content goes here --> </application> </manifest>

    Before initializing the Terminal object, add the following check to make sure that the ACCESS_FINE_LOCATION permission is enabled in your app:

    if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION}; // REQUEST_CODE_LOCATION should be defined on your app level ActivityCompat.requestPermissions(getActivity(), permissions, REQUEST_CODE_LOCATION); }
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { val permissions = arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION) // REQUEST_CODE_LOCATION should be defined on your app level ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_LOCATION) }

    Also verify that the app user grants location permission—the SDK doesn’t function without it. To do this, override the onRequestPermissionsResult method in your app and check the permission result.

    @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_CODE_LOCATION && grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) { throw new RuntimeException("Location services are required in order to " + "connect to a reader."); } }
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { if (requestCode == REQUEST_CODE_LOCATION && grantResults.isNotEmpty() && grantResults[0] != PackageManager.PERMISSION_GRANTED) { throw RuntimeException("Location services are required in order to " + "connect to a reader.") } }

    Step 3: Set up the ConnectionToken endpoint Server-side Client-side

    Server-side

    To connect to a reader, your backend needs to give the SDK permission to use the reader with your Stripe account, by providing it with the secret from a ConnectionToken. Your backend should only create connection tokens for clients that it trusts.

    curl https://api.stripe.com/v1/terminal/connection_tokens \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -X POST
    # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # In a new endpoint on your server, create a ConnectionToken and return the # `secret` to your app. The SDK needs the `secret` to connect to a reader. Stripe::Terminal::ConnectionToken.create
    # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # In a new endpoint on your server, create a ConnectionToken and return the # `secret` to your app. The SDK needs the `secret` to connect to a reader. connection_token = stripe.terminal.ConnectionToken.create()
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // In a new endpoint on your server, create a ConnectionToken and return the // `secret` to your app. The SDK needs the `secret` to connect to a reader. let connectionToken = stripe.terminal.connectionTokens.create();
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // In a new endpoint on your server, create a ConnectionToken and return the // `secret` to your app. The SDK needs the `secret` to connect to a reader. $connectionToken = \Stripe\Terminal\ConnectionToken::create();
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // In a new endpoint on your server, create a ConnectionToken and return the // `secret` to your app. The SDK needs the `secret` to connect to a reader. Map<String, Object> params = new HashMap<String, Object>(); String connectionToken = ConnectionToken.create(params);
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // In a new endpoint on your server, create a ConnectionToken and return the // `secret` to your app. The SDK needs the `secret` to connect to a reader. params := &stripe.TerminalConnectionTokenParams{} connectiontoken, err := connectiontoken.New(params)
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // In a new endpoint on your server, create a ConnectionToken and return the // `secret` to your app. The SDK needs the `secret` to connect to a reader. var options = new ConnectionTokenCreateOptions{}; var service = new ConnectionTokenService(); ConnectionToken connectionToken = service.Create(options);

    Client-side

    To give the SDK access to this endpoint, implement the ConnectionTokenProvider interface in your app, which defines a single function that requests a ConnectionToken from your backend.

    public class TokenProvider implements ConnectionTokenProvider { @Override public void fetchConnectionToken(ConnectionTokenCallback callback) { try { // Your backend should call /v1/terminal/connection_tokens and return the // JSON response from Stripe. When the request to your backend succeeds, // return the `secret` from the response to the SDK. callback.onSuccess(secret); } catch (Exception e) { callback.onFailure( new ConnectionTokenException("Failed to fetch connection token", e)); } } }
    class TokenProvider : ConnectionTokenProvider { override fun fetchConnectionToken(callback: ConnectionTokenCallback) { try { // Your backend should call /v1/terminal/connection_tokens and return the // JSON response from Stripe. When the request to your backend succeeds, // return the `secret` from the response to the SDK. callback.onSuccess(secret) } catch (e: Exception) { callback.onFailure( ConnectionTokenException("Failed to fetch connection token", e) ) } } }

    This function is called whenever the SDK is initialized. It’s also called when a new ConnectionToken is needed to connect to a reader (for example, when your app disconnects from a reader). If the SDK is unable to retrieve a new ConnectionToken from your backend, connecting to a reader fails with the error from your server.

    Step 4: Initialize the SDK Client-side

    The Android SDK is lifecycle aware. To prevent memory leaks and ensure proper cleanup of long-running Terminal SDK processes, your application must have the Application subclass where TerminalLifeCycleObserver is configured. This subclass should do the following:

    • Register activity lifecycle callbacks
    • Implement the onTrimMemory method to notify the SDK to prune its memory usage
    // Substitute with your application name, and remember to keep it the same as your AndroidManifest.xml class StripeTerminalApplication extends Application { @NotNull private final TerminalLifecycleObserver observer; @Override public void onCreate() { super.onCreate(); // Register the observer for all lifecycle hooks observer = TerminalLifecycleObserver.getInstance() registerActivityLifecycleCallbacks(observer); } // Don't forget to let the observer know if your application is running low on memory @Override public void onTrimMemory(level: Int) { super.onTrimMemory(level); observer.onTrimMemory(level, this); } }
    // Substitute with your application name, and remember to keep it the same as your AndroidManifest.xml class StripeTerminalApplication : Application() { private val observer: TerminalLifecycleObserver = TerminalLifecycleObserver.getInstance() override fun onCreate() { super.onCreate() // Register the observer for all lifecycle hooks registerActivityLifecycleCallbacks(observer) } // Don't forget to let the observer know if your application is running low on memory override fun onTrimMemory(level: Int) { super.onTrimMemory(level) observer.onTrimMemory(level, this) } }

    The Terminal class made available by the Stripe Terminal SDK exposes a generic interface for discovering readers, connecting to a reader, creating payment, and updating reader software.

    To get started, provide the current application context, the ConnectionTokenProvider implemented in Step 3, and a TerminalListener object. You can use this listener to handle events from the SDK, such as disconnects. For more information, see Handling disconnects.

    // Create your listener object. Override any methods that you want to be notified about TerminalListener listener = new TerminalListener() {}; // Choose the level of messages that should be logged to your console LogLevel logLevel = LogLevel.VERBOSE; // Create your token provider. MyTokenProvider tokenProvider = new MyTokenProvider(); // Pass in the current application context, your desired logging level, your token provider, and the listener you created if (!Terminal.isInitialized()) { Terminal.initTerminal(getActivity(), logLevel, tokenProvider, listener); } // Since the Terminal is a singleton, you can call getInstance whenever you need it Terminal.getInstance();
    // Create your listener object. Override any methods that you want to be notified about val listener = TerminalListener {} // Choose the level of messages that should be logged to your console val logLevel = LogLevel.VERBOSE // Create your token provider. val tokenProvider = MyTokenProvider() // Pass in the current application context, your desired logging level, your token provider, and the listener you created if (!Terminal.isInitialized()) { Terminal.initTerminal(activity, logLevel, tokenProvider, listener) } // Since the Terminal is a singleton, you can call getInstance whenever you need it Terminal.getInstance()

    Step 5: Connect to the simulated reader Client-side

    The Stripe Terminal SDK comes with a built-in simulated card reader, so you can develop and test your app without connecting to physical hardware. Whether your integration is complete or you’re just starting out, use the simulated reader to emulate all the Terminal flows in your app: connecting to a reader, updating reader software, and collecting payments.

    Note that the simulated reader does not provide a UI. After connecting to it in your app, you can see it working when calls to the Stripe SDK succeed.

    To use the simulated reader, call discoverReaders to search for readers, with the simulated option set to true. When discoverReaders returns a result, call connectReader to connect to the simulated reader.

    // Handler for a "Connect Reader" button public void onConnect() { DiscoveryConfiguration config = new DiscoveryConfiguration(0, DeviceType.CHIPPER_2X, true); Terminal.getInstance().discoverReaders(config, readers -> { // Just select the first reader here. Reader firstReader = readers.get(0); Terminal.getInstance().connectReader(firstReader, new ReaderCallback() { @Override public void onSuccess(Reader r) { System.out.println("Connected to reader"); } @Override public void onFailure(@Nonnull TerminalException e) { e.printStackTrace(); } }); }, new Callback() { @Override public void onSuccess() { System.out.println("Finished discovering readers"); } @Override public void onFailure(TerminalException e) { e.printStackTrace(); } } }
    // Handler for a "Connect Reader" button fun onConnect() { val config = DiscoveryConfiguration(0, DeviceType.CHIPPER_2X, true) Terminal.getInstance().discoverReaders(config, { readers: List<Reader> -> // Just select the first reader here. val firstReader = readers.first() Terminal.getInstance().connectReader(firstReader, object : ReaderCallback { override fun onSuccess(r: Reader) { println("Connected to reader") } override fun onFailure(e: TerminalException) { e.printStackTrace() } }) }, object : Callback { override fun onSuccess() { println("Finished discovering readers") } override fun onFailure(e: TerminalException) { e.printStackTrace() } }) }

    SDK updates

    Stripe periodically releases updates to the Stripe Terminal JavaScript SDK, the Stripe Terminal iOS SDK, and the Stripe Terminal Android SDK, which can include new functionality, bug fixes, and security updates. Update your integrated version of the Stripe Terminal JavaScript, iOS, or Android SDK as soon as a new version is available.

    Next steps

    Congratulations! You integrated the Stripe Terminal SDK into your app and connected to a simulated reader. Next, either continue your integration using the simulated reader to collect payments, or learn about physical reader types.

    Was this page helpful?

    Feedback about this page?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page