# Accept in-app payments

Build a customized payments integration in your iOS, Android, or React Native app using the Payment Element.

The Payment Element is a customizable component that renders a list of payment methods that you can add into any screen in your app. When customers interact with payment methods in the list, the component opens individual bottom sheets to collect payment details.

> #### Accounts v2 API support
> 
> The Payment Sheet doesn’t support *customer-configured Accounts* (Account configurations represent role-based functionality that you can enable for accounts, such as merchant, customer, or recipient). It only supports `Customer` objects.

# Collect and save a payment method


A SetupIntent flow allows you to save payment methods for future payments without creating a charge. In this integration, you render the Payment Element, create a *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method), and save the payment method in your app.

## Set up Stripe [Server-side] [Client-side]

### 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:

#### Ruby

```bash
# Available as a gem
sudo gem install stripe
```

```ruby
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
```

### Client-side 

The [Stripe iOS SDK](https://github.com/stripe/stripe-ios) is open source, [fully documented](https://stripe.dev/stripe-ios/index.html), and compatible with apps supporting iOS 13 or above.

#### Swift Package Manager

To install the SDK, follow these steps:

1. In Xcode, select **File** > **Add Package Dependencies…** and enter `https://github.com/stripe/stripe-ios-spm` as the repository URL.
2. Select the latest version number from our [releases page](https://github.com/stripe/stripe-ios/releases).
3. Add the **StripePaymentSheet** product to the [target of your app](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app).

#### CocoaPods

1. If you haven’t already, install the latest version of [CocoaPods](https://guides.cocoapods.org/using/getting-started.html).
2. If you don’t have an existing [Podfile](https://guides.cocoapods.org/syntax/podfile.html), run the following command to create one:
   ```bash
   pod init
   ```
3. Add this line to your `Podfile`:
   ```podfile
   pod 'StripePaymentSheet'
   ```
4. Run the following command:
   ```bash
   pod install
   ```
5. Don’t forget to use the `.xcworkspace` file to open your project in Xcode, instead of the `.xcodeproj` file, from here on out.
6. In the future, to update to the latest version of the SDK, run:
   ```bash
   pod update StripePaymentSheet
   ```

#### Carthage

1. If you haven’t already, install the latest version of [Carthage](https://github.com/Carthage/Carthage#installing-carthage).
2. Add this line to your `Cartfile`:
   ```cartfile
   github "stripe/stripe-ios"
   ```
3. Follow the [Carthage installation instructions](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos). Make sure to embed all of the required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking).
4. In the future, to update to the latest version of the SDK, run the following command:
   ```bash
   carthage update stripe-ios --platform ios
   ```

#### Manual Framework

1. Head to our [GitHub releases page](https://github.com/stripe/stripe-ios/releases/latest) and download and unzip **Stripe.xcframework.zip**.
2. Drag **StripePaymentSheet.xcframework** to the **Embedded Binaries** section of the **General** settings in your Xcode project. Make sure to select **Copy items if needed**.
3. Repeat step 2 for all required frameworks listed [here](https://github.com/stripe/stripe-ios/tree/master/StripePaymentSheet/README.md#manual-linking).
4. In the future, to update to the latest version of our SDK, repeat steps 1–3.

> For details on the latest SDK release and past versions, see the [Releases](https://github.com/stripe/stripe-ios/releases) page on GitHub. To receive notifications when a new release is published, [watch releases](https://help.github.com/en/articles/watching-and-unwatching-releases-for-a-repository#watching-releases-for-a-repository) for the repository.

You also need to set your [publishable key](https://dashboard.stripe.com/apikeys) so that the SDK can make API calls to Stripe. To get started, you can hardcode the publishable key on the client while you’re integrating, but fetch the publishable key from your server in production.

```swift
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/apikeys
STPAPIClient.shared.publishableKey = "<<YOUR_PUBLISHABLE_KEY>>"
```

## Enable payment methods

View your [payment methods settings](https://dashboard.stripe.com/settings/payment_methods) and enable the payment methods you want to support. You need at least one payment method enabled to create a *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method).

By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See [Payment method support](https://docs.stripe.com/payments/payment-methods/payment-method-support.md) for product and payment method support, and our [pricing page](https://stripe.com/pricing/local-payment-methods) for fees.

## Create a customer [Server-side]

To set up a payment method for future payments, you must attach it to an object that represents your customer. When your customer creates an account or has their first transaction with your business, create a [Customer](https://docs.stripe.com/api/customers/create.md) object.

```curl
curl -X POST https://api.stripe.com/v1/customers \
  -u "<<YOUR_SECRET_KEY>>:"
```

## Collect payment details [Client-side]

Place the Embedded Mobile Payment Element on the checkout page of your native mobile app. The element displays a list of payment methods and you can customize it to match your app’s look and feel.

When the customer taps the **Card** row, it opens a sheet where they can enter their payment method details. The button in the sheet says **Continue** by default and dismisses the sheet when tapped, which lets your customer finish the setup in your checkout.

![Payment Element](https://b.stripecdn.com/docs-statics-srv/assets/ios-embedded.b5867c116d537ffcb920dd80ebdfc741.png)
 

You can configure the button to immediately complete the setup instead of continuing. To do so, complete [this step](https://docs.stripe.com/payments/mobile/accept-payment-embedded.md#embedded-let-customer-pay-immediately) after following the guide.

#### UIKit

### Initialize the Payment Element

Call `create` to instantiate EmbeddedPaymentElement with a `EmbeddedPaymentElement.Configuration` and a [PaymentSheet.IntentConfiguration](https://github.com/stripe/stripe-ios/blob/master/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetIntentConfiguration.swift).

The Configuration object contains general-purpose configuration options for EmbeddedPaymentElement that don’t change between payments, like `returnURL`. The `IntentConfiguration` object contains details about the specific payment like the amount and currency, as well as a `confirmationTokenConfirmHandler` callback. For now, leave its implementation empty. After it successfully initializes, set its `presentingViewController` and `delegate` properties.

```swift
import StripePaymentSheet

class MyCheckoutVC: UIViewController {

    func createEmbeddedPaymentElement() async throws -> EmbeddedPaymentElement {
        let intentConfig = PaymentSheet.IntentConfiguration(
          mode: .setup(currency: "USD")
        ) { [weak self] confirmationToken in
          return await self?.handleConfirmationToken(confirmationToken)
        }
        var configuration = EmbeddedPaymentElement.Configuration()
        configuration.returnURL = "your-app://stripe-redirect" // Use the return url you set up in the previous step
        let embeddedPaymentElement = try await EmbeddedPaymentElement.create(intentConfiguration: intentConfig, configuration: configuration)
        embeddedPaymentElement.presentingViewController = self
        embeddedPaymentElement.delegate = self
        return embeddedPaymentElement
    }

    func handleConfirmationToken(_ confirmationToken: STPConfirmationToken) async throws -> String {
      // You'll implement this in the "Confirm the payment" section below
    }
}
```

### Add the Payment Element view

After EmbeddedPaymentElement successfully initializes, put its view in your checkout UI.

> The view must be contained within a scrollable view such as UIScrollView because it doesn’t have a fixed size and can change height after it initially renders.

```swift
class MyCheckoutVC: UIViewController {
    // ...
    private(set) var embeddedPaymentElement: EmbeddedPaymentElement?

    private lazy var checkoutButton: UIButton = {
        let checkoutButton = UIButton(type: .system)
        checkoutButton.backgroundColor = .systemBlue
        checkoutButton.layer.cornerRadius = 5.0
        checkoutButton.clipsToBounds = true
        checkoutButton.setTitle("Checkout", for: .normal)
        checkoutButton.setTitleColor(.white, for: .normal)
        checkoutButton.translatesAutoresizingMaskIntoConstraints = false
        checkoutButton.isEnabled = embeddedPaymentElement?.paymentOption != nil
        checkoutButton.addTarget(self, action: #selector(didTapConfirmButton), for: .touchUpInside)
        return checkoutButton
    }()
    // ...
    @objc func didTapConfirmButton() {
        // You'll implement this in the "Confirm the payment" section below
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        Task { @MainActor in
            do {
                // Create a UIScrollView
                let scrollView = UIScrollView()
                scrollView.translatesAutoresizingMaskIntoConstraints = false
                self.view.addSubview(scrollView)

	       // Create the Payment Element
                let embeddedPaymentElement = try await createEmbeddedPaymentElement()
                embeddedPaymentElement.delegate = self
                embeddedPaymentElement.presentingViewController = self
                self.embeddedPaymentElement = embeddedPaymentElement

                // Add its view to the scroll view
                scrollView.addSubview(embeddedPaymentElement.view)

	       // Add your own checkout button to the scroll view
                scrollView.addSubview(checkoutButton)

                // Set up layout constraints
                embeddedPaymentElement.view.translatesAutoresizingMaskIntoConstraints = false
                NSLayoutConstraint.activate([
                    scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                    scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                    scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                    scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),

                    embeddedPaymentElement.view.topAnchor.constraint(equalTo: scrollView.topAnchor),
                    embeddedPaymentElement.view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
                    embeddedPaymentElement.view.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
                    checkoutButton.topAnchor.constraint(equalTo: embeddedPaymentElement.view.bottomAnchor, constant: 4.0),
                    checkoutButton.leadingAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.leadingAnchor, constant: 4.0),
                    checkoutButton.trailingAnchor.constraint(equalTo: scrollView.safeAreaLayoutGuide.trailingAnchor, constant: -4.0),
                ])

            } catch {
                // Handle view not being added to view
            }
        }
    }
}
```

At this point you can run your app and see the Embedded Mobile Payment Element.

### Handle height changes

The EmbeddedPaymentElement’s view might grow or shrink in size, which can impact the layout of the view.

Handle height changes by implementing the `embeddedPaymentElementDidUpdateHeight` delegate method. EmbeddedPaymentElement’s view calls this method inside an animation block that updates its height. Your implementation is expected to call `setNeedsLayout()` and `layoutIfNeeded()` on the scroll view that contains the EmbeddedPaymentElement’s view to enable a smooth animation of the height change.

```swift
extension MyCheckoutVC: EmbeddedPaymentElementDelegate {
    func embeddedPaymentElementDidUpdateHeight(embeddedPaymentElement: StripePaymentSheet.EmbeddedPaymentElement) {
        // Handle layout appropriately
        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()
    }
}
```

We recommend that you test that your view properly responds to changes in height. To do this, call `testHeightChange()` on EmbeddedPaymentElement to simulate showing and hiding a mandate within the element. Make sure that after calling `testHeightChange()`, your scroll view adjusts smoothly.

```swift
class MyCheckoutVC: UIViewController {
    override func viewDidLoad() {
        // This is only for testing purposes:
        #if DEBUG
        Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in
            Task { @MainActor in
                self?.embeddedPaymentElement?.testHeightChange()
            }
        }
        #endif
    }
}
```

### (Optional) Display the selected payment option

If you need to access details about the customer’s selected payment option like a label (for example, “····4242”), image (for example, a VISA logo), or billing details to display in your UI, use the EmbeddedPaymentElement’s `paymentOption` property.

To be notified when the `paymentOption` changes, implement the `embeddedPaymentElementDidUpdatePaymentOption` delegate method.

```swift
extension MyCheckoutVC: EmbeddedPaymentElementDelegate {
  func embeddedPaymentElementDidUpdatePaymentOption(embeddedPaymentElement: EmbeddedPaymentElement) {
    print("The payment option changed: \(embeddedPaymentElement.paymentOption)")
    checkoutButton.isEnabled = embeddedPaymentElement.paymentOption != nil
  }
}
```

### (Optional) Update payment details

As the customer performs actions that change the payment details (for example, applying a discount code), update the `EmbeddedPaymentElement` instance to reflect the new values by calling the `update` method. Some payment methods, like Apple Pay and Google Pay, show the amount in the UI, so make sure it’s always accurate and up to date.

When the update call completes, update your UI. The update call might change the customer’s currently selected payment option.

```swift
extension MyCheckoutVC {
    func update() {
        Task { @MainActor in
            var updatedIntentConfig = oldIntentConfig
            // Update the currency
            updatedIntentConfig.mode = PaymentSheet.IntentConfiguration.Mode.setup(currency: "USD")

            let result = await embeddedPaymentElement?.update(intentConfiguration: updatedIntentConfig)
            switch result {
            case .canceled, nil:
                // Do nothing; this happens when a subsequent `update` call cancels this one
                break
            case .failed(let error):
                // Display error to user in an alert, let users retry
            case .succeeded:
                // Update your UI in case the payment option changed
            }
        }
    }
}
```

### Confirm the setup

When the customer taps the checkout button, call `embeddedPaymentElement.confirm()` to complete the setup. Be sure to disable user interaction during confirmation.

```swift
extension MyCheckoutVC {
    @objc func didTapConfirmButton() {
        Task { @MainActor in
            guard let embeddedPaymentElement else { return }
            self.view.isUserInteractionEnabled = false // Disable user interaction, show a spinner, and so on before calling confirm.
            let result = await embeddedPaymentElement.confirm()
            switch result {
            case .completed:
                // Setup completed - show a confirmation screen.
            case .failed(let error):
                self.view.isUserInteractionEnabled = true
                // Encountered an unrecoverable error. You can display the error to the user, log it, and so on.
            case .canceled:
                self.view.isUserInteractionEnabled = true
                // Customer canceled - you should probably do nothing.
                break
            }
        }
    }
}
```

Next, implement the `confirmationTokenConfirmHandler` callback you passed to `PaymentSheet.IntentConfiguration` earlier to send a request to your server. Your server creates a SetupIntent and returns its client secret. For information about this process, see [Create a SetupIntent](https://docs.stripe.com/payments/mobile/accept-payment-embedded.md#submit-setup).

When the request returns, return your server response’s client secret or throw an error. The EmbeddedPaymentElement confirms the PaymentIntent using the client secret or displays the localized error message in its UI (either [errorDescription](https://developer.apple.com/documentation/foundation/localizederror/2946895-errordescription) or [localizedDescription](https://developer.apple.com/documentation/foundation/nserror/1414418-localizeddescription)). After confirmation completes, EmbeddedPaymentElement isn’t usable. Instead, direct the user to a receipt screen or something similar.

```swift
extension MyCheckoutVC {
    func handleConfirmationToken(_ confirmationToken: STPConfirmationToken) async throws -> String {
        // Make a request to your own server. Pass `confirmationToken.stripeId` if using server-side confirmation, and return the client secret or throw an error.
        let myServerClientSecret = try await fetchIntentClientSecret(...)
    }
}
```

#### SwiftUI

### Initialize the Payment Element

Call `load` to load EmbeddedPaymentElementViewModel with a `EmbeddedPaymentElement.Configuration` and a [PaymentSheet.IntentConfiguration](https://github.com/stripe/stripe-ios/blob/master/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetIntentConfiguration.swift).

The Configuration object contains general-purpose configuration options for EmbeddedPaymentElement that don’t change between payments, like `returnURL`. The `IntentConfiguration` object contains details about the specific payment like the amount and currency, as well as a `confirmationTokenConfirmHandler` callback. For now, leave its implementation empty.

```swift
import SwiftUI
import StripePaymentSheet

struct MyEmbeddedCheckoutView: View {
    // Store an `EmbeddedPaymentElementViewModel` as a `@StateObject`
    @StateObject var embeddedViewModel = EmbeddedPaymentElementViewModel()

    var body: some View {
        ScrollView {
            // Empty scroll view for now
        }
        .task {
            do {
                if !embeddedViewModel.isLoaded {
                    // Load the view model with your configuration
                    try await loadEmbeddedViewModel()
                }
            } catch {
                // On load failure, implement retry logic (automatic retry or user-triggered through UI).
            }
        }
    }

    private func loadEmbeddedViewModel() async throws {
        let intentConfiguration = PaymentSheet.IntentConfiguration(
          mode: .setup(currency: "USD")
        ) { confirmationToken in
          try await self.handleConfirmationToken(confirmationToken)
        }
        var configuration = EmbeddedPaymentElement.Configuration()
        configuration.returnURL = "your-app://stripe-redirect" // Use the return url you set up in the previous step
        try await embeddedViewModel.load(intentConfiguration: intentConfiguration, configuration: configuration)
    }

    func handleConfirmationToken(_ confirmationToken: STPConfirmationToken) async throws -> String {
      // You'll implement this in the "Confirm the payment" section below
    }
}
```

### Add the Payment Element view

After EmbeddedPaymentElementViewModel successfully loads, add EmbeddedPaymentElementView in your checkout UI.

> The view must be contained within a scrollable view such as ScrollView because it doesn’t have a fixed size and can change height after it initially renders.

```swift
struct MyEmbeddedCheckoutView: View {
    var body: some View {
        ScrollView {
	      // isLoaded becomes true only after a successful call to `embeddedViewModel.load()`
            if embeddedViewModel.isLoaded {
                EmbeddedPaymentElementView(viewModel: embeddedViewModel)
            }
        }
    }
}
```

At this point you can run your app and see the Embedded Mobile Payment Element.

### Handle height changes

The EmbeddedPaymentElementView might grow or shrink in size, which might impact the layout of the view. The EmbeddedPaymentElementView handles this automatically when inside a ScrollView.

We recommend that you test that your view properly responds to changes in height. To do this, call `testHeightChange()` on EmbeddedPaymentElementViewModel to simulate showing and hiding a mandate within the element. Make sure that after calling `testHeightChange()`, your scroll view adjusts smoothly.

```swift
struct MyEmbeddedCheckoutView: View {
    var body: some View {
        ScrollView {
            if embeddedViewModel.isLoaded {
                EmbeddedPaymentElementView(viewModel: embeddedViewModel)

                // For testing only
                #if DEBUG
                Button("Test height change") {
                    embeddedViewModel.testHeightChange()
                }
                #endif
            }
        }
    }
}
```

### (Optional) Display the selected payment option

If you need to access details about the customer’s selected payment option like a label (for example, “····4242”), image (for example, a VISA logo), or billing details to display in your UI, use the EmbeddedPaymentElementViewModel’s `paymentOption` property. When the customer selects a payment method that opens a form sheet, the payment option updates after they tap **Continue** in the sheet.

```swift
struct MyEmbeddedCheckoutView: View {
    var body: some View {
        ScrollView {
            if embeddedViewModel.isLoaded {
                // ...

                // A real integration probably wouldn't show the selected payment option on the same screen as the embedded payment element. We display it as an example.
                if let paymentOption = embeddedViewModel.paymentOption {
                    HStack {
                        Image(uiImage: paymentOption.image)
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(height: 30)
                        Text(paymentOption.label)
                        Spacer()
                    }
                    .padding()
                }
            }
        }
    }
}
```

### (Optional) Update payment details

As the customer performs actions that change the payment details (for example, applying a discount code), update the `EmbeddedPaymentElementViewModel` instance to reflect the new values by calling the `update` method. Some payment methods, like Apple Pay and Google Pay, show the amount in the UI, so make sure it’s always accurate and up to date.

When the update completes, the update might have changed the customer’s currently selected payment option.

```swift
extension MyEmbeddedCheckoutView {
    func update() {
        Task { @MainActor in
            var updatedIntentConfig = oldIntentConfig
            updatedIntentConfig.mode = PaymentSheet.IntentConfiguration.Mode.setup(currency: "USD")

            let result = await embeddedViewModel.update(intentConfiguration: updatedIntentConfig)
            switch result {
            case .canceled:
                // Do nothing; this happens when a subsequent `update` call cancels this one
                break
            case .failed(let error):
                // Display error to user in an alert, let users retry
            case .succeeded:
                // Update your UI in case the payment option changed
            }
        }
    }
}
```

### Confirm the setup

When the customer taps the checkout button, call `embeddedViewModel.confirm()` to complete the setup. Be sure to disable user interaction during confirmation.

```swift
extension MyEmbeddedCheckoutView {
    func didTapConfirmButton() {
        Task { @MainActor in
            // Be sure to disable user interaction during confirm (not shown in this example)
            let result = await embeddedViewModel.confirm()
            switch result {
            case .completed:
                // Setup completed - show a confirmation screen.
            case .failed(let error):
                // Encountered an unrecoverable error. Re-enable user interaction, display the error to the user, log it, and so on.
            case .canceled:
                // Customer canceled - re-enable user interaction and let them try again.
                break
            }
        }
    }
}
```

Next, implement the `confirmationTokenConfirmHandler` callback you passed to `PaymentSheet.IntentConfiguration` earlier to send a request to your server. Your server creates a SetupIntent and returns its client secret. For information about this process, see [Create a SetupIntent](https://docs.stripe.com/payments/mobile/accept-payment-embedded.md#submit-setup).

Return your server response’s client secret or throw an error. The EmbeddedPaymentElement confirms the PaymentIntent using the client secret or displays the localized error message in its UI (either [errorDescription](https://developer.apple.com/documentation/foundation/localizederror/2946895-errordescription) or [localizedDescription](https://developer.apple.com/documentation/foundation/nserror/1414418-localizeddescription)). After confirmation completes, EmbeddedPaymentElement isn’t usable. Instead, direct the user to a receipt screen or something similar.

```swift
extension MyEmbeddedCheckoutView {
    func handleConfirmationToken(_ confirmationToken: STPConfirmationToken) async throws -> String {
        // Make a request to your own server. Pass confirmationToken.stripeId if using server-side confirmation.
        // Return the client secret or throw an error
        return try await MyAPIClient.shared.createIntent(confirmationTokenId: confirmationToken.stripeId)
    }
}
```

## Optional: Clear the selected payment option

If you have payment options external to EmbeddedPaymentElement, you might need to clear the selected payment option. To do this, use the `clearPaymentOption` API to deselect the selected payment option.

#### UIKit

```swift
extension MyCheckoutVC: UIViewController {
    func deselectPaymentMethod() {
        embeddedPaymentElement?.clearPaymentOption()
    }
}
```

#### SwiftUI

```swift
@available(iOS 15.0, *)
extension MyEmbeddedCheckoutView {
    func deselectPaymentMethod() {
        embeddedViewModel.clearPaymentOption()
    }
}
```

## Optional: Display the mandate yourself

By default, the Embedded Mobile Payment Element displays mandates and legal disclaimers to ensure regulatory compliance. This text must be located close to your buy button. If necessary, disable its display in the view and display it yourself instead.

> Your integration must display the mandate text to be compliant. Make sure URLs in the text can be opened by using a UITextView or something similar.

#### UIKit

```swift
var configuration = EmbeddedPaymentElement.Configuration(...)
configuration.embeddedViewDisplaysMandateText = true

...

let mandateTextView = UITextView()
mandateTextView.attributedText = embeddedPaymentElement.paymentOption.mandateText
```

#### SwiftUI

```swift
var configuration = EmbeddedPaymentElement.Configuration(...)
configuration.embeddedViewDisplaysMandateText = true

...

if let attributedText = embeddedViewModel.paymentOption?.mandateText {
  Text(AttributedString(attributedText))
}
```

## Optional: Let the customer confirm setup immediately in the sheet

To configure the button in the form sheet to immediately confirm setup, set `formSheetAction` on your `EmbeddedPaymentElement.Configuration` object.

The completion block executes with the result of the setup after the sheet dismisses. The embedded UI isn’t usable after setup completes, so we recommend that your implementation directs the user to a different screen, such as a receipt screen.

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.formSheetAction = .confirm(completion: { result in
  switch result {
  case .completed:
    // Setup completed. You can for example, show a confirmation screen.
    print("Completed")
  case .failed(let error):
    // Encountered an unrecoverable error. You can display the error to the user, log it, etc.
    print(error)
  case .canceled:
    // Customer canceled - you should probably do nothing.
    break
  }
})
```

## Create a SetupIntent [Server-side]

On your server, create a *SetupIntent* (The Setup Intents API lets you build dynamic flows for collecting payment method details for future payments. It tracks the lifecycle of a payment setup flow and can trigger additional authentication steps if required by law or by the payment method). You can manage payment methods from the [Dashboard](https://dashboard.stripe.com/settings/payment_methods). Stripe evaluates payment method restrictions and other parameters to determine the list of supported payment methods.

If the call succeeds, return the SetupIntent *client secret* (The client secret is a unique key returned from Stripe as part of a PaymentIntent. This key lets the client access important fields from the PaymentIntent (status, amount, currency) while hiding sensitive ones (metadata, customer)). If the call fails, [handle the error](https://docs.stripe.com/error-handling.md) and return an error message with a brief explanation for your customer.

> Verify that all IntentConfiguration properties match your SetupIntent (for example, [usage](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-usage)).

#### Ruby

```ruby
require 'stripe'
# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
client = Stripe::StripeClient.new('<<YOUR_SECRET_KEY>>')

post '/create-intent' do
  data = JSON.parse request.body.read
  params = {
    customer: ..., # The Customer ID you previously created
    automatic_payment_methods: {enabled: true},
  }
  begin
    intent = client.v1.setup_intents.create(params)
    {client_secret: intent.client_secret}.to_json
  rescue Stripe::StripeError => e
    {error: e.error.message}.to_json
  end
end
```

## Set up a return URL [Client-side]

The customer might navigate away from your app to authenticate (for example, in Safari or their banking app). To allow them to automatically return to your app after authenticating, [configure a custom URL scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) and set up your app delegate to forward the URL to the SDK. Stripe doesn’t support [universal links](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content).

#### SceneDelegate

#### Swift

```swift
// This method handles opening custom URL schemes (for example, "your-app://stripe-redirect")
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else {
        return
    }
    let stripeHandled = StripeAPI.handleURLCallback(with: url)
    if (!stripeHandled) {
        // This was not a Stripe url – handle the URL normally as you would
    }
}

```

#### AppDelegate

#### Swift

```swift
// This method handles opening custom URL schemes (for example, "your-app://stripe-redirect")
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    let stripeHandled = StripeAPI.handleURLCallback(with: url)
    if (stripeHandled) {
        return true
    } else {
        // This was not a Stripe url – handle the URL normally as you would
    }
    return false
}
```

#### SwiftUI

#### Swift

```swift

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      Text("Hello, world!")
        .onOpenURL { incomingURL in
          let stripeHandled = StripeAPI.handleURLCallback(with: incomingURL)
          if (!stripeHandled) {
            // This was not a Stripe url – handle the URL normally as you would
          }
        }
    }
  }
}
```

Additionally, set the [returnURL](https://github.com/stripe/stripe-ios/blob/aa3234a7fafde98c9203b6ed77e0278c04310eb0/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L70) on your [EmbeddedPaymentElement.Configuration](https://github.com/stripe/stripe-ios/blob/aa3234a7fafde98c9203b6ed77e0278c04310eb0/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L12) object to the URL for your app.

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.returnURL = "your-app://stripe-redirect"
```

## Charge the saved payment method later [Server-side]

> `bancontact` and `ideal` are one-time payment methods by default. When set up for future usage, they generate a `sepa_debit` reusable payment method type so you need to use `sepa_debit` to query for saved payment methods.

To find a payment method to charge, list the payment methods associated with your customer. This example lists cards, but you can list any supported [type](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-type).

> #### Use the Accounts v2 API to represent customers
> 
> The Accounts v2 API is generally available for Connect users, and in public preview for other Stripe users. If you’re part of the Accounts v2 preview, you need to specify a [preview version](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning) in your code.
> 
> To join the Accounts v2 preview, go to [Account previews and features](https://dashboard.stripe.com/settings/previews) in your Dashboard and enable **Reusable payment methods for Global Payouts**.
> 
> For most use cases, we recommend [modeling your customers as customer-configured Account objects](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md) instead of using [Customer](https://docs.stripe.com/api/customers.md) objects.

#### Accounts v2

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d type=card
```

#### Customers v1

```curl
curl -G https://api.stripe.com/v1/payment_methods \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "customer={{CUSTOMER_ID}}" \
  -d type=card
```

When you’re ready to charge your customer *off-session* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information), use the ID of the `Customer` or customer-configured `Account` and the `PaymentMethod` ID to 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](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-off_session) to true to indicate that the customer isn’t in your checkout flow to respond to any authentication requests. If, during your checkout flow, a partner (such as a card issuer or bank) requests authentication, Stripe requests exemptions using customer information from a previous *on-session* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method) transaction. If the conditions for exemption aren’t met, the `PaymentIntent` might throw an error.
- Set [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) to true to trigger confirmation immediately when the `PaymentIntent` is created.
- Set [payment_method](https://docs.stripe.com/api.md#create_payment_intent-payment_method) to the `PaymentMethod`’s ID.
- Depending on how you represent customers in your integration, set either [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) to the ID of the customer-configured `Account` or [customer](https://docs.stripe.com/api.md#create_payment_intent-customer) to the ID of the `Customer`.

#### Accounts v2

```curl
curl https://api.stripe.com/v1/payment_intents \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d amount=1099 \
  -d currency=usd \
  -d "automatic_payment_methods[enabled]=true" \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}" \
  -d payment_method={{PAYMENT_METHOD_ID}} \
  --data-urlencode "return_url=https://example.com/order/123/complete" \
  -d off_session=true \
  -d confirm=true
```

#### Customers v1

```curl
curl https://api.stripe.com/v1/payment_intents \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d amount=1099 \
  -d currency=usd \
  -d "automatic_payment_methods[enabled]=true" \
  -d "customer={{CUSTOMER_ID}}" \
  -d payment_method={{PAYMENT_METHOD_ID}} \
  --data-urlencode "return_url=https://example.com/order/123/complete" \
  -d off_session=true \
  -d confirm=true
```

## Test the integration

#### Cards

| Card number         | Scenario                                                                                                                                                                                                                                                                                      | How to test                                                                                           |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| 4242424242424242    | The card payment succeeds and doesn’t require authentication.                                                                                                                                                                                                                                 | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. |
| 4000002500003155    | The card payment requires *authentication* (Strong Customer Authentication (SCA) is a regulatory requirement in effect as of September 14, 2019, that impacts many European online payments. It requires customers to use two-factor authentication like 3D Secure to verify their purchase). | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. |
| 4000000000009995    | The card is declined with a decline code like `insufficient_funds`.                                                                                                                                                                                                                           | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. |
| 6205500000000000004 | The UnionPay card has a variable length of 13-19 digits.                                                                                                                                                                                                                                      | Fill out the credit card form using the credit card number with any expiration, CVC, and postal code. |

#### Bank redirects

| Payment method    | Scenario                                                                                                                                                                                        | How to test                                                                                                                                              |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bancontact, iDEAL | Your customer fails to authenticate on the redirect page for a redirect-based and immediate notification payment method.                                                                        | Choose any redirect-based payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page. |
| Pay by Bank       | Your customer successfully pays with a redirect-based and [delayed notification](https://docs.stripe.com/payments/payment-methods.md#payment-notification) payment method.                      | Choose the payment method, fill out the required details, and confirm the payment. Then click **Complete test payment** on the redirect page.            |
| Pay by Bank       | Your customer fails to authenticate on the redirect page for a redirect-based and delayed notification payment method.                                                                          | Choose the payment method, fill out the required details, and confirm the payment. Then click **Fail test payment** on the redirect page.                |
| BLIK              | BLIK payments fail in a variety of ways—immediate failures (for example, the code is expired or invalid), delayed errors (the bank declines) or timeouts (the customer didn’t respond in time). | Use email patterns to [simulate the different failures.](https://docs.stripe.com/payments/blik/accept-a-payment.md#simulate-failures)                    |

#### Bank debits

| Payment method    | Scenario                                                                                          | How to test                                                                                                                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SEPA Direct Debit | Your customer successfully pays with SEPA Direct Debit.                                           | Fill out the form using the account number `AT321904300235473204`. The confirmed PaymentIntent initially transitions to processing, then transitions to the succeeded status three minutes later. |
| SEPA Direct Debit | Your customer’s payment intent status transitions from `processing` to `requires_payment_method`. | Fill out the form using the account number `AT861904300235473202`.                                                                                                                                |

See [Testing](https://docs.stripe.com/testing.md) for additional information to test your integration.

## Enable card scanning

To enable card scanning support for iOS, set the `NSCameraUsageDescription` (**Privacy - Camera Usage Description**) in the `Info.plist` of your application, and provide a reason for accessing the camera (for example, “To scan cards”).

## Optional: Enable saved cards [Server-side] [Client-side]

`EmbeddedPaymentElement` can allow the customer to save their card and can include the customer’s saved cards in available payment methods. The customer must have an associated customer-configured [Account](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer) object or a [Customer](https://docs.stripe.com/api/customers/create.md) object on your server. To enable a checkbox that allows the customer to save their card, create a [CustomerSession](https://docs.stripe.com/api/customer_sessions.md), with `payment_method_save` set to `enabled`.

#### Accounts v2

```javascript
const stripe = require('stripe')('sk_test_your_secret_key');

app.post('/mobile-payment-element', async (req, res) => {
  // Use an existing Account ID if this is a returning customer.
  const customer_account = await stripe.v2.core.accounts.create();
  const customerSession = await stripe.customerSessions.create({
    customer_account: customer_account.id,
    components: {
      mobile_payment_element: {
        enabled: true,
        features: {
          payment_method_save: 'enabled',
          payment_method_redisplay: 'enabled',
          payment_method_remove: 'enabled'
        }
      },
    },
  });

  res.json({
    customerSessionClientSecret: customerSession.client_secret,
    customer_account: customer_account.id,
  });
});
```

Next, configure EmbeddedPaymentElement with the customer’s ID and the CustomerSession client secret.

#### UIKit

```swift
@_spi(CustomerSessionBetaAccess) import StripePaymentSheet

var configuration = EmbeddedPaymentElement.Configuration()
configuration.customer = .init(id: customerAccountId, customerSessionClientSecret: customerSessionClientSecret)

self.embeddedPaymentElement = try await EmbeddedPaymentElement.create(..., configuration: configuration)
```

#### SwiftUI

```swift
@_spi(CustomerSessionBetaAccess) import StripePaymentSheet

var configuration = EmbeddedPaymentElement.Configuration()
configuration.customer = .init(id: customerAccountId, customerSessionClientSecret: customerSessionClientSecret)

try await embeddedViewModel.load(..., configuration: configuration)
```

#### Customers v1

```javascript
const stripe = require('stripe')('sk_test_your_secret_key');

app.post('/mobile-payment-element', async (req, res) => {
  // Use an existing Customer ID if this is a returning customer.
  const customer = await stripe.customers.create();
  const customerSession = await stripe.customerSessions.create({
    customer: customer.id,
    components: {
      mobile_payment_element: {
        enabled: true,
        features: {
          payment_method_save: 'enabled',
          payment_method_redisplay: 'enabled',
          payment_method_remove: 'enabled'
        }
      },
    },
  });

  res.json({
    customerSessionClientSecret: customerSession.client_secret,
    customer: customer.id,
  });
});
```

Next, configure EmbeddedPaymentElement with the customer’s ID and the CustomerSession client secret.

#### UIKit

```swift
@_spi(CustomerSessionBetaAccess) import StripePaymentSheet

var configuration = EmbeddedPaymentElement.Configuration()
configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret)

self.embeddedPaymentElement = try await EmbeddedPaymentElement.create(..., configuration: configuration)
```

#### SwiftUI

```swift
@_spi(CustomerSessionBetaAccess) import StripePaymentSheet

var configuration = EmbeddedPaymentElement.Configuration()
configuration.customer = .init(id: customerId, customerSessionClientSecret: customerSessionClientSecret)

try await embeddedViewModel.load(..., configuration: configuration)
```

## Optional: Allow delayed payment methods [Client-side]

*Delayed payment methods* (A payment method that can't immediately return payment status when a customer attempts a transaction (for example, ACH debits). Businesses commonly hold an order in a pending state until payment is successful with these payment methods) don’t guarantee that you’ll receive funds from your customer at the end of the checkout either because they take time to settle (for example, US Bank Accounts, SEPA Debit, iDEAL, and Bancontact) or because they require customer action to complete (for example, OXXO, Konbini, and Boleto).

By default, EmbeddedPaymentElement doesn’t display delayed payment methods. To opt in, set `allowsDelayedPaymentMethods` to true in your `EmbeddedPaymentElement.Configuration`. This step alone doesn’t activate any specific payment methods; rather, it indicates that your app is able to handle them. For example, although OXXO is currently not supported by EmbeddedPaymentElement, if it becomes supported and you’ve updated to the latest SDK version, your app will be able to display OXXO as a payment option without additional integration changes.

#### UIKit

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.allowsDelayedPaymentMethods = true

self.embeddedPaymentElement = try await EmbeddedPaymentElement.create(..., configuration: configuration)
```

#### SwiftUI

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.allowsDelayedPaymentMethods = true

try await embeddedViewModel.load(..., configuration: configuration)
```

If the customer successfully uses one of these delayed payment methods in EmbeddedPaymentElement, the payment result returned is `.completed`.

## Optional: Enable Apple Pay

> If your checkout screen has a dedicated **Apple Pay** button, follow the [Apple Pay guide](https://docs.stripe.com/apple-pay.md#present-payment-sheet) and use `ApplePayContext` to collect payment from your **Apple Pay** button. You can use `EmbeddedPaymentElement` to handle other payment method types.

### Register for an Apple Merchant ID

Obtain an Apple Merchant ID by [registering for a new identifier](https://developer.apple.com/account/resources/identifiers/add/merchant) on the Apple Developer website.

Fill out the form with a description and identifier. Your description is for your own records and you can modify it in the future. Stripe recommends using the name of your app as the identifier (for example, `merchant.com.{{YOUR_APP_NAME}}`).

### Create a new Apple Pay certificate

Create a certificate for your app to encrypt payment data.

Go to the [iOS Certificate Settings](https://dashboard.stripe.com/settings/ios_certificates) in the Dashboard, click **Add new application**, and follow the guide.

Download a Certificate Signing Request (CSR) file to get a secure certificate from Apple that allows you to use Apple Pay.

One CSR file must be used to issue exactly one certificate. If you switch your Apple Merchant ID, you must go to the [iOS Certificate Settings](https://dashboard.stripe.com/settings/ios_certificates) in the Dashboard to obtain a new CSR and certificate.

### Integrate with Xcode

Add the Apple Pay capability to your app. In Xcode, open your project settings, click the **Signing & Capabilities** tab, and add the **Apple Pay** capability. You might be prompted to log in to your developer account at this point. Select the merchant ID you created earlier, and your app is ready to accept Apple Pay.
![](https://b.stripecdn.com/docs-statics-srv/assets/xcode.a701d4c1922d19985e9c614a6f105bf1.png)

Enable the Apple Pay capability in Xcode

### Add Apple Pay

#### One-time payment

To add Apple Pay to EmbeddedPaymentElement, set [applePay](https://github.com/stripe/stripe-ios/blob/8be959abc141e360080efa88980afb325737a935/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L28) after initializing `EmbeddedPaymentElement.Configuration` with your Apple merchant ID and your business’s [country code](https://dashboard.stripe.com/settings/account).

#### iOS (Swift)

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

#### Recurring payments

To add Apple Pay to EmbeddedPaymentElement, set [applePay](https://github.com/stripe/stripe-ios/blob/8be959abc141e360080efa88980afb325737a935/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L28) after initializing `EmbeddedPaymentElement.Configuration` with your Apple merchant ID and your business’s [country code](https://dashboard.stripe.com/settings/account).

Per [Apple’s guidelines](https://developer.apple.com/design/human-interface-guidelines/apple-pay#Supporting-subscriptions) for recurring payments, you must also set additional attributes on the `PKPaymentRequest`. Add a handler in [ApplePayConfiguration.paymentRequestHandlers](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/paymentrequesthandler) to configure the [PKPaymentRequest.paymentSummaryItems](https://developer.apple.com/documentation/passkit/pkpaymentrequest/1619231-paymentsummaryitems) with the amount you intend to charge (for example, 9.95 USD a month).

You can also adopt [merchant tokens](https://developer.apple.com/apple-pay/merchant-tokens/) by setting the `recurringPaymentRequest` or `automaticReloadPaymentRequest` properties on the `PKPaymentRequest`.

To learn more about how to use recurring payments with Apple Pay, see [Apple’s PassKit documentation](https://developer.apple.com/documentation/passkit/pkpaymentrequest).

#### iOS (Swift)

```swift
let customHandlers = EmbeddedPaymentElement.ApplePayConfiguration.Handlers(
    paymentRequestHandler: { request in
        // PKRecurringPaymentSummaryItem is available on iOS 15 or later
        if #available(iOS 15.0, *) {
            let billing = PKRecurringPaymentSummaryItem(label: "My Subscription", amount: NSDecimalNumber(string: "59.99"))

            // Payment starts today
            billing.startDate = Date()

            // Payment ends in one year
            billing.endDate = Date().addingTimeInterval(60 * 60 * 24 * 365)

            // Pay once a month.
            billing.intervalUnit = .month
            billing.intervalCount = 1

            // recurringPaymentRequest is only available on iOS 16 or later
            if #available(iOS 16.0, *) {
                request.recurringPaymentRequest = PKRecurringPaymentRequest(paymentDescription: "Recurring",
                                                                            regularBilling: billing,
                                                                            managementURL: URL(string: "https://my-backend.example.com/customer-portal")!)
                request.recurringPaymentRequest?.billingAgreement = "You'll be billed $59.99 every month for the next 12 months. To cancel at any time, go to Account and click 'Cancel Membership.'"
            }
            request.paymentSummaryItems = [billing]
            request.currencyCode = "USD"
        } else {
            // On older iOS versions, set alternative summary items.
            request.paymentSummaryItems = [PKPaymentSummaryItem(label: "Monthly plan starting July 1, 2022", amount: NSDecimalNumber(string: "59.99"), type: .final)]
        }
        return request
    }
)
var configuration = EmbeddedPaymentElement.Configuration()
configuration.applePay = .init(merchantId: "merchant.com.your_app_name",
                                merchantCountryCode: "US",
                                customHandlers: customHandlers)
```

### Order tracking

To add [order tracking](https://developer.apple.com/design/human-interface-guidelines/technologies/wallet/designing-order-tracking) information in iOS 16 or later, configure an [authorizationResultHandler](https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/applepayconfiguration/handlers/authorizationresulthandler) in your `PaymentSheet.ApplePayConfiguration.Handlers`. Stripe calls your implementation after the payment is complete, but before iOS dismisses the Apple Pay sheet.

In your `authorizationResultHandler` implementation, fetch the order details from your server for the completed order. Add the details to the provided [PKPaymentAuthorizationResult](https://developer.apple.com/documentation/passkit/pkpaymentauthorizationresult) and return the modified result.

To learn more about order tracking, see [Apple’s Wallet Orders documentation](https://developer.apple.com/documentation/walletorders).

#### iOS (Swift)

```swift
let customHandlers = PaymentSheet.ApplePayConfiguration.Handlers(
    authorizationResultHandler: { result in
      do {
        // Fetch the order details from your service
        let myOrderDetails = try await MyAPIClient.shared.fetchOrderDetails(orderID: orderID)
        result.orderDetails = PKPaymentOrderDetails(
          orderTypeIdentifier: myOrderDetails.orderTypeIdentifier, // "com.myapp.order"
          orderIdentifier: myOrderDetails.orderIdentifier, // "ABC123-AAAA-1111"
          webServiceURL: myOrderDetails.webServiceURL, // "https://my-backend.example.com/apple-order-tracking-backend"
          authenticationToken: myOrderDetails.authenticationToken) // "abc123"
        // Return your modified PKPaymentAuthorizationResult
        return result
      } catch {
        return PKPaymentAuthorizationResult(status: .failure, errors: [error])
      }
    }
)
var configuration = EmbeddedPaymentElement.Configuration()
configuration.applePay = .init(merchantId: "merchant.com.your_app_name",
                               merchantCountryCode: "US",
                               customHandlers: customHandlers)
```

## Optional: Customize the element

All customization is configured through the [EmbeddedPaymentElement.Configuration](https://github.com/stripe/stripe-ios/blob/8be959abc141e360080efa88980afb325737a935/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L12) object.

### Appearance

Customize colors, fonts, and so on to match the look and feel of your app by using the [appearance API](https://docs.stripe.com/elements/appearance-api/embedded-mobile.md?platform=ios).

### Collect users addresses

Collect local and international shipping or billing addresses from your customers using the [Address Element](https://docs.stripe.com/elements/address-element.md?platform=ios).

### Merchant display name

Specify a customer-facing business name by setting [merchantDisplayName](https://github.com/stripe/stripe-ios/blob/8be959abc141e360080efa88980afb325737a935/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L66). By default, this is your app’s name.

#### Swift

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.merchantDisplayName = "My app, Inc."
```

### Dark mode

`EmbeddedPaymentElement` automatically adapts to the user’s system-wide appearance settings (light and dark mode). If your app doesn’t support dark mode, you can set [style](https://github.com/stripe/stripe-ios/blob/8be959abc141e360080efa88980afb325737a935/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElementConfiguration.swift#L51) to `alwaysLight` or `alwaysDark` mode.

```swift
var configuration = EmbeddedPaymentElement.Configuration()
configuration.style = .alwaysLight
```

