Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
Security
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Home

Mobile Payments UI Integration Guide
Beta

Learn how to integrate our prebuilt payments UI for mobile apps

Beta info

  • The latest iOS release is beta-2. The latest Android release is beta-1. Beta program members will be notified about new releases by email.
  • Don’t hesitate to get in touch by emailing mobile-payments-ui-beta@stripe.com if you have any questions or feedback!

This guide shows you how to:

  1. Install the Stripe Mobile SDK (Private Beta)
  2. Set up your server
  3. Add a prebuilt payment sheet to accept payments in your mobile app

Install the SDK

The steps in this guide are fully implemented on iOS in our example app and example backend server.

The iOS SDK has been converted from Objective-C to Swift. If you’re using an older version, follow our migration guide after updating the SDK.

To install the SDK, follow these steps:

  1. In Xcode, select File > Swift Packages > Add Package Dependency and enter https://github.com/stripe/stripe-ios as the repository URL.
  2. Select the mc-beta-2 branch.
  3. Add the Stripe product to your app’s target.

Add a server endpoint

This integration uses three Stripe API objects:

  1. A PaymentIntent. Stripe uses this to represent your intent to collect payment from a customer, tracking your charge attempts and payment state changes throughout the process.

  2. A Customer (optional). To set up a card for future payments, it must be attached to a Customer. Create a Customer object when your customer creates an account with your business. If your customer is making a payment as a guest, you can create a Customer object before payment and associate it with your own internal representation of the customer’s account later.

  3. A Customer Ephemeral Key (optional). Information on the Customer object is sensitive, and cannot be retrieved directly from an app. An Ephemeral Key grants the SDK temporary access to the Customer.

If you never save cards to a Customer and don’t allow returning Customers to reuse saved cards, you can omit the Customer and Customer Ephemeral Key objects from your integration.

For security, your app cannot create these objects. Instead, add an endpoint on your server that:

  1. Retrieves the Customer, or creates a new one.
  2. Creates an Ephemeral Key for the Customer.
  3. Creates a PaymentIntent, passing the Customer id.
  4. Returns the Payment Intent’s clientSecret, the Ephemeral Key’s secret, and the Customer’s id to your app.

A running implementation in Node is available on Glitch for quick testing.

# This example sets up an endpoint using the Sinatra framework. # Watch this video to get started: https://youtu.be/8aA9Enb8NVc. post '/payment-sheet' do # Here, we're creating a new customer. Use an existing Customer if this is a returning user customer = Stripe::Customer.create ephemeralKey = Stripe::EphemeralKey.create( {customer: customer['id']}, {apiVersion: '2020-08-27'} ) paymentIntent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: customer['id'] }) { paymentIntent: paymentIntent['client_secret'], ephemeralKey: ephemeralKey['secret'], customer: customer['id'] }.to_json end

Integrate the payment sheet

Currently, PaymentSheet does not support collecting shipping details. If you need to collect shipping details, collect them in your checkout before displaying the payment sheet.

Before getting started, your checkout page should:

  • Show the products being purchased and the total amount
  • Collect any shipping information required
  • Include a checkout button to present Stripe’s UI

Present a prebuilt payment sheet to handle the entire payment flow. In the payment sheet, your customer can reuse a saved payment method or add a new one. Your customer taps a “Buy” button in the payment sheet to complete the payment.

Next, integrate Stripe’s prebuilt payment UI in your app’s checkout using use the PaymentSheet class. PaymentSheet guides the customer through the payment process, combining all the steps required — collecting payment details, billing details, and confirming the payment — into a single sheet. If you prefer a more customized checkout experience, consider using the Custom integration.

First, configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API.

Use your test mode keys while you test and develop, and your live mode keys before you publish your app.

AppDelegate.swift
import UIKit import Stripe @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { STPAPIClient.shared.publishableKey =
"pk_test_TYooMQauvdEDq54NiTphI7jx"
// do any other necessary launch configuration return true } }

In your app’s checkout, make a network request to the backend endpoint you created in the previous step and initialize PaymentSheet. To reduce loading time, make this request before the Checkout button is tapped, e.g. when the screen is loaded.

import UIKit import Stripe class CheckoutViewController: UIViewController { @IBOutlet weak var buyButton: UIButton! var paymentSheet: PaymentSheet? let backendCheckoutUrl = URL(string: "Your backend endpoint")! // Your backend endpoint override func viewDidLoad() { super.viewDidLoad() buyButton.addTarget(self, action: #selector(didTapCheckoutButton), for: .touchUpInside) buyButton.isEnabled = false // MARK: Fetch the PaymentIntent and Customer information from the backend var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let customerId = json["customer"] as? String, let customerEphemeralKeySecret = json["ephemeralKey"] as? String, let paymentIntentClientSecret = json["paymentIntent"] as? String, let self = self else { // Handle error return } // MARK: Create a PaymentSheet instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret) self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) DispatchQueue.main.async { self.buyButton.isEnabled = true } }) task.resume() } }

When the checkout button is tapped, call present to present the payment sheet. After the customer completes the payment, the sheet is dismissed and the completion block is called with a PaymentResult.

@objc func didTapCheckoutButton() { // MARK: Start the checkout process paymentSheet?.present(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Payment succeeded!") case .canceled: print("Canceled!") case .failed(let error, _): print("Payment failed: \n\(error.localizedDescription)") } } }

You’re done! Read on to learn more about the Custom integration style and integrating Apple Pay and Google Pay.

Custom integration

If you prefer a more customized checkout experience, you can use the Custom integration style. Choose this style if:

  • Your checkout screen has a “Choose payment method” button to collect payment details, and a separate “Buy” button to complete the payment.
  • You want your customer to complete the payment on your checkout screen instead of our payment sheet.

If you choose this integration, you’ll use the PaymentSheet.FlowController class. PaymentSheet.FlowController breaks down PaymentSheet into its individual steps, and lets you control when those steps happen. For example, your checkout page can display a “Choose payment method” button to collect payment details, and a separate “Buy” button to finalize the payment.

Custom Present a prebuilt payment sheet to collect payment details. In the payment sheet, your customer can add new payment details and select saved payment method. Your customer returns to your checkout screen before completing the payment.

This guide assumes you have a payment details button with a label and an image that can display the details of a selected payment method and a buy button. You’ll hook these buttons up to PaymentSheet.FlowController in the following steps.

In your app’s checkout, make a network request to your backend endpoint and initialize PaymentSheet.FlowController. To reduce loading time, make this request before the Checkout button is tapped, e.g. when the screen is loaded.

import UIKit import Stripe class CheckoutViewController: UIViewController { @IBOutlet weak var buyButton: UIButton! @IBOutlet weak var paymentMethodButton: UIButton! @IBOutlet weak var paymentMethodImage: UIImageView! var paymentSheetFlowController: PaymentSheet.FlowController! let backendCheckoutUrl = URL(string: "Your backend endpoint")! // Your backend endpoint override func viewDidLoad() { super.viewDidLoad() buyButton.addTarget(self, action: #selector(didTapBuyButton), for: .touchUpInside) buyButton.isEnabled = false paymentMethodButton.addTarget(self, action: #selector(didTapPaymentMethodButton), for: .touchUpInside) paymentMethodButton.isEnabled = false // MARK: Fetch the PaymentIntent and Customer information from the backend var request = URLRequest(url: backendCheckoutUrl) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { [weak self] (data, response, error) in guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any], let paymentIntentClientSecret = json["paymentIntent"] as? String, let customerId = json["customer"] as? String, let customerEphemeralKeySecret = json["ephemeralKey"] as? String, let self = self else { // Handle error return } // MARK: Create a PaymentSheet.FlowController instance var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "Example, Inc." configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret) PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) { [weak self] result in switch result { case .failure(let error): print(error) case .success(let paymentSheetFlowController): self?.paymentSheetFlowController = paymentSheetFlowController self?.paymentMethodButton.isEnabled = true self?.updateButtons() } } }) task.resume() } // ... }

PaymentSheet.FlowController has a paymentOption property containing an image and label representing the customer’s payment method. After PaymentSheet.FlowController is initialized, enable your payment method button and update its UI with the paymentOption.

When the customer taps your payment method button, collect their payment details by calling presentPaymentOptions. When the customer finishes, the sheet dismisses itself and calls the provided completion handler. Update your payment method button with the selected payment method details.

@objc func didTapPaymentMethodButton() { // MARK: Present payment options to the customer paymentSheetFlowController.presentPaymentOptions(from: self) { self.updateButtons() } } func updateButtons() { // MARK: Update the payment method and buy buttons if let paymentOption = paymentSheetFlowController.paymentOption { paymentMethodButton.setTitle(paymentOption.label, for: .normal) paymentMethodButton.setTitleColor(.black, for: .normal) paymentMethodImage.image = paymentOption.image buyButton.isEnabled = true } else { paymentMethodButton.setTitle("Select", for: .normal) paymentMethodButton.setTitleColor(.systemBlue, for: .normal) paymentMethodImage.image = nil buyButton.isEnabled = false } }

Finally, when your buy button is tapped, call confirmPayment to complete the payment.

@objc func didTapBuyButton() { // MARK: Confirm payment paymentSheetFlowController.confirmPayment(from: self) { paymentResult in // MARK: Handle the payment result switch paymentResult { case .completed: print("Payment succeeded!") case .canceled: print("Canceled!") case .failed(let error, _): print(error) } } }

Apple Pay

If your checkout page has a dedicated Apple Pay button, follow our Apple Pay guide and use ApplePayContext to collect payment from your Apple Pay button. You can use PaymentSheet to handle other payment method types.

First, follow steps 1–3 in our Accept Apple Pay in your iOS app guide. Once you’ve finished adding the Apple Pay capability in Xcode, return to this guide.

Next, set applePay after initializing PaymentSheet.Configuration with your merchant ID and the country code of your business (check your account details here):

var configuration = PaymentSheet.Configuration() configuration.applePay = .init(merchantId: "merchant.com.your_app_name", merchantCountryCode: "US")

Google Pay

First, follow step 1 in our Accepting Google Pay in your Android app guide. Once you’ve finished updating your AndroidManifest.xml, return to this guide.

When you configure PaymentSheet or PaymentSheet.FlowController, provide a PaymentSheet.GooglePayConfiguration with your Google Pay environment (production or test) and country code.

val googlePayConfig = PaymentSheet.GooglePayConfiguration( environment = PaymentSheet.GooglePayConfiguration.Environment.Test, countryCode = "US" ) paymentSheet.present( paymentIntentClientSecret = paymentIntentClientSecret, configuration = PaymentSheet.Configuration( merchantDisplayName = "Example, Inc.", googlePay = googlePayConfig ) ) // Custom integration flowController.configure( paymentIntentClientSecret = paymentIntentClientSecret, configuration = PaymentSheet.Configuration( merchantDisplayName = "Example, Inc.", googlePay = googlePayConfig ) ) { isReady, error -> }

Card scanning

To enable card scanning support, set the NSCameraUsageDescription (“Privacy - Camera Usage Description”) in your application’s Info.plist, and provide a reason for accessing the camera (e.g. “To scan cards”). Card scanning is supported on devices with iOS 13 or higher.

Customization

All customization is configured via the PaymentSheet.Configuration object.

Merchant display name

You can specify your own customer-facing business name instead of your app’s name. This is used to display a “Pay (merchantDisplayName)” line item in the Apple Pay sheet.

var configuration = PaymentSheet.Configuration() configuration.merchantDisplayName = "My app, Inc."

UserInterfaceStyle

PaymentSheet automatically adapts to the user’s system-wide appearance settings (light & dark mode). If your app doesn’t support dark mode, you can set PaymentSheet.Configuration.style to alwaysLight or alwaysDark mode.

var configuration = PaymentSheet.Configuration() configuration.style = .alwaysLight
Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.
On this page
Install the SDK
Add a server endpoint
Integrate the payment sheet
Custom integration
Apple Pay
Google Pay
Card scanning
Customization