I recently updated Stripe iOS SDK and API from 2019-05-16 version to the latest one. Previously my code was working fine with Charges API, but having issue with PaymentIntents now.
I work with Stripe Connect and custom accounts while creating separate charges and transfers.
The problem is that I get No such payment intent: (null) error when I attempt to make the initial payment. But a payment intent, in fact, is being created. The payment is "incomplete" and "PaymentIntent status: requires_payment_method".
On the other hand, if I manually replace the (clientSecret) that is passed from MyAPIClient.swift/createCustomerKey method to CheckoutViewController.swift/paymentContext(didCreatePaymentResult) method, with another clientSecret key from a previously incomplete charge, it all works fine and the payment is successful.
I can confirm that clientSecret key is being correctly passed from my server (Firebase Cloud functions) to client, and then from MyAPIClient to CheckoutViewController - see print()'s in the code below. I also double checked the API keys on front and back end.
Here is my backend code:
const stripe = require('stripe')(functions.config().stripe.token);
exports.createPaymentIntentForStripeAccount = functions.https.onRequest((req, res) => {
const uid = req.body.uid;
const amount = req.body.amount;
const currency = req.body.currency;
const customer_id = req.body.customer_id;
const transfer_group = req.body.transfer_group;
return stripe.paymentIntents.create({
amount: amount,
currency: currency,
customer: customer_id,
transfer_group: transfer_group,
capture_method: "manual",
}).then(function(paymentIntent) {
const clientSecret = paymentIntent.client_secret;
res.status(200).json(clientSecret);
});
});
Client side:
// MyAPIClient
func createPaymentIntent(amount: Int, bookingID: String, completion: @escaping ((Result<String>) -> Void)) {
let url = self.baseURL.appendingPathComponent("createPaymentIntentForStripeAccount")
let transfer_group = bookingID.components(separatedBy: "/").last!
let params: [String: Any] = [
"uid": UserService.currentUserProfile!.uid,
"customer_id": UserService.currentUserProfile!.stripe_customer_id!,
"amount": amount,
"transfer_group": transfer_group,
"currency": "USD"
]
Alamofire.request(url, method: .post, parameters: params)
.validate(statusCode: 200..<300)
.responseString { responseString in
switch responseString.result {
case .success(let clientSecret):
print(clientSecret)
completion(.success(clientSecret))
case .failure(let error):
completion(.failure(error))
}
}
}
// CheckoutViewController
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPPaymentStatusBlock) {
MyAPIClient.sharedClient.createPaymentIntent(amount: self.paymentContext.paymentAmount, bookingID: self.bookingRef.url) { result in
switch result {
case .success(let clientSecret):
let paymentIntentParams = STPPaymentIntentParams(clientSecret: clientSecret)
paymentIntentParams.configure(with: paymentResult)
print(clientSecret)
STPPaymentHandler.shared().confirmPayment(withParams: paymentIntentParams, authenticationContext: paymentContext) { status, paymentIntent, error in
switch status {
case .succeeded:
completion(.success, nil)
case .failed:
completion(.error, error)
case .canceled:
completion(.userCancellation, nil)
@unknown default:
completion(.error, nil)
}
}
case .failure(let error):
print("Failed to create a Payment Intent: \(error)")
completion(.error, error)
break
}
}
}
Any suggestion or feedback will be welcomed and greatly appreciated.
Thank you.