Sign in
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
Overview
How cards work
Sample integration
Accept a payment
More payment scenarios
U.S. and Canadian cards
Testing
payments
·
HomePaymentsOnline payments

Accept a payment

Securely accept payments online.

Collecting payments in your iOS app consists of creating an object to track a payment on your server, collecting card information in your app, and submitting the payment to Stripe for processing.

Stripe uses a payment object, called a PaymentIntent, to track and handle all the states of the payment until it’s completed, including situations like two-factor authentication when the bank requires customer intervention.

The steps in this guide are fully implemented on GitHub in the using-webhooks directory. Clone the repo and follow the instructions to run the demo app.

Set up Stripe
Server-side
Client-side

First, you need a Stripe account. Register now.

Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use the official libraries for access to the Stripe API from your server:

Terminal
# Available as a gem sudo gem install stripe
Gemfile
# If you use bundler, you can add this line to your Gemfile gem 'stripe'

Client-side

The iOS SDK is open source, fully documented, and compatible with apps supporting iOS 11 or above.

  1. If you haven’t already, install the latest version of CocoaPods.
  2. If you don’t have an existing Podfile, run the following command to create one:
    Terminal
    pod init
  3. Add this line to your Podfile:
    Podfile
    pod 'Stripe'
  4. Run the following command:
    Terminal
    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, just run:
    Terminal
    pod update Stripe

For details on the latest SDK release and past versions, see the Releases page on GitHub. To receive notifications when a new release is published, watch releases for the repository.

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

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

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

Create your checkout page
Client-side

Want a prebuilt UI instead?

The iOS Basic Integration features prebuilt, full size screens to collect payment information.

Securely collect card information on the client with STPPaymentCardTextField, a drop-in UI component provided by the SDK.

STPPaymentCardTextField performs real-time validation and formatting.

Create an instance of the card component and a Pay button with the following code:

CheckoutViewController.swift
View full sample
import UIKit import Stripe class CheckoutViewController: UIViewController { lazy var cardTextField: STPPaymentCardTextField = { let cardTextField = STPPaymentCardTextField() return cardTextField }() lazy var payButton: UIButton = { let button = UIButton(type: .custom) button.layer.cornerRadius = 5 button.backgroundColor = .systemBlue button.titleLabel?.font = UIFont.systemFont(ofSize: 22) button.setTitle("Pay", for: .normal) button.addTarget(self, action: #selector(pay), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white let stackView = UIStackView(arrangedSubviews: [cardTextField, payButton]) stackView.axis = .vertical stackView.spacing = 20 stackView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stackView) NSLayoutConstraint.activate([ stackView.leftAnchor.constraint(equalToSystemSpacingAfter: view.leftAnchor, multiplier: 2), view.rightAnchor.constraint(equalToSystemSpacingAfter: stackView.rightAnchor, multiplier: 2), stackView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor, multiplier: 2), ]) } @objc func pay() { // ... } }

Run your app, and make sure your checkout page shows the card component and pay button.

Create a PaymentIntent
Server-side
Client-side

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

Server-side

On your server, make an endpoint that creates a PaymentIntent with an amount and currency. Always decide how much to charge on the server side, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices.

Terminal
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "amount"=1099 \ -d "currency"="usd"

Instead of passing the entire PaymentIntent object to your app, only return its client secret. The PaymentIntent’s client secret is a unique key that lets you confirm the payment and update card details on the client, without allowing manipulation of sensitive information, like payment amount.

Client-side

On the client, request a PaymentIntent from your server and store its client secret.

CheckoutViewController.swift
View full sample
class CheckoutViewController: UIViewController { var paymentIntentClientSecret: String? // ...continued from previous step override func viewDidLoad() { // ...continued from previous step startCheckout() } func startCheckout() { // Request a PaymentIntent from your server and store its client secret // Click Open on GitHub to see a full implementation } }

Submit the payment to Stripe
Client-side

When the customer taps the Pay button, confirm the PaymentIntent to complete the payment.

First, assemble a STPPaymentIntentParams object with:

  1. The card text field’s payment method details
  2. The PaymentIntent client secret from your server

Rather than sending the entire PaymentIntent object to the client, use its client secret. This is different from your API keys that authenticate Stripe API requests. The client secret is a string that lets your app access important fields from the PaymentIntent (e.g., status) while hiding sensitive ones (e.g., customer).

The client secret should still be handled carefully because it can complete the charge. Don’t log it, embed it in URLs, or expose it to anyone but the customer.

Next, complete the payment by calling the STPPaymentHandler confirmPayment method.

CheckoutViewController.swift
View full sample
class CheckoutViewController: UIViewController { // ... @objc func pay() { guard let paymentIntentClientSecret = paymentIntentClientSecret else { return; } // Collect card details let cardParams = cardTextField.cardParams let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: nil, metadata: nil) let paymentIntentParams = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret) paymentIntentParams.paymentMethodParams = paymentMethodParams // Submit the payment let paymentHandler = STPPaymentHandler.shared() paymentHandler.confirmPayment(withParams: paymentIntentParams, authenticationContext: self) { (status, paymentIntent, error) in switch (status) { case .failed: self.displayAlert(title: "Payment failed", message: error?.localizedDescription ?? "") break case .canceled: self.displayAlert(title: "Payment canceled", message: error?.localizedDescription ?? "") break case .succeeded: self.displayAlert(title: "Payment succeeded", message: paymentIntent?.description ?? "", restartDemo: true) break @unknown default: fatalError() break } } } } extension CheckoutViewController: STPAuthenticationContext { func authenticationPresentingViewController() -> UIViewController { return self } }

If authentication is required by regulation such as Strong Customer Authentication, STPPaymentHandler presents view controllers using the STPAuthenticationContext passed in and walks the customer through that process. See Supporting 3D Secure Authentication on iOS to learn more.

If the payment succeeds, the completion handler is called with a status of .succeeded. If it fails, the status is .failed and you can display the error.localizedDescription to the user.

You can also check the status of a PaymentIntent in the Dashboard or by inspecting the status property on the object.

Test the integration

By this point you should have a basic card integration that collects card details and makes a payment.

There are several test cards you can use in test mode to make sure this integration is ready. Use them with any CVC, postal code, and future expiration date.

NumberDescription
Succeeds and immediately processes the payment.
Requires authentication. Stripe will trigger a modal asking for the customer to authenticate.
Always fails with a decline code of insufficient_funds.

For the full list of test cards see our guide on testing.

OptionalHandle post-payment events

See also

  • Accept Apple Pay
  • Save card details during payment
  • Learn more about the Payment Intents API
Was this page helpful?
Questions? Contact us.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.
On this page
Set up Stripe
Create your checkout page
Create a PaymentIntent
Submit the payment to Stripe
Test the integration
Handle post-payment events