Set up future card payments
Use manual server-side confirmation or present payment methods separately.
Warning
We recommend that you follow the Set up future payments guide. Only use this guide if you need to use manual server-side confirmation or your integration requires presenting payment methods separately. If you’ve already integrated with Elements, see the Payment Element migration guide.
The Setup Intents API lets you save a customer’s card without an initial payment. This is helpful if you want to onboard customers now, set them up for payments, and charge them in the future—when they’re offline.
Use this integration to set up recurring payments or to create one-time payments with a final amount determined later, often after the customer receives your service.
Note
The steps in this guide are fully implemented on GitHub. Clone the repo and follow the instructions to run the demo app.
Set up Stripe
First, you need a Stripe account. Register now.
Server-side 
This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:
Client-side 
The Stripe Android SDK is open source and fully documented.
To install the SDK, add stripe-android
to the dependencies
block of your app/build.gradle file:
Note
For details on the latest SDK release and past versions, see the Releases page on GitHub. To receive notifications when a new release is published, watch releases for the repository.
Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API, such as in your Application
subclass:
Create a Customer before setupServer-side
To set a card up for future payments, you must attach it to a Customer. Create a Customer object when your customer creates an account with your business. Customer objects allow for reusing payment methods and tracking across multiple payments.
Successful creation returns the Customer object. You can inspect the object for the customer id
and store the value in your database for later retrieval.
You can find these customers in the Customers page in the Dashboard.
Create a SetupIntentServer-side
A SetupIntent is an object that represents your intent to set up a payment method for future payments.
The SetupIntent object contains a client secret, a unique key that you pass to your app. The client secret lets you perform certain actions on the client, such as confirming the setup and updating payment method details, while hiding sensitive information like customer
. You can use the client secret to validate and authenticate card details using the credit card networks. The client secret is sensitive—don’t log it, embed it in URLs, or expose it to anyone but the customer.
Server-side
On your server, make an endpoint that creates a SetupIntent and returns its client secret to your app.
If you only plan on using the card for future payments when your customer is present during the checkout flow, set the usage parameter to on_session to improve authorization rates.
Client-side
On the client, request a SetupIntent from your server.
Collect card detailsClient-side
When the customer submits the payment form, collect their card details using CardInputWidget, a drop-in UI component provided by the SDK that collects the card number, expiration date, CVC, and postal code.
CardInputWidget
performs real-time validation and formatting.
Caution
When saving card details to use for future off-session payments, especially in Europe because of regulations around card reuse, get permission to save a card. Include some text in your checkout flow to inform your user how you intend to use the card.
Call the getPaymentMethodCard
method to retrieve the card details. Pass the collected information into new PaymentMethodCreateParams and PaymentMethod.
instances to create a ConfirmSetupIntentParams
instance.
To complete the setup, pass the SetupIntentParams
object with the current Activity to PaymentLauncher confirm. The SetupIntent verifies that the card information your customer is using is valid on the network. However, automatic verification isn’t always performed. For details on this, see Check if a card is valid without a charge. Also, don’t maintain long-lived, unhandled SetupIntents as they may no longer be valid when you call PaymentLauncher#confirm()
.
Some payment methods require additional authentication steps to complete a payment. The SDK manages the payment confirmation and authentication flow, which might involve presenting additional screens required for authentication. For more information on 3D Secure authentication and customizing the authentication experience, see Supporting 3D Secure Authentication on Android.
The result of the flow returns to your calling Activity through the callback provided, here onPaymentResult
. The PaymentResult returned by the PaymentLauncher has these types:
Completed
- confirmation or authentication succeededCanceled
- the customer canceled required authenticationFailed
- the authentication attempt failed, a reason is provided by the throwable
You now have a flow to collect card details and handle any authentication requests. Use the test card 4000 0025 0000 3155
, along with any CVC, postal code, and future expiration date to test the authentication process.
When the SetupIntent succeeds, the resulting PaymentMethod ID (in setupIntent.
) will be saved to the provided Customer.
Charge the saved card laterServer-side
When you are ready to charge your customer off-session, use the Customer and PaymentMethod IDs to create a PaymentIntent. To find a card to charge, list the PaymentMethods associated with your Customer.
When you have the Customer and PaymentMethod IDs, create a PaymentIntent with the amount and currency of the payment. Set a few other parameters to make the off-session payment:
- Set off_session to
true
to indicate that the customer is not in your checkout flow during this payment attempt. This causes the PaymentIntent to throw an error if authentication is required. - Set the value of the PaymentIntent’s confirm property to
true
, which causes confirmation to occur immediately when the PaymentIntent is created. - Set payment_method to the ID of the PaymentMethod and customer to the ID of the Customer.
Inspect the status property of the PaymentIntent to confirm that the payment completed successfully. If the payment attempt succeeded, the PaymentIntent’s status is succeeded
and the off-session payment is complete.
Start a recovery flow
If the PaymentIntent has any other status, the payment did not succeed and the request fails. Notify your customer to return to your application (for example, by email, text, push notification) to complete the payment. We recommend creating a recovery flow in your app that shows why the payment failed initially and lets your customer retry.
In your recovery flow, retrieve the PaymentIntent through its client secret. Check the PaymentIntent’s lastPaymentError to inspect why the payment attempt failed. For card errors, you can show the user the last payment error’s message. Otherwise, you can show a generic failure message.
Let your customer try again
Give the customer the option to update or remove their saved card and try payment again in your recovery flow. Follow the same steps you did to accept their initial payment with one difference—confirm the original, failed PaymentIntent by reusing its client secret instead of creating a new one.
If the payment failed because it requires authentication, try again with the existing PaymentMethod instead of creating a new one.
Test the integration
By this point you should have an integration that:
- Collects and saves card details without charging the customer by using a SetupIntent
- Charges the card off-session and has a recovery flow to handle declines and authentication requests
There are several test cards you can use to make sure this integration is ready for production. Use them with any CVC, postal code, and future expiration date.
Number | Description |
---|---|
Succeeds and immediately processes the payment. | |
Requires authentication for the initial purchase, but succeeds for subsequent payments (including off-session ones) as long as the card is setup with setup_ . | |
Requires authentication for the initial purchase, and fails for subsequent payments (including off-session ones) with an authentication_ decline code. | |
Requires authentication for the initial purchase, but fails for subsequent payments (including off-session ones) with an insufficient_ decline code. | |
Always fails (including the initial purchase) with a decline code of insufficient_ . |
See the full list of test cards.