iOS basic integration

    Accept cards and Apple Pay with the iOS SDK's prebuilt UI.

    Use this integration if you want a prebuilt UI that:

    • Accepts credit cards and Apple Pay
    • Saves and displays cards for reuse
    • Supports limited customization of fonts and colors
    • Displays full-screen view controllers to collect payment details, shipping address, and shipping method:

    These view controllers are also available to use individually—see the steps below for more details. This integration requires both server and client-side steps to implement.

    1 Set up Stripe Client-side Server-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 our official libraries for access to the Stripe API from your server:

    Available as a gem:

    sudo gem install stripe

    If you use bundler, you can add this line:

    gem 'stripe'

    Available through pip:

    pip install --upgrade stripe

    Alternatively, you can also use easy_install:

    easy_install --upgrade stripe

    The PHP library can be installed via Composer:

    composer require stripe/stripe-php

    Alternatively, you can download the source directly.

    For Gradle, add the following dependency to your build.gradle:

    implementation "com.stripe:stripe-java:{VERSION}"
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    For Maven, add the following dependency to your POM:

    <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    In other environments, manually install the following JARs:

    Install via npm:

    npm install stripe

    Install via go:

    go get github.com/stripe/stripe-go

    Then import the package:

    import ( "github.com/stripe/stripe-go" )

    Install via dotnet:

    dotnet add package Stripe.net dotnet restore

    Or using NuGet:

    PM> Install-Package Stripe.net

    Client-side

    The iOS SDK is open source, fully documented, and compatible with apps supporting iOS 9 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:
      pod init
    3. Add this line to your Podfile:
      pod 'Stripe'
    4. Run the following command:
      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:
      pod update Stripe
    1. If you haven't already, install the latest version of Carthage.
    2. Add this line to your Cartfile:
      github "stripe/stripe-ios"
    3. Follow the Carthage installation instructions.
    4. In the future, to update to the latest version of the SDK, run the following command:
      carthage update stripe-ios --platform ios
    1. Head to our GitHub releases page and download and unzip Stripe.framework.zip.
    2. Drag Stripe.framework to the "Embedded Binaries" section of your Xcode project's "General" settings. Make sure to select "Copy items if needed".
    3. Head to the "Build Phases" section of your Xcode project settings, and create a new "Run Script Build Phase". Paste the following snippet into the text field:
      bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.framework/integrate-dynamic-framework.sh"
    4. In the future, to update to the latest version of our SDK, just repeat steps 1 and 2.

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

    import UIKit import Stripe @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Stripe.setDefaultPublishableKey("pk_test_TYooMQauvdEDq54NiTphI7jx") // do any other necessary launch configuration return true } }
    #import "AppDelegate.h" #import <Stripe/Stripe.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Stripe setDefaultPublishableKey:@"pk_test_TYooMQauvdEDq54NiTphI7jx"]; // do any other necessary launch configuration return YES; } @end

    2 Set up an ephemeral key Client-side Server-side

    In order for the SDK to save and retrieve credit cards for later use, create a single Stripe Customer object for each of your users. When you create a new user or account on your server, create a corresponding Customer object at the same time, even if you don’t collect payment information from your users when they sign up. This ensures that your application has a matching Customer for each user.

    For security, the Customer API is not directly accessible from the client. Instead, your server provides the SDK with an ephemeral key—a short-lived API key with restricted access to the Customer API. You can think of an ephemeral key as a session, authorizing the SDK to retrieve and update a specific Customer object for the duration of the session.

    Server-side

    To provide an ephemeral key to the SDK, you’ll need to expose a new API endpoint on your backend. This endpoint should create an ephemeral key for the current Stripe customer, and return the key’s unmodified response as JSON. When the SDK requests an ephemeral key, it will specify the version of the Stripe API that it expects the response to come from. Your endpoint must accept an api_version parameter, and use the specified API version when creating the ephemeral key. This ensures that the SDK always receives the correct ephemeral key response from your backend. Consult our Example Backend to see this in practice.

    # Sinatra post path do stripe_version = params['api_version'] customer_id = session['customer_id'] key = Stripe::EphemeralKey.create( {customer: customer_id}, {stripe_version: stripe_version} ) key.to_json end
    # Flask from flask import Flask, session, jsonify, request # This function assumes that the session handling has stored the customerId @app.route(path, methods=['POST']) def issue_key(): api_version = request.args['api_version'] customerId = session['customerId'] key = stripe.EphemeralKey.create(customer=customerId, api_version="2017-05-25") return jsonify(key)
    // This assumes that $customerId has been set appropriately from session data if (!isset($_POST['api_version'])) { exit(http_response_code(400)); } try { $key = \Stripe\EphemeralKey::create( ["customer" => $customerId], ["stripe_version" => $_POST['api_version']] ); header('Content-Type: application/json'); exit(json_encode($key)); } catch (Exception $e) { exit(http_response_code(500)); }
    // Express app.post(path, (req, res) => { const stripe_version = req.query.api_version; if (!stripe_version) { res.status(400).end(); return; } // This function assumes that some previous middleware has determined the // correct customerId for the session and saved it on the request object. stripe.ephemeralKeys.create( {customer: req.customerId}, {stripe_version: stripe_version} ).then((key) => { res.status(200).json(key); }).catch((err) => { res.status(500).end(); }); });
    // Using Spark framework (http://sparkjava.com) post(new Route(path) { @Override public Object handle(final Request request, final Response response) { String apiVersion = request.queryParams("api_version"); RequestOptions requestOptions = (new RequestOptions.RequestOptionsBuilder()) .setStripeVersion(apiVersion) .build(); try { // Retrieve the customer id from your session for example Map<String, Object> options = new HashMap<String, Object>(); options.put("customer", customerId); EphemeralKey key = EphemeralKey.create(options, requestOptions); return key.getRawJson(); } catch (StripeException e) { response.status(500); return e; } } });
    // net/http // The customerId parameter should be the ID of the Customer object associated // with the session the request was made on. func issueKeyHandler(w http.ResponseWriter, r *http.Request, customerId string) { r.ParseForm() stripeVersion := r.Form.Get("api_version") if stripeVersion == "" { log.Printf("Stripe-Version not found\n") w.WriteHeader(400) return } params := &stripe.EphemeralKeyParams{ Customer: stripe.String(customerId), StripeVersion: stripe.String(stripeVersion), } key, err := ephemeralkey.New(params) if err != nil { log.Printf("Stripe bindings call failed, %v\n", err) w.WriteHeader(500) return } w.Write(key.RawJSON) }

    Client-side

    In your app, conform to the STPCustomerEphemeralKeyProvider protocol by implementing its createCustomerKeyWithAPIVersion method. This method requests an ephemeral key from the endpoint you created on the backend.

    When implementing this method, be sure to pass the apiVersion parameter along to your ephemeral keys endpoint. Consult the API client in our example app to see this in practice.

    import Stripe class MyAPIClient: NSObject, STPCustomerEphemeralKeyProvider { func createCustomerKey(withAPIVersion apiVersion: String, completion: @escaping STPJSONResponseCompletionBlock) { let url = self.baseURL.appendingPathComponent("ephemeral_keys") var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false)! urlComponents.queryItems = [URLQueryItem(name: "api_version", value: apiVersion)] var request = URLRequest(url: urlComponents.url!) request.httpMethod = "POST" let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in guard let response = response as? HTTPURLResponse, response.statusCode == 200, let data = data, let json = ((try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]) as [String : Any]??) else { completion(nil, error) return } completion(json, nil) }) task.resume() } }
    // In MyApiClient.h, declare conformance to STPCustomerEphemeralKeyProvider: // @interface MyAPIClient : NSObject <STPCustomerEphemeralKeyProvider> @implementation MyAPIClient - (void)createCustomerKeyWithAPIVersion:(NSString *)apiVersion completion:(STPJSONResponseCompletionBlock)completion { NSURL *url = [self.baseURL URLByAppendingPathComponent:@"ephemeral_keys"]; NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; urlComponents.queryItems = @[[[NSURLQueryItem alloc] initWithName:@"api_version" value:apiVersion]]; NSURLRequest *request = [[NSURLRequest alloc] initWithURL:urlComponents.URL]; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (data != nil && [response isKindOfClass:[NSHTTPURLResponse class]] && ((NSHTTPURLResponse *)response).statusCode == 200) { NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; completion(json, nil); } else { completion(nil, error); } }]; [task resume]; } @end

    3 Set up an STPCustomerContext Client-side

    Next, initialize an STPCustomerContext with the STPCustomerEphemeralKeyProvider you created in the previous step.

    A CustomerSession talks to your backend to retrieve an ephemeral key for your Customer with its STPCustomerEphemeralKeyProvider, and uses that key to manage retrieving and updating the Customer’s payment methods on your behalf.

    // MyAPIClient implements STPCustomerEphemeralKeyProvider (see above) let customerContext = STPCustomerContext(keyProvider: MyAPIClient())
    // MyAPIClient implements STPCustomerEphemeralKeyProvider (see above) STPCustomerContext *customerContext = [[STPCustomerContext alloc] initWithKeyProvider:[MyAPIClient new]];

    To reduce load times, preload your customer’s information by initializing STPCustomerContext before they enter your payment flow.

    If your current user logs out of the app and a new user logs in, create a new instance of STPCustomerContext or clear the cached customer using the provided clearCachedCustomer method. On your backend, create and return a new ephemeral key for the Customer object associated with the new user.

    4 Set up an STPPaymentContext Client-side

    Once you’ve set up your customer context, you can use it to initialize STPPaymentContext, the core class of the integration. Conform a class to STPPaymentContextDelegate and assign it to the payment context’s delegate and hostViewController properties. We recommend using your app’s checkout screen UIViewController. In the next steps, you will implement the STPPaymentContext delegate methods.

    You should also set the payment context’s paymentAmount property, which will be displayed to your user in the Apple Pay dialog (you can change this later, if the amount of the user’s purchase changes).

    init() { self.paymentContext = STPPaymentContext(customerContext: customerContext) super.init(nibName: nil, bundle: nil) self.paymentContext.delegate = self self.paymentContext.hostViewController = self self.paymentContext.paymentAmount = 5000 // This is in cents, i.e. $50 USD }
    - (instancetype)init { self = [super initWithNibName:nil bundle:nil]; if (self) { self.paymentContext = [[STPPaymentContext alloc] initWithCustomerContext:customerContext]; self.paymentContext.delegate = self; self.paymentContext.hostViewController = self; self.paymentContext.paymentAmount = 5000; // This in cents, i.e. $50 USD } return self; }

    5 Handle the user's payment method Client-side

    In your checkout screen, add a button to let the customer enter or change their payment method. When tapped, use STPPaymentContext to push or present an STPPaymentOptionsViewController on the payment context’s hostViewController.

    // If you prefer a modal presentation func choosePaymentButtonTapped() { self.paymentContext.presentPaymentOptionsViewController() } // If you prefer a navigation transition func choosePaymentButtonTapped() { self.paymentContext.pushPaymentOptionsViewController() }
    // If you prefer a modal presentation - (void)choosePaymentButtonTapped { [self.paymentContext presentPaymentOptionsViewController]; } // If you prefer a navigation transition - (void)choosePaymentButtonTapped { [self.paymentContext pushPaymentOptionsViewController]; }

    STPPaymentOptionsViewController uses STPCustomerContext to display a Customer’s payment methods. If there are no stored payment methods or the Add New Card button is tapped, STPAddCardViewController is displayed. You can also initialize and display these view controllers without using STPPaymentContext.

    - paymentContextDidChange:

    This STPPaymentContext delegate method triggers when the content of the payment context changes, like when the user selects a new payment method or enters shipping information. This is a good place to update your UI:

    func paymentContextDidChange(_ paymentContext: STPPaymentContext) { self.activityIndicator.animating = paymentContext.loading self.paymentButton.enabled = paymentContext.selectedPaymentOption != nil self.paymentLabel.text = paymentContext.selectedPaymentOption?.label self.paymentIcon.image = paymentContext.selectedPaymentOption?.image }
    - (void)paymentContextDidChange:(STPPaymentContext *)paymentContext { self.activityIndicator.animating = paymentContext.loading; self.paymentButton.enabled = paymentContext.selectedPaymentOption != nil; self.paymentLabel.text = paymentContext.selectedPaymentOption.label; self.paymentIcon.image = paymentContext.selectedPaymentOption.image; }

    6 Handle the user's shipping info Client-side

    If your user needs to enter or change their shipping address and shipping method, STPPaymentContext can do this for you automatically. STPPaymentContext will save shipping info to the Stripe customer when your user updates their information, and automatically prefill the shipping view controller for future purchases. Note that you should not rely on the shipping information stored on the Stripe customer for order fulfillment, as your user may change this information if they make multiple purchases. We recommend adding shipping information when you create a PaymentIntent object (which can also help prevent fraud), or when saving it to your own database. When presenting the shipping view controller, you can specify whether you'd like it presented modally, or pushed onto a UINavigationController stack:

    // If you prefer a modal presentation func shippingButtonTapped() { self.paymentContext.presentShippingViewController() } // If you prefer a navigation transition func shippingButtonTapped() { self.paymentContext.pushShippingViewController() }
    // If you prefer a modal presentation - (void)shippingButtonTapped { [self.paymentContext presentShippingViewController]; } // If you prefer a navigation transition - (void)shippingButtonTapped { [self.paymentContext pushShippingViewController]; }

    This sets up and presents an STPShippingAddressViewController on the payment context's hostViewController. Once the user enters a valid shipping address, they'll be taken to an STPShippingMethodsViewController. After they select a shipping method, both view controllers will be dismissed or popped off the hostViewController's stack.


    - paymentContext:didUpdateShippingAddress:completion:

    This method is called after your user enters a shipping address. Validate the returned address and determine the shipping methods available for that address.

    If the address is valid, call the provided completion block with a status of STPShippingStatusValid, nil for the error argument, an array of shipping methods, and a selected shipping method. If you don't need to collect a shipping method, pass nil for the shipping methods and selected shipping method.

    If the address is invalid, call the completion block with a status of STPShippingStatusInvalid, an error object describing the issue with the address, and nil for the shipping methods and selected shipping method. Note that providing an error object is optional—if you omit it, the user will simply see an alert with the message "Invalid Shipping Address".

    func paymentContext(_ paymentContext: STPPaymentContext, didUpdateShippingAddress address: STPAddress, completion: @escaping STPShippingMethodsCompletionBlock) { let upsGround = PKShippingMethod() upsGround.amount = 0 upsGround.label = "UPS Ground" upsGround.detail = "Arrives in 3-5 days" upsGround.identifier = "ups_ground" let fedEx = PKShippingMethod() fedEx.amount = 5.99 fedEx.label = "FedEx" fedEx.detail = "Arrives tomorrow" fedEx.identifier = "fedex" if address.country == "US" { completion(.valid, nil, [upsGround, fedEx], upsGround) } else { completion(.invalid, nil, nil, nil) } }
    - (void)paymentContext:(STPPaymentContext *)paymentContext didUpdateShippingAddress:(STPAddress *)address completion:(STPShippingMethodsCompletionBlock)completion { PKShippingMethod *upsGround = [PKShippingMethod new]; upsGround.amount = [NSDecimalNumber decimalNumberWithString:@"0"]; upsGround.label = @"UPS Ground"; upsGround.detail = @"Arrives in 3-5 days"; upsGround.identifier = @"ups_ground"; PKShippingMethod *fedEx = [PKShippingMethod new]; fedEx.amount = [NSDecimalNumber decimalNumberWithString:@"5.99"]; fedEx.label = @"FedEx"; fedEx.detail = @"Arrives tomorrow"; fedEx.identifier = @"fedex"; if ([address.country isEqualToString:@"US"]) { completion(STPShippingStatusValid, nil, @[upsGround, fedEx], upsGround); } else { completion(STPShippingStatusInvalid, nil, nil, nil); } }

    7 Submit the payment Client-side Server-side

    Finally, when your user is ready to pay (e.g., they tap the Buy button) call requestPayment on your payment context. It’ll display any required UI (such as the Apple Pay dialog) and call the appropriate methods on its delegate as your user finishes their payment.

    func payButtonTapped() { self.paymentContext.requestPayment() }
    - (void)payButtonTapped { [self.paymentContext requestPayment]; }

    - paymentContext:didCreatePaymentResult:completion:

    This method is called when the customer has successfully selected a payment method. Submit the payment to Stripe using a Payment Intent. Stripe uses this payment object to track and handle all the states of the payment until the payment completes.

    Server-side

    On your server, make an endpoint that creates a PaymentIntent with an amount and currency and returns its client secret to your client.

    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.

    curl https://api.stripe.com/v1/payment_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=usd
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', }) client_secret = payment_intent['client_secret'] # Pass the client secret to the client
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.create( amount=1099, currency='usd', ) client_secret = intent.client_secret # Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', ]); $client_secret = $intent->client_secret // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; import com.stripe.model.PaymentIntent; import com.stripe.param.PaymentIntentCreateParams; PaymentIntentCreateParams createParams = new PaymentIntentCreateParams.Builder() .setCurrency("usd").setAmount(new Long(1099)) .build(); PaymentIntent intent = PaymentIntent.create(createParams); String clientSecret = intent.getClientSecret(); // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); (async () => { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', }); const clientSecret = paymentIntent.client_secret // Pass the client secret to the client })();
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), } paymentintent.New(params) // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", }; service.Create(options); // Pass the client secret to the client

    Client-side

    On the client, implement this delegate method to:

    1. Request a PaymentIntent from your server
    2. Assemble a STPPaymentIntentParams object with the PaymentIntent client secret from your server and the paymentMethod provided by the delegate method.
    3. Call the STPPaymentHandler confirmPayment method to confirm the payment, passing the STPPaymentContext as the authenticationContext.
    func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPErrorBlock) { // Request a PaymentIntent from your backend MyAPIClient.sharedClient.createPaymentIntent(products: self.products, shippingMethod: paymentContext.selectedShippingMethod) { result in switch result { case .success(let clientSecret): // Assemble the PaymentIntent parameters let paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret) paymentIntentParams.paymentMethodId = paymentResult.paymentMethod.stripeId // Confirm the PaymentIntent STPPaymentHandler.shared().confirmPayment(withParams: paymentIntentParams, authenticationContext: paymentContext) { status, paymentIntent, error in switch status { case .succeeded: // Your backend asynchronously fulfills the customer's order, e.g. via webhook completion(.success, nil) case .failed: completion(.error, error) // Report error case .canceled: completion(.userCancellation, nil) // Customer cancelled @unknown default: completion(.error, nil) } } case .failure(let error): completion(.error, error) // Report error from your API break } } }
    - (void)paymentContext:(STPPaymentContext *)paymentContext didCreatePaymentResult:(STPPaymentResult *)paymentResult completion:(STPErrorBlock)completion { // Request a PaymentIntent from your backend [[MyAPIClient sharedClient] createPaymentIntentWithCompletion:^(MyAPIClientResult status, NSString * _Nullable paymentIntentClientSecret, NSError * _Nullable error) { if (paymentIntentClientSecret == nil || error != nil) { completion(STPPaymentStatusError, error); // Report error from your API return; } // Assemble the PaymentIntent parameters STPPaymentIntentParams *paymentIntentParams = [[STPPaymentIntentParams alloc] initWithClientSecret: paymentIntentClientSecret]; paymentIntentParams.paymentMethodId = paymentResult.paymentMethod.stripeId; // Confirm the PaymentIntent [[STPPaymentHandler sharedHandler] confirmPayment:paymentIntentParams withAuthenticationContext:paymentContext completion:^(STPPaymentHandlerActionStatus status, STPPaymentIntent * _Nullable paymentIntent, NSError * _Nullable error) { switch (status) { case STPPaymentHandlerActionStatusSucceeded: // Your backend asynchronously fulfills the customer's order, e.g. via webhook completion(STPPaymentStatusSuccess, nil); break; case STPPaymentHandlerActionStatusFailed: completion(STPPaymentStatusError, error); break; case STPPaymentHandlerActionStatusCanceled: completion(STPPaymentStatusUserCancellation, nil); break; } }]; }]; }

    You must call the provided completion block with the appropriate STPPaymentStatus (.success, .error, or .userCancellation) when the customer’s payment is finished.

    - paymentContext:didFinishWithStatus:error:

    This method is called after the previous method, when any auxiliary UI that has been displayed (such as the Apple Pay dialog) has been dismissed. You should inspect the returned status and show an appropriate message to your user. For example:

    func paymentContext(_ paymentContext: STPPaymentContext, didFinishWithStatus status: STPPaymentStatus, error: Error?) { switch status { case .error: self.showError(error) case .success: self.showReceipt() case .userCancellation: return // Do nothing } }
    - (void)paymentContext:(STPPaymentContext *)paymentContext didFinishWithStatus:(STPPaymentStatus)status error:(NSError *)error { switch (status) { case STPPaymentStatusSuccess: [self showReceipt]; break; case STPPaymentStatusError: [self showError:error]; break; case STPPaymentStatusUserCancellation: return; // Do nothing } }

    - paymentContext:didFailToLoadWithError:

    This method is called in the rare case that the payment context’s initial loading call fails, usually due to lack of internet connectivity. You should dismiss your checkout page when this occurs and invite the user to try again. You can also optionally attempt to try again by calling retryLoading on the payment context.

    func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) { self.navigationController?.popViewController(animated: true) // Show the error to your user, etc. }
    - (void)paymentContext:(STPPaymentContext *)paymentContext didFailToLoadWithError:(NSError *)error { [self.navigationController popViewControllerAnimated:YES]; // Show the error to your user, etc. }

    8 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.

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

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

    Optional Handle post-payment events

    Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.

    Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future, like direct debit.

    Receive events and run business actions

    Manually

    Use the Stripe Dashboard to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments.

    Custom Code

    Build a webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

    Prebuilt Apps

    Handle common business events, like shipping and inventory management, by integrating a partner application.

    Optional Set up Apple Pay Client-side

    Register for an Apple Merchant ID

    First, you’ll need to obtain an Apple Merchant ID. Start by heading to the Registering a Merchant ID page on the Apple Developer website.

    Fill out the form with a description and identifier. Your description is for your own records and can be modified in the future (we recommend just using the name of your app). The identifier must be unique (across all apps, not just yours) and can’t be changed later (although you can always make another one). We recommend using merchant.com.{{your_app_name}}.

    After you’ve obtained an Apple Merchant ID, set it in your configuration:

    STPPaymentConfiguration.shared().appleMerchantIdentifier = "your apple merchant identifier"
    [[STPPaymentConfiguration sharedConfiguration] setAppleMerchantIdentifier:@"your apple merchant identifier"];

    Create a new Apple Pay certificate

    You need to include a certificate in your app to encrypt outgoing payment data. This involves 3 steps:

    1. Obtain a CSR (certificate signing request) file from Stripe
    2. Use this CSR to generate a certificate through Apple
    3. Upload the certificate back to Stripe

    First, head to the Apple Pay Settings page in the Dashboard. Choose Add new application and download the .certSigningRequest file.

    Next, back on the Apple Developer site, visit the Add iOS Certificate page. Choose Apple Pay Certificate from the options and click Continue. On the next page, choose the Merchant ID you created earlier from the dropdown and continue.

    The next page explains that you can obtain a CSR from your Payment Provider (which at this point you’ve done already) or create one manually. Important note: you must use the CSR provided by Stripe - creating your own won’t work. So ignore the directions at the bottom of this page and continue on.

    You’ll be prompted to upload a .certSigningRequest file. Choose the file you downloaded from the Dashboard and continue. You’ll see a success page, with an option to download your certificate. Download it. Finally, return to the Dashboard and upload this .cer file to Stripe.

    Integrate with Xcode

    Add the Apple Pay capability to your app. In Xcode, open your project settings, choose the Capabilities tab, and enable the Apple Pay switch. You may be prompted to log in to your developer account at this point. Enable the checkbox next to the merchant ID you created earlier, and your app is ready to accept Apple Pay!

    Xcode capabilities pane

    Enable the Apple Pay capability in Xcode

    STPPaymentContext will now display Apple Pay as a payment option in the payment options view controller.

    Optional Customize the UI Client-side

    The appearance of the UI components is customizable by using the STPTheme object.

    Stripe iOS UI Theming

    You can override any of the properties from the default theme, typically in your AppDelegate:

    STPTheme.default().accentColor = UIColor.blue
    [[STPTheme defaultTheme] setAccentColor:[UIColor blueColor]];

    Here is a list of properties you can customize and their respective usage inside the payment selector UI:

    Property Name Description
    primaryBackgroundColor Background color for any views in this theme
    secondaryBackgroundColor Background color for any supplemental views inside a view (for example the cells of a table view)
    primaryForegroundColor Text color for any important labels in a view
    secondaryForegroundColor Text color for any supplementary labels in a view
    accentColor Color for any buttons and other elements on a view that are important to highlight
    errorColor Color for rendering any error messages or views
    font Font to be used for all views
    emphasisFont Medium-weight font to be used for all bold text in views

    You can also customize the fonts in the UI. By default, the SDK will use the system font at different weight and sizes. To override the defaults, set the font and emphasisFont properties and the SDK will automatically use your choice instead and infer the rest.

    See also

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page