# Additional payment methods Accept supported payment methods by displaying a QR code on Terminal readers. In addition to cards, Terminal supports QR code-based [payment methods](https://docs.stripe.com/payments/payment-methods/overview.md). Your customers can scan a QR code to complete their checkout on their mobile devices. **Supported payment methods**: [WeChat Pay](https://docs.stripe.com/payments/wechat-pay.md)1, [Affirm](https://docs.stripe.com/payments/affirm.md), and [PayNow](https://docs.stripe.com/payments/paynow.md) > #### Want access to Klarna on Stripe Terminal? > > We support [Klarna](https://docs.stripe.com/payments/klarna.md) in Private Preview. If you’re interested in joining the preview, [share your email address to request access](https://docs.stripe.com/terminal/payments/additional-payment-methods.md#signup). ### Want access to Klarna on Stripe Terminal? Enter your email to request access. ```bash curl https://docs.stripe.com/preview/register \ -X POST \ -H "Content-Type: application/json" \ -H "Referer: https://docs.stripe.com/terminal/payments/additional-payment-methods" \ -d '{"email": "EMAIL", "preview": "terminal_lpm_preview"}' ``` **Supported readers**: [Smart readers](https://docs.stripe.com/terminal/smart-readers.md), [mobile readers](https://docs.stripe.com/terminal/mobile-readers.md), and [Tap to Pay readers](https://docs.stripe.com/terminal/tap-to-pay-readers.md) 1WeChat Pay isn’t available for Terminal in Japan due to regional limitations. > Connected accounts must have the [requisite capability](https://docs.stripe.com/connect/account-capabilities.md#payment-methods) to perform transactions for each payment method. Learn more about Connect compatibility with [Affirm](https://docs.stripe.com/payments/affirm.md#connect), [WeChat Pay](https://docs.stripe.com/payments/wechat-pay.md#connect), and [PayNow](https://docs.stripe.com/payments/paynow.md#connect). > > To test non-card payment methods on Stripe Terminal, use a physical reader. The simulated reader isn’t supported. > > All transactions must be made with a functional network connection, not while [offline](https://docs.stripe.com/terminal/features/operate-offline/overview.md). ## Smart readers and Tap to Pay on Android - [setReaderDisplay (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/set-reader-display.html) For [smart readers](https://docs.stripe.com/terminal/smart-readers.md) with built-in displays and [Tap to Pay on Android](https://docs.stripe.com/terminal/tap-to-pay-readers.md), the reader displays the QR code directly on its screen. If you only want to accept non-card payment methods, the reader can bypass the **tap or insert** prompt used for card payment methods. If you’ve enabled a single non-card payment method, the reader loads the QR code directly. Otherwise, the reader displays a list of non-card payment method options. > #### US-based readers > > In the United States, if you plan on deploying readers with only non-card payment methods, [displaying cart details](https://docs.stripe.com/terminal/features/display.md) isn’t supported at this time. Displaying cart details shows the NFC logo and supports pre-dipping cards to tokenize card details before a PaymentIntent is created. ![The collect payment method screen with button reading more ways to pay](https://b.stripecdn.com/docs-statics-srv/assets/s700-more-ways-to-pay.dfa04185db8a0b70bb7b13e7a695a80d.png) Collect payment method screen ![The payment method selection screen with buttons for paying with card, Affirm, or WeChat Pay](https://b.stripecdn.com/docs-statics-srv/assets/s700-pay-with-screen.9c8f58c5a58e9db064085647d0151737.png) Payment method selection screen ![The payment loading screen](https://b.stripecdn.com/docs-statics-srv/assets/s700-loading-screen.5e0523a12d7a1fc5c4f6f511d0928163.png) Loading screen ![The screen displaying a WeChat Pay QR code to scan](https://b.stripecdn.com/docs-statics-srv/assets/s700-wechat-pay-qr-code.a63cff6f60892ec896f726a93b88c167.png) Scan QR code screen ![The screen displaying Approved](https://b.stripecdn.com/docs-statics-srv/assets/s700-approved-screen.ae53ca99ba84aefbf2cb1aacf9ef1a2e.png) Approved screen ## Mobile readers and Tap to Pay on iPhone When using a [mobile reader](https://docs.stripe.com/terminal/mobile-readers.md) and [Tap to Pay on iPhone](https://docs.stripe.com/terminal/tap-to-pay-readers.md), the app on your POS device must show the QR code for supported payment methods. The mobile reader display is not capable of displaying QR codes itself because of the pixel density. To have your mobile app display the QR code, you must have at least SDK 5.3, and follow the [implementation details](https://docs.stripe.com/terminal/payments/additional-payment-methods.md?terminal-sdk-platform=android&reader-type=bluetooth#create-payment). > See [Terminal mobile readers](https://docs.stripe.com/terminal/mobile-readers.md) for supported SDKs. # Android ## Create a PaymentIntent To accept non-card payment methods through the QR code interface, [create a PaymentIntent](https://docs.stripe.com/api/payment_intents.md) and include your preferred payment method types in the `payment_method_types` parameter. - To present your customer all payment method options in the checkout flow, combine `card_present` with non-card payment method types. We recommend enabling this if you operate in a heavily [offline](https://docs.stripe.com/terminal/features/operate-offline/overview.md) environment because only cards are supported in offline mode. - If you don’t want to accept cards, support only non-card payment method types. - If you know which payment method you want to direct your customer to checkout to, select a single payment method type. ### Capture type Not all payment methods support [manual capture](https://docs.stripe.com/terminal/payments/collect-card-payment.md#capture-payment). The following table shows which payment methods support manual capture: | Payment method | Manual capture | | -------------- | --------------- | | `card_present` | ✓ Supported | | `affirm` | ✓ Supported | | `wechat_pay` | ❌ Not supported | | `paynow` | ❌ Not supported | To support the broadest set of payment methods, create your PaymentIntent with `capture_method` set to `automatic`. To support manual capture for card payments and Affirm while also accepting payment methods that require automatic capture, set `capture_method` on the nested `payment_method_options.card_present` attribute to `manual`. #### Kotlin ```kotlin val paymentMethodTypes = listOf(PaymentMethodType.CARD_PRESENT,PaymentMethodType.WECHAT_PAY) val params = PaymentIntentParameters.Builder( paymentMethodTypes = paymentMethodTypes ) .setAmount(1000) .setCurrency("usd") .setCaptureMethod(CaptureMethod.Automatic) .setPaymentMethodOptionsParameters( PaymentMethodOptionsParameters.Builder() .setCardPresentParameters( CardPresentParameters.Builder() .setCaptureMethod(CardPresentCaptureMethod.Manual) .build() ) .build() ) .build() Terminal.getInstance().createPaymentIntent( params, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` ## Handle the payment Unlike card payments, processing QR code payments occurs asynchronously. When confirming a PaymentIntent with a QR code payment method, Stripe generates a QR code unique to that payment. After confirming the payment, the QR code is displayed for the customer to scan with their mobile device. For smart readers, the reader displays the QR code on its screen. For mobile readers without displays and Tap to Pay on iPhone, your app handles QR code display (see [Confirm the PaymentIntent](https://docs.stripe.com/terminal/payments/additional-payment-methods.md#confirm-the-paymentintent)). Shortly after the customer completes the payment on their device, the payment updates to reflect completion. > The time it takes for the reader to display the result of the payment might differ depending on the payment method used. The reader usually updates after a few seconds. #### Collect, inspect, and confirm ### Collect a PaymentMethod - [collectPaymentMethod (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/collect-payment-method.html) To collect payment, pass the PaymentIntent object you created to the SDK. Your app needs to be connected to a reader to collect a payment method. #### Smart readers When you start collecting a payment method, the reader prompts the customer to tap, insert their card, or to use “more ways to pay”, which includes QR code payment methods. The reader handles displaying the payment method selection and QR code automatically. #### Kotlin ```kotlin val cancelable = Terminal.getInstance().collectPaymentMethod( paymentIntent, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` This method collects payment method data using the connected reader, and associates the data with the local PaymentIntent. At this point, you can determine the payment method type selected. #### Mobile readers For mobile readers, call `collectPaymentMethod` to begin payment collection. #### Kotlin ```kotlin val cancelable = Terminal.getInstance().collectPaymentMethod( paymentIntent, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder for handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } } ) ``` #### Handle payment method selection When your PaymentIntent includes multiple payment method types (such as `card_present` and `wechat_pay`), `collectPaymentMethod` triggers the `onPaymentMethodSelectionRequired` callback. Collection is blocked until your app invokes the callback with the customer’s selection. To handle this callback, implement [MobileReaderListener](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-mobile-reader-listener/index.html) to select the payment method. ```kotlin class MyMobileReaderListener : MobileReaderListener { override fun onPaymentMethodSelectionRequired( paymentIntent: PaymentIntent, availablePaymentOptions: List, callback: PaymentMethodSelectionCallback ) { // Present a UI for the customer to select their payment method // For example, show a dialog with the available options showPaymentMethodDialog(availablePaymentOptions) { selectedOption -> if (selectedOption != null) { // Customer selected a payment method callback.onSuccess(selectedOption) } else { // Customer cancelled callback.onFailure(Exception("Customer cancelled payment method selection")) } } } private fun showPaymentMethodDialog( options: List, onResult: (PaymentOption?) -> Unit ) { // Implement your dialog UI here // Call onResult with the selected PaymentOption or null if cancelled } } ``` After the customer selects a payment method and you invoke the callback, collection proceeds. If the customer selects a card, the reader prompts them to tap or insert. If the customer selects a QR code payment method, collection completes and QR code display happens during confirmation (see [Confirm the PaymentIntent](https://docs.stripe.com/terminal/payments/additional-payment-methods.md#confirm-the-paymentintent)). ### Confirm the PaymentIntent - [confirmPaymentIntent (Android)](https://stripe.dev/stripe-terminal-android/core/com.stripe.stripeterminal/-terminal/confirm-payment-intent.html) After successfully collecting a payment method, you can proceed to confirming the PaymentIntent. Confirming the PaymentIntent with the SDK is synchronous, calling `confirmPaymentIntent` is blocked until the payment completes. #### Smart readers For QR code payments, this method switches the reader screen to a UI displaying the QR code for the customer to scan. The reader handles the QR code display automatically. The customer completing the payment on their device updates the payment and allows the method to return. If the customer chooses to cancel the payment, the SDK returns an error. Some payment methods (for example, [Affirm](https://docs.stripe.com/payments/affirm/accept-a-payment.md?payment-ui=direct-api#web-collect-payment-method-details)) require a [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) when confirming a PaymentIntent to redirect your customer to after they authenticate or cancel their payment on the payment method’s app or site. You can provide your own [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) when confirming the PaymentIntent. If you don’t provide one, the customer sees a [generic landing page](https://terminal-statics.stripe.com/terminal-checkout/assets/index.html) hosted by Stripe. #### Kotlin ```kotlin val confirmConfig = ConfirmPaymentIntentConfiguration.Builder().setReturnUrl("https://stripe.com/").build() val cancelable = Terminal.getInstance().confirmPaymentIntent( paymentIntent, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } }, confirmConfig ) ``` #### Mobile readers For mobile readers, call `confirmPaymentIntent` to confirm the payment. If the customer cancels, the SDK returns an error. Some payment methods (for example, [Affirm](https://docs.stripe.com/payments/affirm/accept-a-payment.md?payment-ui=direct-api#web-collect-payment-method-details)) require a [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) when confirming a PaymentIntent to redirect your customer to after they authenticate or cancel their payment on the payment method’s app or site. You can provide your own [return_url](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-return_url) when confirming the PaymentIntent. If you don’t provide one, the customer sees a [generic landing page](https://terminal-statics.stripe.com/terminal-checkout/assets/index.html) hosted by Stripe. #### Kotlin ```kotlin val confirmConfig = ConfirmPaymentIntentConfiguration.Builder().setReturnUrl("https://stripe.com/").build() val cancelable = Terminal.getInstance().confirmPaymentIntent( paymentIntent, object : PaymentIntentCallback { override fun onSuccess(paymentIntent: PaymentIntent) { // Placeholder handling successful operation } override fun onFailure(e: TerminalException) { // Placeholder for handling exception } }, confirmConfig ) ``` #### Handle QR code display callback For QR code payment methods, `confirmPaymentIntent` triggers the `onQrCodeDisplayRequired` callback. Confirmation is blocked until your app invokes the callback to signal the QR code is displayed. To handle this callback, implement [MobileReaderListener](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-mobile-reader-listener/index.html) to display the QR code. Use `qrCodeImageUrlPng` or `qrCodeImageUrlSvg` from the callback data to render the QR code image. ```kotlin class MyMobileReaderListener : MobileReaderListener { override fun onQrCodeDisplayRequired( paymentIntent: PaymentIntent, qrData: QrCodeDisplayData, callback: QrCodeDisplayCallback ) { // Display the QR code to the customer // qrData contains the QR code image URLs and payment method information runOnUiThread { showQrCodeDialog(qrData) { displayed -> if (displayed) { // QR code was displayed successfully // Payment confirmation will proceed once this is called callback.onSuccess() } else { // Failed to display QR code callback.onFailure(Exception("Failed to display QR code")) } } } } private fun showQrCodeDialog( qrData: QrCodeDisplayData, onResult: (Boolean) -> Unit ) { // Create a dialog or fragment to display the QR code // Use qrData.qrCodeImageUrlPng or qrData.qrCodeImageUrlSvg to load the image // Call onResult(true) once the QR code is visible to the customer } } ``` After you invoke the callback, confirmation proceeds. The customer scans the QR code and completes payment on their device. The method returns when payment completes (or fails). ### Free up the reader to take another payment It might take multiple minutes for a customer to complete the payment on their device. Instead of waiting for the reader to reflect the result of the completed payment, you can free up the reader to take a payment for a different customer. - [Cancelable (Android)](https://stripe.dev/stripe-terminal-android/external/com.stripe.stripeterminal.external.callable/-cancelable/index.html) After the customer scans the QR code and switches to their device to complete the payment, use the `Cancelable` object returned by the Android SDK to cancel the action and reset the reader. After you cancel the reader’s action to confirm the payment, the payment intent remains in the `requires_action` state, allowing the customer to complete the payment. Use the `payment_intent.succeeded` and `payment_intent.payment_failed` webhooks to reconcile the result of the completed payment. Learn how to [monitor a PaymentIntent with webhooks](https://docs.stripe.com/payments/payment-intents/verifying-status.md#webhooks). ## Customer experience After you [confirm](https://docs.stripe.com/terminal/payments/additional-payment-methods.md#handle-payment) the PaymentIntent, the customer scans a QR code. For [smart readers](https://docs.stripe.com/terminal/smart-readers.md), the QR code is rendered on the reader screen. For [mobile readers](https://docs.stripe.com/terminal/mobile-readers.md), your app displays the QR code using the callbacks. Depending on the payment method, the customer might quickly finalize the payment in their mobile application (most digital wallets), or complete a more extended process of evaluating financing offers (BNPL payment methods). The following sections demonstrate the payment flow for supported payment methods with smart readers: #### Affirm Learn more about how to provide the best customer experience and promote awareness of BNPL options in a store through these [Affirm training resources](https://businesshub.affirm.com/hc/en-us/articles/30660865631892-Stripe-User-Affirm-Resources). ![](https://d37ugbyn3rpeym.cloudfront.net/videos/terminal/affirm-customer-experience.mp4) #### WeChat Pay ![](https://d37ugbyn3rpeym.cloudfront.net/videos/terminal/wechat-pay-customer-experience.mp4) #### PayNow ![](https://docs.stripecdn.com/50c48b010444a4c4db73126c3ecc68f555ab3a59940349a72558d934f274b666.mp4) ## Testing In a *sandbox* (A sandbox is an isolated test environment that allows you to test Stripe functionality in your account without affecting your live integration. Use sandboxes to safely experiment with new features and changes), you can scan the QR code using a QR code scanning application on your mobile phone. The QR code payload contains a URL that goes to a Stripe-hosted test payment page where you can authorize or decline the test payment. ### Affirm sandbox If your account is onboarded with Affirm, the QR code URL takes you to an Affirm-hosted sandbox page where you can complete the payment process. When you’re redirected to the Affirm sandbox, you might receive a prompt to enter the last four digits of your SSN. Affirm recommends using either `0000` or `5678` for testing purposes. If your account isn’t onboarded with Affirm, you’ll be directed to the Stripe-hosted test payment page.