Processing payments using Stripe SDK iOS
Tags: stripe, swift, ios, paymentgateway
Published: 2023-02-26 05:15:19

---
title: Processing payments using Stripe SDK iOS
description: This guide explains how to install and set up Stripe SDK on your iOS application.
published: true
date: 2023-02-09 22:10:33 UTC
tags: stripe, Swift, iOS, paymentgateway
canonical_url: https://blog.shivammaggu.com/processing-payments-using-stripe-sdk-ios
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xijeeez1whq80ioykatw.png
---

This guide explains how to install and set up Stripe SDK on your iOS application.

## Table of Contents
- [Aim](#aim)
- [Minimum iOS Deployment Version](#minimum-ios-deployment-version)
- [Stripe Frameworks](#stripe-frameworks)
- [Requirements](#requirements)
- [Proof of Concept](#proof-of-concept)
- [Setup](#setup)
   - [Adding the Stripe dependency](#adding-the-stripe-dependency)
   - [Getting started with Stripe Developers Dashboard](#getting-started-with-stripe-developers-dashboard)
   - [Setup Stripe in your iOS App](#setup-stripe-in-your-ios-app)
   - [Address collection](#address-collection)
   - [Enable card scanning](#enable-card-scanning)
   - [Process payments using Apple Pay](#process-payments-using-apple-pay)
   - [Return to the app automatically after external authentication](#return-to-the-app-automatically-after-external-authentication)
   - [Clear cookies on logout](#clear-cookies-on-logout)
- [FAQ](#faq)
- [Resources](#resources)

## Aim

Open the inbuilt Address and Payment Sheet of Stripe and start accepting payments from your customer.

## Minimum iOS Deployment Version

12.0

## Stripe Frameworks

1. Stripe (22.8.4)

2. StripeApplePay (22.8.4)

3. StripeCore (22.8.4)

4. StripeUICore (22.8.4)

## Requirements

1. MacBook / MacOS

2. CocoaPods installed on your system

3. Xcode

4. Terminal

## Proof of Concept

iOS project and test backend for processing payments with Stripe SDK.

{% github https://github.com/shivammaggu/payments-using-stripe %}

## Setup

### Adding the Stripe dependency

- Open **Terminal** in the project directory and do `pod init`.

- Open the newly created `Podfile` and set the iOS version to _12.0._

```

 # Uncomment the next line to define a global platform for your project
 platform :ios, '12.0'

```

- Add the **Stripe** dependency to the `Podfile`.

```

 target 'payments with stripe' do
   # Comment the next line if you don't want to use dynamic frameworks
   use_frameworks!

   # Pods for payments with stripe

   pod 'Stripe'

 end

```

- Save the `Podfile` and do a `pod install` on the **Terminal**. The following dependencies showed be installed.

```

pod install

Analyzing dependencies
Downloading dependencies
Installing Stripe (22.8.4)
Installing StripeApplePay (22.8.4)
Installing StripeCore (22.8.4)
Installing StripeUICore (22.8.4)
Generating Pods project
Integrating client project

```

- Close the `payments with stripe.xcodeproj` and open `payments with stripe.xcworkspace`.

- Select a simulator and run the project. The project should run successfully with a blank screen.

### Getting started with Stripe Developers Dashboard

> This process should be done once. All the teams will use the same Dashboard. (Backend, iOS, Android etc.)

1. Go to [stripe.com](http://stripe.com) and click on **start now**.

2. Follow the steps as directed by the website to complete the registration process.

3. Complete the email verification and set up your business details for which payments will be accepted by Stripe.

4. On the [Stripe Dashboard](https://dashboard.stripe.com/apikeys), you should be able to see your Publishable key and Secret key for both test mode and live mode.

   1. The _publishable key_ is used on the client side such as in iOS, android or web apps.

   2. The _secret key_ is used on the server side. **(Secret key should not be stored on client-facing apps.)**

### Setup Stripe in your iOS App

- Open `AppDelegate.swift` and add the **Publishable key** inside the `didFinishLaunchingWithOptions` method. The publishable key can be retrieved from the Stripe Developers Dashboard.

```

  StripeAPI.defaultPublishableKey = "Insert your key here"

```

> Use the test mode keys during the testing and development phase, and the live mode keys when publishing the app.

- We need to hit a POST API to create the payment intent and in return receive the following data. This data is used to initialize the `customer`, Stripe SDK and the `PaymentSheet`.

  - `customerId`

  - `ephemeralKey`

  - `paymentIntent`

  - `publishableKey`

> Refer to `CourseCheckoutViewModel` in the Proof of Concept example on GitHub.

```
// Creates a payment intent for the customer and fetches the important keys and id's for processing a payment

func fetchPaymentIntent(completion: @escaping ((Bool, String?) -> Void)) {

    // This could be the details for the item that the customer wants to buy

    let cartContent: [String: Any] = ["items": [["id": UUID().uuidString]]]

    self.apiClient.createPaymentIntent(cartContent: cartContent) { [weak self] (data, error) in

        guard let self = self else { return }

        guard error == nil else {
            print(error.debugDescription)
            completion(false, error.debugDescription)
            return
        }

        guard
            let customerId = data?.customerId as? String,
            let customerEphemeralKeySecret = data?.ephemeralKey as? String,
            let paymentIntentClientSecret = data?.paymentIntent as? String,
            let publishableKey = data?.publishableKey as? String
        else {
            let error = "Error fetching required data"
            print(error)
            completion(false, error)
            return
        }

        print("Created Payment Intent")

        self.setPublishableKey(publishableKey: publishableKey)
        self.paymentIntentClientSecret = paymentIntentClientSecret
        self.customer = .init(id: customerId,
                              ephemeralKeySecret: customerEphemeralKeySecret)
        completion(true, nil)
    }
}

```

- Setup the `PaymentSheet` in your View Controller. Refer to `CourseCheckoutViewController` in the Proof of Concept example on GitHub.

```

// Create and configure the payment sheet

private func createPaymentSheet() {
    var configuration = PaymentSheet.Configuration()

    // Autofills the shipping details with the one we collected from user through AddressViewController

    configuration.shippingDetails = { [weak self] in
        return self?.address
    }

    // Configure button for Apple Pay in PaymentSheet

    configuration.applePay = .init(merchantId: "com.example.appname",
                                    merchantCountryCode: "US")

    // Provides checkbox for saving card details

    configuration.savePaymentMethodOptInBehavior = .requiresOptIn

    // Sets the return url. Used when user needs to go outside the app for authentication

    configuration.returnURL = "payments-with-stripe://stripe-redirect"

    // Configures the color of the pay button

    configuration.primaryButtonColor = .blue

    // Shows the name of the company collecting the payment

    configuration.merchantDisplayName = "Dummy Corp Inc"

    // Allows payments which requires some time to confirm

    configuration.allowsDelayedPaymentMethods = true

    // Adds default billing details for user to the payment object

    configuration.defaultBillingDetails.email = "dummy@corp.com"
    configuration.defaultBillingDetails.name = self.address?.name
    configuration.defaultBillingDetails.phone = self.address?.phone
    configuration.defaultBillingDetails.address.country = self.address?.address.country
    configuration.defaultBillingDetails.address.city = self.address?.address.city
    configuration.defaultBillingDetails.address.line1 = self.address?.address.line1
    configuration.defaultBillingDetails.address.line2 = self.address?.address.line2
    configuration.defaultBillingDetails.address.state = self.address?.address.state
    configuration.defaultBillingDetails.address.postalCode = self.address?.address.postalCode

    // Sets customer object to payment object

    if let customer = self.viewModel.getCustomer() {
        configuration.customer = customer
    }

    // Initiaises the PaymentSheet with the above config and client secret received from payment intent API

    if let paymentIntentClientSecret = self.viewModel.getPaymentIntentClientSecret() {
        self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret,
                                        configuration: configuration)
    }
}

```

- Handle the conditions after the payment. The following three scenarios can happen during/after the payment.

```

// Present user with the payment sheet and handles the various payment scenarios

private func presentPaymentSheet() {
    guard let paymentSheet = paymentSheet else { return }

    DispatchQueue.main.async {
        paymentSheet.present(from: self) { [weak self] (paymentResult) in

            guard let self = self else { return }

            switch paymentResult {
            case .completed:
                self.displayAlert(title: "Payment complete!")
            case .canceled:
                self.displayAlert(title: "Payment canceled!")
            case .failed(let error):
                self.displayAlert(title: "Payment failed", message: error.localizedDescription)
            }
        }
    }
}

```

- On tap of the pay now button, present the payment sheet, add the payment details and click on pay.

- Either the payment will be completed or it will fail if there are issues with the payment method. We can debug the failure reasons in the following [link](https://stripe.com/docs/error-codes).

- Payment can also result in cancellation if the user dismisses the `PaymentSheet`.

### Address collection

- We can set up the `AddressViewController` to display a form for collecting names, addresses, cities, countries, postal codes and phone numbers.

```

 // Setup and display the address sheet

 private func presentAddressCollectionController(_ controller: CourseCheckoutViewController) {
     let addressConfiguration = AddressViewController.Configuration(additionalFields: .init(name: .required,
                                                                                            phone: .required),
                                                                     allowedCountries: [],
                                                                     title: "Billing Address")
     let addressViewController = AddressViewController(configuration: addressConfiguration,
                                                       delegate: controller)

     let navigationController = UINavigationController(rootViewController: addressViewController)
     self.rootViewController.present(navigationController, animated: true)
 }

```

- Set up the delegate method to get the address details filled in by the customer.

```

 extension CourseCheckoutViewController: AddressViewControllerDelegate {

     func addressViewControllerDidFinish(_ addressViewController: Stripe.AddressViewController, with address: Stripe.AddressViewController.AddressDetails?) {
         addressViewController.dismiss(animated: true) {
             debugPrint(address as Any)

             self.address = address
         }
     }
 }

```

3. The address details collected from the user should be passed to `PaymentSheet` `Configuration`. This will auto-fill the details in the `PaymentSheet` and also send the customer details to Stripe Dashboard.

4. Collecting these details is essential if the Stripe account is registered in India but the users are paying in international currency. More on this [here](https://stripe.com/docs/india-accept-international-payments).

```

 var configuration = PaymentSheet.Configuration()

 configuration.shippingDetails = { [weak self] in
     return self?.address
 }

```

### Enable card scanning

To enable the option for scanning debit/credit cards, add the following key to the `info.plist` file.

```

  <key>NSCameraUsageDescription</key>
  <string>Allow the app to scan cards.</string>

```

> This feature is available on iOS 13.0 and above.

### Process payments using Apple Pay

Steps for integrating Apple Pay are well documented in the links below.

Please check out this tutorial for adding Apple Pay as a payment option to your app.

1. [Apple Pay with Payment Sheet](https://stripe.com/docs/payments/accept-a-payment?platform=ios&ui=payment-sheet#ios-apple-pay)

2. [Setup Apple Pay button](https://stripe.com/docs/apple-pay)

Add an Apple pay button on your `PaymentSheet` by editing the configuration as follows.

```

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

```

### Return to the app automatically after external authentication

A customer may go out of your app for authentication purposes, for example, in Safari or their banking app to complete payment.

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) or [universal link](https://developer.apple.com/documentation/xcode/allowing-apps-and-websites-to-link-to-your-content) and set up your app delegate/scene delegate

(If using scene delegate for iOS 13 and above) to forward the URL to the SDK.

- **AppDelegate.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 {

          /*
            This was not a stripe url, do whatever url handling your app
            normally does, if any.
            */
      }

      return true
  }

  // This method handles opening universal link URLs
  // (for example, "https://example.com/stripe_ios_callback")

  func application(_ application: UIApplication,
                    continue userActivity: NSUserActivity,
                    restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
  ) -> Bool  {

      if userActivity.activityType == NSUserActivityTypeBrowsingWeb {

          if let url = userActivity.webpageURL {

              let stripeHandled = StripeAPI.handleURLCallback(with: url)

              guard !stripeHandled else { return true }

              /*
                This was not a stripe url, do whatever url handling your app
                normally does, if any.
                */
          }
      }

      return false
  }

```

- **SceneDelegate.swift**

```

  func scene(_ scene: UIScene,
              openURLContexts URLContexts: Set<UIOpenURLContext>) {

      if let urlContext = URLContexts.first {

          let url = urlContext.url
          let stripeHandled = StripeAPI.handleURLCallback(with: url)

          if !stripeHandled {
              // This was not a stripe url, do whatever url handling your app
              // normally does, if any.
          }
      }
  }

```

Also, a `returnURL` should be configured in the `PaymentSheet.Configuration` object to the URL for your app.

```

var configuration = PaymentSheet.Configuration()
configuration.returnURL = "payments-with-stripe://stripe-redirect"

```

### Clear cookies on logout

`PaymentSheet` related cookies and other authentication data should be cleared when a user logs out of the app. Add the following code to your logout function.

```

import Stripe

// Resets all payment and user related cache
// Should be called when user logs out of the app

func logout() {

    /*
      Perform all other logout related steps here
      */

    PaymentSheet.resetCustomer()
}

```

## FAQ

1. Stripe SDK can be installed using CocoaPods, Carthage, and Swift Package Manager.

2. The latest version [v23.3.2](https://github.com/stripe/stripe-ios/tree/23.3.2) or above of Stripe iOS SDK requires Xcode 13.2.1 or later and is compatible with apps targeting iOS 13 or above.

3. For iOS 12 support use [v22.8.4](https://github.com/stripe/stripe-ios/tree/22.8.4).

4. For iOS 11 support use [v21.13.0](https://github.com/stripe/stripe-ios/tree/21.13.0).

5. For iOS 10 support use [v19.4.0](https://github.com/stripe/stripe-ios/tree/v19.4.0).

6. For iOS 9 support use [v17.0.2](https://github.com/stripe/stripe-ios/tree/v17.0.2).

7. Why was my card declined when trying to make a payment? Check the reason for your [decline code](https://stripe.com/docs/declines/codes).

8. Got an error message while processing your payment? Check the reason in this [article](https://stripe.com/docs/error-codes).

## Resources

1. [Stripe SDK on CocoaPods](https://cocoapods.org/pods/Stripe)

2. [Stripe SDK on GitHub](https://github.com/stripe/stripe-ios)

3. [Stripe API Reference](https://stripe.com/docs/api)

4. [Stripe Documentation](https://stripe.com/docs)

5. [Stripe iOS SDK Documentation](https://stripe.dev/stripe-ios/documentation/stripe/)

6. [Installing Stripe SDK using CocoaPods](https://stripe.com/docs/libraries/ios)

7. [About API Keys](https://stripe.com/docs/keys#obtain-api-keys)

8. [Test mode and Live mode](https://stripe.com/docs/keys#test-live-modes)

9. [Accepting Payments with Stripe](https://stripe.com/docs/payments/accept-a-payment)

10. [Collecting User's Address](https://stripe.com/docs/elements/address-element/collect-addresses)

11. [Dummy Credentials for testing payments](https://stripe.com/docs/testing)

12. [Accept payment from regions outside of India](https://stripe.com/docs/india-accept-international-payments)

13. [Adding multiple payment methods](https://stripe.com/docs/payments/payment-methods/integration-options#payment-method-product-support)

14. [Debug card Decline Codes](https://stripe.com/docs/declines/codes)

15. [Understanding payment Error Codes](https://stripe.com/docs/error-codes)

16. [Collecting user phone numbers through the backend](https://stripe.com/docs/payments/checkout/phone-numbers)

17. Adding additional articles on security when processing payments using Stripe:

    1. [Strong Customer Authentication](https://stripe.com/docs/strong-customer-authentication)

    2. [Security](https://stripe.com/docs/strong-customer-authentication)

    3. [3-D Secure](https://stripe.com/docs/strong-customer-authentication)

    4. [Privacy Details for iOS](https://stripe.com/docs/strong-customer-authentication)