# Manage payment methods in settings Use the Payment Method Settings Sheet to let your customers manage their payment methods in your app settings page. > The Payment Method Settings Sheet is intended for use on an app settings page. For checkout and payments, use [In-app Payments](https://docs.stripe.com/payments/mobile.md), which also has built-in support for saving and displaying payment methods and supports more payment methods than the Payment Method Settings Sheet. > In code, this component is referenced as `CustomerSheet` for historical reasons. Throughout the documentation, when you see `CustomerSheet` in code examples, it refers to the Payment Method Settings Sheet. The Payment Method Settings Sheet is a prebuilt UI component that lets your customers manage their saved payment methods. You can use the Payment Method Settings Sheet UI outside of a checkout flow, and the appearance and styling is customizable to match the appearance and aesthetic of your app. Customers can add and remove payment methods, which get saved to the `Customer` object, and can set their default payment method stored locally on the device. Use both In-app Payments and the Payment Method Settings Sheet to provide customers a consistent end-to-end solution for saved payment methods. > #### Accounts v2 API support > > The Payment Method Settings Sheet doesn’t support *customer-configured Accounts* (Account configurations represent role-based functionality that you can enable for accounts, such as merchant, customer, or recipient). It only supports `Customer` objects. ![Screenshot of Payment Method Settings Sheet presenting multiple saved payment methods in an Android app.](https://b.stripecdn.com/docs-statics-srv/assets/ios-landing.6c4969968fd6efe3d39fe673628f8284.png) The [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) object grants the SDK temporary access to the `Customer` or customer-configured `Account` and provides additional configuration options. These configuration options allow you to customize the behavior of `CustomerSheet`. A complete list of features exposed on the `CustomerSession` are in our [API docs](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components). ## Set up Stripe First, you need a Stripe account. [Register now](https://dashboard.stripe.com/register). To install the SDK, add `stripe-android` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Stripe Android SDK implementation("com.stripe:stripe-android:23.9.1") // Include the financial connections SDK to support US bank account as a payment method implementation("com.stripe:financial-connections:23.9.1") } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). Configure the SDK with your Stripe [publishable key](https://dashboard.stripe.com/apikeys) so that it can make requests to the Stripe API, such as in your `Application` subclass: #### Kotlin ```kotlin import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "<>" ) } } ``` > Use your [test keys](https://docs.stripe.com/keys.md#obtain-api-keys) while you test and develop, and your [live mode](https://docs.stripe.com/keys.md#test-live-modes) keys when you publish your app. ## Enable payment methods View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method). By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees. > At this time, Payment Method Settings Sheet only supports cards and US bank accounts. ## Add customer endpoints [Server-side] Create two endpoints on your server: one for fetching a CustomerSession client secret, and one to create a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) for saving a new payment method to the [Customer](https://docs.stripe.com/api/customers.md). 1. Create an endpoint to return a [Customer](https://docs.stripe.com/api/customers.md) ID and a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) client secret. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/customer_sessions \ -u <>: \ -X "POST" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "components[customer_sheet][enabled]"=true \ -d "components[customer_sheet][features][payment_method_remove]"=enabled ``` > Integrations with legacy customer ephemeral keys results in saved payment methods having an `allow_redisplay` value of `unspecified`. To display these payment methods in addition to payment methods saved while using Customer Sessions, set `payment_method_allow_redisplay_filters` to `["unspecified", "always"]`. For more information, see [CustomerSessions](https://docs.stripe.com/api/customer_sessions.md). 1. Create an endpoint to return a [SetupIntent](https://docs.stripe.com/api/setup_intents.md) configured with the [Customer](https://docs.stripe.com/api/customers.md) ID. #### curl ```bash # Create a Customer (skip this and get the existing Customer ID if this is a returning customer) curl https://api.stripe.com/v1/customers \ -u <>: \ -X "POST" curl https://api.stripe.com/v1/setup_intents \ -u <>: \ -d "customer"="{{CUSTOMER_ID}}" \ ``` If you only plan to use the payment method for future payments when your customer is present during the checkout flow, set the [usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage) parameter to *on\_session* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method) to improve authorization rates. ## Create a Customer Session provider [Client-side] A `CustomerSessionProvider` enables a `CustomerSheet` to communicate with Stripe using [CustomerSession](https://docs.stripe.com/api/customer_sessions.md) objects. On the client, create a `CustomerSessionProvider` that can create a `CustomerSession` client secret and a `SetupIntent` client secret from your server. ```kotlin import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi @OptIn(ExperimentalCustomerSheetApi::class) class MyCustomerSessionProvider : CustomerSheet.CustomerSessionProvider() { val myBackend = // .... override suspend fun providesCustomerSessionClientSecret(): Result { return myBackend.getCustomerSessionClientSecret().fold( onSuccess = { response -> Result.success( CustomerSessionClientSecret.create( customerId = response.customerId, clientSecret = response.customerSessionClientSecret, ) ) }, onFailure = { exception -> Result.failure(exception) } ) } override suspend fun provideSetupIntentClientSecret(customerId: String): Result { return myBackend.getSetupIntentClientSecret(customerId).fold( onSuccess = { response -> Result.success(response.setupIntentClientSecret) }, onFailure = { exception -> Result.failure(exception) } ) } } ``` ```kotlin import android.app.Application import androidx.lifecycle.AndroidViewModel class CheckoutViewModel( application: Application ) : AndroidViewModel(application) { val customerSessionProvider = MyCustomerSessionProvider() } ``` ## Configure the sheet Next, initialize the Payment Method Settings Sheet using the `CustomerSheet` class with your `CustomerSessionProvider` then call `configure` with a [CustomerSheet.Configuration](https://github.com/stripe/stripe-android/blob/master/paymentsheet/src/main/java/com/stripe/android/customersheet/CustomerSheet.kt). Always call `configure` before calling `present` and `retrievePaymentOptionSelection`. ```kotlin import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.customersheet.rememberCustomerSheet @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutActivity : ComponentActivity() { private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = CustomerSheet.Configuration.builder(merchantDisplayName = "{{YOUR BUSINESS NAME}}") .build() setContent { val customerSheet = rememberCustomerSheet( customerSessionProvider = viewModel.customerSessionProvider, callback = viewModel::handleResult // Implemented in next step ) LaunchedEffect(customerSheet) { customerSheet.configure(configuration = configuration) } } } } ``` ## Present the sheet Present the Payment Method Settings Sheet using `CustomerSheet`. When the customer dismisses the sheet, the `CustomerSheet` calls the completion block with a `CustomerSheetResult`. ```kotlin import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModelsimport androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.ExperimentalCustomerSheetApi import com.stripe.android.customersheet.rememberCustomerSheetimport com.stripe.android.uicore.image.rememberDrawablePainter @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutActivity : ComponentActivity() {private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = CustomerSheet.Configuration.builder(merchantDisplayName = "{{YOUR BUSINESS NAME}}") .headerTextForSelectionScreen("Manage your payment method") .build() setContent { val customerSheet = rememberCustomerSheet( customerSessionProvider = viewModel.customerSessionProvider, callback = viewModel::handleResult ) LaunchedEffect(customerSheet) { customerSheet.configure(configuration = configuration)viewModel.handleResult(customerSheet.retrievePaymentOptionSelection()) }val paymentOption by viewModel.paymentOption.collectAsState() Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, ) { val icon = paymentOption?.icon() if (icon != null) { Image( painter = rememberDrawablePainter( drawable = icon ), contentDescription = "Payment Method Icon", modifier = Modifier.height(32.dp) ) } TextButton( onClick = { customerSheet.present() } ) { Text( text = paymentOption?.label ?: "Select" ) } } } } } ``` ```kotlin import android.app.Application import androidx.lifecycle.AndroidViewModel import com.stripe.android.customersheet.ExperimentalCustomerSheetApiimport com.stripe.android.paymentsheet.model.PaymentOption import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update @OptIn(ExperimentalCustomerSheetApi::class) class CheckoutViewModel( application: Application ) : AndroidViewModel(application) { val customerSessionProvider = // ... private val _paymentOption = MutableStateFlow(null) val paymentOption: StateFlow = _paymentOption fun handleResult(result: CustomerSheetResult) { when (result) { is CustomerSheetResult.Selected -> { // Configure your UI based on the payment option _paymentOption.update { result.selection?.paymentOption } } is CustomerSheetResult.Canceled -> { // Configure your UI based on the payment option _paymentOption.update { result.selection?.paymentOption } } is CustomerSheetResult.Failed -> { // Show the error in your UI } } } } ``` - If the customer selects a payment method, the result is `CustomerSheetResult.Selected`. The associated value is the selected `PaymentOptionSelection`, or null if the user deleted the previously-selected payment method. The full payment method details are available in the `PaymentOptionSelection`’s `paymentMethod` value. - If the customer cancels the sheet, the result is `CustomerSheetResult.Canceled`. The associated value is the customer’s original `PaymentOptionSelection`, or null if the customer hasn’t selected a payment method before or has deleted the originally selected payment method. - If an error occurs, the result is `CustomerSheetResult.Failed`. ## Optional: Enable Google Pay ### Set up your integration To use Google Pay, first enable the Google Pay API by adding the following to the `` tag of your **AndroidManifest.xml**: ```xml ... ``` For more details, see Google Pay’s [Set up Google Pay API](https://developers.google.com/pay/api/android/guides/setup) for Android. ### Add Google Pay To add Google Pay to your integration, pass `true` to [googlePayEnabled](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/google-pay-enabled.html) when initializing [CustomerSheet.Configuration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/index.html) with [CustomerSheet.Configuration.Builder](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html). #### Kotlin ```kotlin val configuration = CustomerSheet.Configuration.Builder() .googlePayEnabled(true) .build() ``` ## Optional: Enable ACH payments To enable ACH debit payments include Financial Connections as a dependency for your app. The [Stripe Android SDK](https://github.com/stripe/stripe-android) is open source and [fully documented](https://stripe.dev/stripe-android/). To install the SDK, add `financial-connections` to the `dependencies` block of your [app/build.gradle](https://developer.android.com/studio/build/dependencies) file: #### Kotlin ```kotlin plugins { id("com.android.application") } android { ... } dependencies { // ... // Financial Connections Android SDK implementation("com.stripe:financial-connections:23.9.1") } ``` > For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-android/releases) page on GitHub. To receive notifications when a new release is published, [watch releases for the repository](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/configuring-notifications#configuring-your-watch-settings-for-an-individual-repository). ## Optional: Fetch the selected payment method To fetch the default payment method without presenting the Payment Method Settings Sheet, call `retrievePaymentOptionSelection()` on `CustomerSheet`. ```kotlin class CheckoutActivity : ComponentActivity() { private val viewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val configuration = ... setContent { val customerSheet = ... LaunchedEffect(Unit) { customerSheet.configure(configuration = configuration) val result = customerSheet.retrievePaymentOptionSelection() viewModel.handleResult(result) } ... } } } ``` ## Optional: Customize the sheet ### Appearance Customize the colors, fonts, and other appearance attributes to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api/mobile.md?platform=android). > `retrievePaymentMethods` can filter out saved payment methods from being shown, but won’t impact the type of payment methods that are addable. ### Default billing details To set default values for billing details collected in the customer sheet, configure the [defaultBillingDetails](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#-1446247975%2FFunctions%2F2002900378) property. The `CustomerSheet` pre-populates its fields with the values that you provide. ```kotlin val configuration = CustomerSheet.Configuration.Builder() .defaultBillingDetails( PaymentSheet.BillingDetails( address = PaymentSheet.Address( country = "US" ), email = "foo@bar.com" ) ) .build() ``` ### Billing details collection Use [billingDetailsCollectionConfiguration](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#1512634376%2FFunctions%2F2002900378) to specify how you want to collect billing details in the payment sheet. You can collect your customer’s name, email, phone number, and address. To attach values that aren’t collected by `CustomerSheet`, add them to the [defaultBillingDetails](https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.customersheet/-customer-sheet/-configuration/-builder/index.html#-1446247975%2FFunctions%2F2002900378) property and set `billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod` to `true`. Make sure that you complete this step if you don’t plan to collect values required by the payment method. ```kotlin val configuration = CustomerSheet.Configuration.Builder() .defaultBillingDetails( PaymentSheet.BillingDetails( email = "foo@bar.com" ) ) .billingDetailsCollectionConfiguration( PaymentSheet.BillingDetailsCollectionConfiguration( name = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Always, email = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Never, address = PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full, attachDefaultsToPaymentMethod = true, ) ) .build() ``` > Consult with your legal team regarding laws that apply to you collecting information. Only collect phone numbers if you need them for the transaction.