Collect payments
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:
Authorization on the customer’s card takes place in Step 3, when the SDK processes the payment.
Create a PaymentIntentServer-side
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.
Use test amounts to try producing different results. An amount ending in 00
results in an approved payment.
The following example shows how to create a PaymentIntent
on your server:
For Terminal payments, the payment_method_types
parameter must include card_present
. To control the payment flow for card_present
payments, set the capture_method
to manual
.
To accept Interac payments in Canada, you will need to also include interac_present
in payment_method_types
. For more details, visit our Canada documentation.
The PaymentIntent contains a client secret, a key that is 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.
Use the client secret as a parameter when calling collectPaymentMethod
.
The client_secret
is all you need in your client-side application to proceed to payment method collection.
Collect a payment method Client-side
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 will wait 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.
You can cancel collecting a payment method calling cancelCollectPaymentMethod
in the JavaScript SDK.
Collecting a payment method happens locally and requires no authorization or updates to the Payment Intents API object until the next step, process the payment.
Handle events
The JavaScript SDK only supports the Verifone P400 and the BBPOS WisePOS E, which have a built-in display. Your application doesn’t need to display events from the payment method collection process to users, as the reader displays them. To clear the payment method on a transaction, the cashier can press the red X key.
Process the paymentClient-side
After successfully collecting a payment method from the customer, the next step is to process the payment with the SDK. You can either process automatically or display a confirmation screen, where the customer can choose to proceed with the payment or cancel (for example, to pay with cash, or use a different payment method).
When you’re ready to proceed with the payment, call processPayment
with the updated PaymentIntent from Step 2. A successful processPayment
call results in a PaymentIntent with a status of requires_capture
.
You must manually capture payments processed by the Terminal SDKs. Set up your backend to capture the payment within two days. Otherwise, the authorization expires and funds get released back to the customer.
Handle processing failures
When processing a payment fails, the SDK returns an error that includes the updated PaymentIntent
. Your application should inspect the PaymentIntent
to decide how to deal with the error.
PaymentIntent Status | Meaning | Resolution |
---|---|---|
requires_payment_method | Payment method declined | Try collecting a different payment method by calling collectPaymentMethod again with the same PaymentIntent. |
requires_confirmation | Temporary connectivity problem | Call processPayment again with the same PaymentIntent to retry the request. |
PaymentIntent is nil | Request to Stripe timed out, unknown PaymentIntent status | Retry processing the original PaymentIntent. Don’t create a new one, as 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 is able to communicate with the internet.
Capture the paymentServer-side
Stripe Terminal uses a two-step process to prevent unintended and duplicate payments. When the SDK returns a processed PaymentIntent to your app, the payment is authorized but not captured. Read the auth and capture documentation for more information about the difference.
When your app receives a processed 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
.
Reconcile payments
To monitor the payments activity of your business, you may 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_capture
status may 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 is not associated with a completed order on your server, you can cancel it. A canceled PaymentIntent can no longer be used 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
In the US, eligible users can collect tips when capturing payments.