Getting Started with Sources in the iOS SDK

    Make use of Sources with the iOS SDK.

    Creating a payment using Sources with the iOS SDK is a multi-step process:

    1. Create an STPSource object that represents your customer's payment method
    2. Check if further action is required from your customer

    If no further action is required:

    1. Confirm the source is ready to use
    2. Tell your backend to create a charge request using the source

    If further action is required:

    1. Present the user with any information they may need to authorize the charge
    2. In your backend, listen to Stripe webhooks to create a charge with the source
    3. In your app, display the appropriate confirmation to your customer based on the source's status

    Create an STPSource object

    Once you’ve collected your customer’s payment details, you can use the STPAPIClient class to create a source. First, assemble an STPSourceParams object with the payment information you’ve collected. Then, pass this object to STPAPIClient’s createSourceWithParams: method.

    To create an STPSourceParams object, we recommend that you use one of the helper constructors we provide, which specify the information needed for each payment method. For example, to create a source for a Sofort payment:

    let sourceParams = STPSourceParams.sofortParams(withAmount: 1099,
                                                    returnURL: "payments-example://stripe-redirect",
                                                    country: "DE",
                                                    statementDescriptor: "ORDER AT11990")
    STPAPIClient.shared().createSource(with: sourceParams, completion: completionBlock)
    STPSourceParams *sourceParams = [STPSourceParams sofortParamsWithAmount:1099
                                                                  returnURL:@"payments-example://stripe-redirect"
                                                                    country:@"DE"
                                                        statementDescriptor:@"ORDER AT11990"];
    [[STPAPIClient sharedClient] createSourceWithParams:sourceParams completion:completionBlock];

    Check if further action is required from your customer

    To determine whether further action is required from your customer, check the flow property on the newly created STPSource object. If flow is STPSourceFlowNone, no further action is required. For example, if you create a source for a card payment, its status is immediately set to STPSourceStatusChargeable. No additional customer action is needed, so you can tell your backend to create a charge with the source right away.

    let cardParams = STPCardParams()
    cardParams.name = "Jenny Rosen"
    cardParams.number = "4242424242424242"
    cardParams.expMonth = 12
    cardParams.expYear = 18
    cardParams.cvc = "424"
    
    let sourceParams = STPSourceParams.cardParams(withCard: cardParams)
    STPAPIClient.shared().createSource(with: sourceParams) { (source, error) in
        if let s = source, s.flow == .none && s.status == .chargeable {
            self.createBackendChargeWithSourceID(s.stripeID)
        }
    }
    STPCardParams *cardParams = [STPCardParams new];
    cardParams.name = @"Jenny Rosen";
    cardParams.number = @"4242424242424242";
    cardParams.expMonth = 12;
    cardParams.expYear = 18;
    cardParams.cvc = @"123";
    
    STPSourceParams *sourceParams = [STPSourceParams cardParamsWithCard:cardParams];
    
    [[STPAPIClient sharedClient] createSourceWithParams:sourceParams completion:^(STPSource *source, NSError *error) {
        if (source.flow == STPSourceFlowNone
            && source.status == STPSourceStatusChargeable) {
            [self createBackendChargeWithSourceID:source.stripeID];
        }
    }];

    If the source’s flow is not STPSourceFlowNone, then your customer needs to complete an action before the source can be used in a charge request.

    Flow Description
    STPSourceFlowRedirect Your customer must be redirected to the payment method’s website or app to confirm the charge. See the section below for more information.
    STPSourceFlowReceiver Your customer must push funds to the account information provided in the Source object. See the documentation for the specific payment method you are using for more information.
    STPSourceFlowVerification Your customer must verify ownership of their account by providing a code that you post to the Stripe API for authentication. See the documentation for the specific payment method you are using for more information.

    If the source requires further action from your customer, your iOS app should not tell your backend to create a charge request. Instead, your backend should listen for the source.chargeable webhook event to charge the source. This ensures that the source is charged even if the user never returns to your app after taking the required action. You can refer to our best practices for more information on supporting different payment methods using webhooks.

    Redirecting your customer to authorize a source

    For sources that require redirecting your customer to authorize the payment, you need to specify a return URL when you create the source. This allows your customer to be redirected back to your app after they authorize the payment. For this return URL, you can either use a custom URL scheme or a universal link supported by your app. For more information on registering and handling URLs in your app, refer to the Apple documentation:

    To handle redirecting your customer to the URL in the source object’s redirect.url parameter, we recommend using [UIApplication openURL:]. Opening the URL in an in-app container like SFSafariViewController can prevent your customer’s installed banking app from launching to complete authentication, resulting in a lower conversion rate. When you redirect your customer to authorize the payment, we recommend that you register for the UIApplicationWillEnterForeground notification to handle when they return to your app.

    let stripeClient = STPAPIClient.shared()
    let sourceParams = STPSourceParams.sofortParams(withAmount: 1099,
                                                    returnURL: "payments-example://stripe-redirect",
                                                    country: "DE",
                                                    statementDescriptor: "ORDER AT11990")
    stripeClient.createSource(with: sourceParams) { (source, error) in
        if let e = error {
            self.handleError(e)
        } else {
            self.source = source
            self.presentPollingUI()
            NotificationCenter.default.addObserver(self, selector: #selector(handleAppForeground), name: .UIApplicationWillEnterForeground, object: nil)
            UIApplication.shared.openURL(url)
        }
    }
    STPAPIClient *stripeClient = [STPAPIClient sharedClient];
    STPSourceParams *sourceParams = [STPSourceParams sofortParamsWithAmount:1099
                                                                  returnURL:@"payments-example://stripe-redirect"
                                                                    country:@"DE"
                                                        statementDescriptor:@"ORDER AT11990"];
    [stripeClient createSourceWithParams:sourceParams completion:^(STPSource *source, NSError *error) {
        if (error) {
            [self handleError:error];
        } else {
            self.source = source;
            [self presentPollingUI];
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleAppForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
            [[UIApplication sharedApplication] openURL:source.redirect.url];
        }
    }];

    After your customer returns to your app, we recommend that you start polling the source in order to display the appropriate confirmation status. STPAPIClient’s startPollingSourceWithId method continuously fetches a source, and calls its completion block once the source’s status is no longer pending, or after the specified timeout length has been exceeded. Most sources become chargeable within a few seconds of your customer authorizing the payment, but some may take longer, and it is always possible for your customer to return to your app without authorizing the payment. To avoid making your customer wait for too long for a confirmation after they return to your app, we recommend polling with a short timeout (e.g., 10 seconds).

    While polling, be sure to update your app’s UI in order to prevent your customer from making an additional payment. If the status of the source is still pending after polling for a short time, or if the status cannot be determined, it may be more appropriate for your app to simply tell the user that their order has been received. Once your backend creates a charge using the source, you can notify your customer that their order has been fulfilled (e.g., by sending an email or a push notification).

    func handleAppForeground() {
        guard let s = self.source, let clientSecret = s.clientSecret else {
            return
        }
        NotificationCenter.default.removeObserver(self, name: .UIApplicationWillEnterForeground, object: nil)
        STPAPIClient.shared().startPollingSource(withId: s.stripeID,
                                                 clientSecret: clientSecret,
                                                 timeout: 10,
                                                 completion: { (source, error) in
            self.dismissPollingUI()
            if let s = source, s.status == .consumed {
                self.displayOrderConfirmation("Payment successfully created")
            } else if let s = source, s.status == .failed {
                self.displayOrderConfirmation("Payment failed")
            } else {
                self.displayOrderConfirmation("Order received")
            }
        })
    }
    - (void)handleAppForeground {
        if (!self.source) {
            return;
        }
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
        [[STPAPIClient sharedClient] startPollingSourceWithId:self.source.stripeID
                                                 clientSecret:self.source.clientSecret
                                                      timeout:10
                                                   completion:^(STPSource *source, NSError *error) {
            [self dismissPollingUI];
            if (error) {
                [self.delegate exampleViewController:self didFinishWithError:error];
            } else {
                if (source.status == STPSourceStatusConsumed) {
                    [self.delegate exampleViewController:self didFinishWithMessage:@"Payment successfully created"];
                } else if (source.status == STPSourceStatusFailed) {
                    [self.delegate exampleViewController:self didFinishWithMessage:@"Payment failed"];
                } else {
                    [self.delegate exampleViewController:self didFinishWithMessage:@"Order received"];
                }
            }
        }];
    }

    More information

    If you'd like more help, check out our example app that demonstrates creating a payment using several different payment methods. In addition, here's some documentation you might want to read next: