Collect card payments
Prepare your application and backend to collect card payments using Stripe Terminal.
Collecting payments with Stripe Terminal requires writing a payment flow in your application. Use the Stripe Terminal SDK to create and update a PaymentIntent, an object representing a single payment session.
Designed to be robust to failures, the Terminal integration splits the payment process into several steps, each of which can be retried safely:
- Create a PaymentIntent.
- Collect a payment method. You can define whether to automatically or manually capture your payments.
- Confirm the payment. Authorization on the customer’s card takes place when the SDK confirms the payment.
- (Optional) Capture the payment
Create a PaymentIntentClient-sideServer-side![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
The first step when collecting payments is to start the payment flow. When a customer begins checking out, your application must create a PaymentIntent
object. This represents a new payment session on Stripe.
You can create a PaymentIntent
on the client or server.
Use test amounts to try producing different results. An amount ending in 00
results in an approved payment.
Client-side ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
Create a PaymentIntent
from your client:
Warning
If your app is connected to the Verifone P400, you can’t create a PaymentIntent from the Android SDK. Instead, you must create the PaymentIntent server-side, and retrieve the PaymentIntent in your app using the Terminal.
method in the SDK.
Server-side ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
You can create the PaymentIntent
on your server if the information required to start a payment isn’t readily available in your app.
The following example shows how to create a PaymentIntent
on your server:
For Terminal payments, the payment_
parameter must include card_
.
You can control the payment flow as follows:
- To fully control the payment flow for
card_
payments, set thepresent capture_
tomethod manual
. This allows you to add a reconciliation step before finalizing the payment. - To authorize and capture payments in one step, set the
capture_
tomethod automatic
.
To accept payments in Australia, you need to set capture_
to automatic
or manual_
. For more details, visit our Australia documentation. To accept Interac payments in Canada, you must also include interac_
in payment_
. For more details, visit our Canada documentation.
The PaymentIntent
contains a client secret, a key that’s unique to the individual PaymentIntent
. To use the client secret, you must obtain it from the PaymentIntent
on your server and pass it to the client side.
To retrieve a PaymentIntent
, use the client secret to call retrievePaymentIntent
.
After you retrieve the PaymentIntent
, use it to call collectPaymentMethod
.
Collect a payment method Client-side![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
After you’ve created a PaymentIntent
, the next step is to collect a payment method with the SDK.
In order to collect a payment method, your app needs to be connected to a reader. The connected reader waits for a card to be presented after your app calls collectPaymentMethod
.
This method collects encrypted payment method data using the connected card reader, and associates the encrypted data with the local PaymentIntent
.
Note
Collecting a payment method happens locally and requires no authorization or updates to the Payment Intents API object until the next step, confirm the payment.
Optionally inspect payment method details Beta![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
For advanced use cases, you can examine the payment method details of the presented card and perform your own business logic prior to authorization.
Use the updatePaymentIntent
parameter in CollectConfiguration
to attach a PaymentMethod
to the server-side PaymentIntent
. This data is returned in the collectPaymentMethod
response.
Note
This method attaches the collected encrypted payment method data with an update to the PaymentIntent
object. It requires no authorization until the next step, confirm the payment.
This advanced use case isn’t supported on the Verifone P400 or with simulated Terminal readers.
You can access attributes like card brand, funding, and other useful data at this point.
Note
Stripe attempts to detect whether a mobile wallet is used in a transaction as shown in the wallet.
attribute. However, the attribute isn’t populated if the card’s issuing bank doesn’t support reader-driven identification of a mobile wallet, so accurate detection isn’t guaranteed. After authorization in the confirmation step, Stripe receives up-to-date information from the networks and updates wallet.
reliably
Cancel collection ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
Programmatic cancellation![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
You can cancel collecting a payment method using the Cancelable
object returned by the Android SDK.
Customer-initiated cancellation![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
When you set setEnableCustomerCancellation
to true for a transaction, smart reader users see a cancel button.
Tapping the cancel button cancels the active transaction.
Handle events ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
When collecting a payment method using a reader like the BBPOS Chipper 2X BT, without a built-in display, your app must be able to display events from the payment method collection process to users. These events help users successfully collect payments (for example, retrying a card, trying a different card, or using a different read method).
When a transaction begins, the SDK passes a ReaderInputOptions
value to your app’s reader display handler, denoting the acceptable types of input (for example, Swipe, Insert, Tap). In your app’s checkout UI, prompt the user to present a card using one of these options.
During the transaction, the SDK might request your app to display additional prompts (for example, Retry Card) to your user by passing a ReaderDisplayMessage
value to your app’s reader display handler. Make sure your checkout UI displays these messages to the user.
Note
Your application doesn’t need to display events from the payment method collection process to users because the reader displays them. To clear the payment method on a transaction, you can cancel the request.
Collect payments with Tap to Pay on Android ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
When your application is ready to collect a payment, the Stripe Android SDK takes over the display to handle the collection process. After calling the collect payment method, your application remains running. The Android device displays a full-screen prompt to the cardholder, instructing them to present their card or NFC-based mobile wallet. If there’s an error reading the card, a prompt for retry displays. A successful presentation returns a success indication, and then control returns to your application to confirm the payment.
![Tap to pay on Android](https://b.stripecdn.com/docs-statics-srv/assets/tap-to-pay-on-android-payment-collection.1297981f07df468768e4c8286b99281b.jpeg)
Payment collection
Confirm the paymentClient-side![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
After successfully collecting a payment method from the customer, the next step is to confirm the payment with the SDK. When you’re ready to proceed with the payment, call confirmPaymentIntent
with the updated PaymentIntent
from Step 2.
- For manual capture of payments, a successful
confirmPaymentIntent
call results in aPaymentIntent
with a status ofrequires_
.capture - For automatic capture of payments, the
PaymentIntent
transitions to asucceeded
state.
Warning
You must manually capture a PaymentIntent within 2 days or the authorization expires and funds are released to the customer.
Handle failures ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
When confirming a payment fails, the SDK returns an error that includes the updated PaymentIntent
. Your application needs to inspect the PaymentIntent
to decide how to deal with the error.
PaymentIntent Status | Meaning | Resolution |
---|---|---|
requires_ | Payment method declined | Try collecting a different payment method by calling collectPaymentMethod again with the same PaymentIntent . |
requires_ | Temporary connectivity problem | Call confirmPaymentIntent again with the same PaymentIntent to retry the request. |
PaymentIntent is nil | Request to Stripe timed out, unknown PaymentIntent status | Retry confirming the original PaymentIntent . Don’t create a new one, because that could result in multiple authorizations for the cardholder. |
If you encounter multiple, consecutive timeouts, there might be a problem with your connectivity. Make sure that your app can communicate with the internet.
Avoiding double charges ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
The PaymentIntent
object enables money movement at Stripe—use a single PaymentIntent
to represent a transaction.
Re-use the same PaymentIntent
after a card is declined (for example, if it has insufficient funds), so your customer can try again with a different card.
If you edit the PaymentIntent
, you must call collectPaymentMethod
to update the payment information on the reader.
A PaymentIntent
must be in the requires_
state before Stripe can confirm it. An authorized, captured, or canceled PaymentIntent
can’t be confirmed by a reader.
Capture the paymentServer-side![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
If you defined capture_
as manual
during PaymentIntent
creation in Step 1, the SDK returns an authorized but not captured PaymentIntent
to your application. Learn more about the difference between authorization and capture.
When your app receives a confirmed PaymentIntent
from the SDK, make sure it notifies your backend to capture the payment. Create an endpoint on your backend that accepts a PaymentIntent
ID and sends a request to the Stripe API to capture it:
A successful capture
call results in a PaymentIntent
with a status of succeeded
.
Note
To make sure the application fee captured is correct for connected accounts, inspect each PaymentIntent
and modify the application fee, if needed, before manually capturing the payment.
Reconcile payments ![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
To monitor the payments activity of your business, you might want to reconcile PaymentIntents with your internal orders system on your server at the end of a day’s activity.
A PaymentIntent
that retains a requires_
status might represent two things:
Unnecessary authorization on your customer’s card statement
- Cause: User abandons your app’s checkout flow in the middle of a transaction
- Solution: If the uncaptured
PaymentIntent
isn’t associated with a completed order on your server, you can cancel it. You can’t use a canceledPaymentIntent
to perform charges.
Incomplete collection of funds from a customer
- Cause: Failure of the request from your app notifying your backend to capture the payment
- Solution: If the uncaptured
PaymentIntent
is associated with a completed order on your server, and no other payment has been taken for the order (for example, a cash payment), you can capture it.
Collect tips US only![](https://b.stripecdn.com/docs-statics-srv/assets/fcc3a1c24df6fcffface6110ca4963de.svg)
In the US, eligible users can collect tips when capturing payments.