iosswiftstripe-paymentsstripe-sca

Stripe SCA need to handle next action


I am using string in this application perviously but all the things done by backend developer but now stripe change their implementation and give support for European payment change (Supporting 3D Secure Authentication) with SCA so now i need to add library in my local code but i stuck at this place.

I got the client id from server but handle next action will give me error something like this.

Error Domain=STPPaymentHandlerErrorDomain Code=1 "There was an unexpected error -- try again in a few seconds" UserInfo={com.stripe.lib:ErrorMessageKey=The PaymentIntent requires a PaymentMethod or Source to be attached before using STPPaymentHandler., NSLocalizedDescription=There was an unexpected error -- try again in a few seconds}

I did not find any relative document here

Here is my code

//Api called on server for client id
    MyAPIClient.sharedClient.createAndConfirmPaymentIntent(paymentResult,
                                                                   amount: self.paymentContext.paymentAmount,
                                                                   returnURL: "payments-example://stripe-redirect",
                                                                   shippingAddress: self.paymentContext.shippingAddress,
                                                                   shippingMethod: self.paymentContext.selectedShippingMethod) { (clientSecret, error) in
                guard let clientSecret = clientSecret else {
                    completion(.error, error ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse clientSecret from response"]))
                    return
                }
                STPPaymentHandler.shared().handleNextAction(forPayment: clientSecret, authenticationContext: paymentContext, returnURL: "payments-example://stripe-redirect") { (status, handledPaymentIntent, actionError) in
                    switch (status) {
                    case .succeeded:
                        guard let handledPaymentIntent = handledPaymentIntent else {
                            completion(.error, actionError ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unknown failure"]))
                            return
                        }
                        if (handledPaymentIntent.status == .requiresConfirmation) {
                            // Confirm again on the backend
                            MyAPIClient.sharedClient.confirmPaymentIntent(handledPaymentIntent) { clientSecret, error in
                                guard let clientSecret = clientSecret else {
                                    completion(.error, error ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse clientSecret from response"]))
                                    return
                                }

                                // Retrieve the Payment Intent and check the status for success
                                STPAPIClient.shared().retrievePaymentIntent(withClientSecret: clientSecret) { (paymentIntent, retrieveError) in
                                    guard let paymentIntent = paymentIntent else {
                                        completion(.error, retrieveError ?? NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Unable to parse payment intent from response"]))
                                        return
                                    }

                                    if paymentIntent.status == .succeeded {
                                        completion(.success, nil)
                                    }
                                    else {
                                        completion(.error, NSError(domain: StripeDomain, code: 123, userInfo: [NSLocalizedDescriptionKey: "Authentication failed."]))
                                    }
                                }
                            }
                        } else {
                            // Success
                            completion(.success, nil)
                        }
                    case .failed:
                        completion(.error, actionError)
                    case .canceled:
                        completion(.userCancellation, nil)
                    }
                }

Solution

  • My fix was to call paymentManager.confirmPayment(withParams: params, authenticationContext: self) instead of handleNextAction