I am using swiftUI. My code currently is using PassKit alone. It integrates with swiftUI nicely and I am able to get the payment.token encrypted from apple pay. I want to use that token, and tokenized it client-side (according to stripe docs, this is the best way to stay compliant with laws) and send it to stripe to complete the payment. I am having issue as to what API endpoints to call in order to send and complete all this while staying compliant. The docs only show using Stripe SDK which is very hard to integrate with swiftui.
import PassKit
import Stripe
typealias PaymentCompletionHandler = (Bool) -> Void
class PaymentHandler: NSObject{
static let supportedNetworks: [PKPaymentNetwork] = [
.amex,
.masterCard,
.visa
]
var paymentController: PKPaymentAuthorizationController?
var paymentSummaryItems = [PKPaymentSummaryItem]()
var paymentStatus = PKPaymentAuthorizationStatus.failure
var completionHandler: PaymentCompletionHandler?
func startPayment(client: ClientData, completion: @escaping PaymentCompletionHandler) {
let cartTotal = client.cart.totalPrice
let salesTax = client.cart.tax
let amount = PKPaymentSummaryItem(label: "Amount", amount: NSDecimalNumber(value: cartTotal), type: .final)
let tax = PKPaymentSummaryItem(label: "Tax", amount: NSDecimalNumber(value: salesTax), type: .final)
let total = PKPaymentSummaryItem(label: "ToTal", amount: NSDecimalNumber(value: cartTotal + salesTax), type: .final)
paymentSummaryItems = [amount, tax, total];
completionHandler = completion
// Create our payment request
let paymentRequest = PKPaymentRequest()
paymentRequest.paymentSummaryItems = paymentSummaryItems
paymentRequest.merchantIdentifier = "merchant.com.xxxxx"
paymentRequest.merchantCapabilities = .capability3DS
paymentRequest.countryCode = "US"
paymentRequest.currencyCode = "USD"
// .phoneNumber, .emailAddress, .postalAddress
paymentRequest.requiredShippingContactFields = []
paymentRequest.supportedNetworks = PaymentHandler.supportedNetworks
// Display our payment request
paymentController = PKPaymentAuthorizationController(paymentRequest: paymentRequest)
paymentController?.delegate = self
paymentController?.present(completion: { (presented: Bool) in
if presented {
NSLog("Presented payment controller")
} else {
NSLog("Failed to present payment controller")
self.completionHandler!(false)
}
})
}
}
/*
PKPaymentAuthorizationControllerDelegate conformance.
*/
extension PaymentHandler: PKPaymentAuthorizationControllerDelegate{
func paymentAuthorizationController(_ controller: PKPaymentAuthorizationController, didAuthorizePayment payment: PKPayment, completion: @escaping (PKPaymentAuthorizationStatus) -> Void) {
// // Perform some very basic validation on the provided contact information
// if payment.shippingContact?.emailAddress == nil || payment.shippingContact?.phoneNumber == nil {
// paymentStatus = .failure
// } else {
// // Here you would send the payment token to your server or payment provider to process
// // Once processed, return an appropriate status in the completion handler (success, failure, etc)
// paymentStatus = .success
// }
let data = payment.token.paymentData
let json = try! JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
print(json)
paymentStatus = .success
completion(paymentStatus)
}
func paymentAuthorizationControllerDidFinish(_ controller: PKPaymentAuthorizationController) {
controller.dismiss {
DispatchQueue.main.async {
if self.paymentStatus == .success {
print()
self.completionHandler!(true)
} else {
self.completionHandler!(false)
}
}
}
}
}
I am thinking of sending the token/ tokenizing it in the paymentAuthorizationControllerDidFinish() function on .success and let stripe finish the charge.
Currently I think the steps are:
Create a new stripe customer on backend when apple Pay is tapped -> send id back to client.
Create a payment intent -> send id back to client.
3...? I am lost here on sending stripe all of the above along with the payment source, in my case is an encrypted payment token by apple.
i have tried sending a request to https://api.stripe.com/v1/charges? api and sending the entire token, but it says invalid request. I know its brute forcing but i am desperate :/
UPDATE 2
I used
STPAPIClient.shared().createPaymentMethod(with: payment) { (source, err) in
if let err = err {
print(err.localizedDescription)
self.paymentStatus = .failure
completion(self.paymentStatus)
}
// returns a hashable [dictionary]
guard let sourceDetails = source?.allResponseFields else
{
self.paymentStatus = .failure
return
}
print(sourceDetails)
AF.request("http://localhost:5001/rxxxxx/us-central1/paymentIntent", method: .post, parameters: ["data" : sourceDetails]).response { (response) in
if let data = response.data {
guard let res = String(data: data, encoding: .utf8) else {return}
print(res)
} else {
print("almo fire err")
}
}
And my backend returns a success response from Stripe [DELETED]
However, nothing has been charged or created in my Stripe dashboard.
**UPDATE 3**
I was able to confirm the payment intent using postman and calling the API and passing in the PayMent Method id directly. Still trying to implement using typescript.
LAST QUESTION. Is this PCI compliance? I have zero idea how all this is working. No client is created in dashboard, is this even working? The charges are being posted though. I am just confused because everything that i passed around didn't even show a full card number....