-1

So my ultimate goal is to be able to just make test payments with Apple Pay on Stripe, whether that be with a token or something else.

**EDIT **I have this function I use to gather card info from the stored card in the Wallet:

 func applePayContext(_ context: STPApplePayContext, didCreatePaymentMethod paymentMethod: STPPaymentMethod, paymentInformation: PKPayment, completion: @escaping STPIntentClientSecretCompletionBlock) {
    guard let paymentIntentClientSecret = paymentIntentClientSecret else {
        return;
    }

    let backendUrlForToken = "https://us-central1-xxxxxx-41f12.cloudfunctions.net/createStripeToken"
    let url = URL(string: backendUrlForToken)
    let pkToken = String(data: paymentInformation.token.paymentData, encoding: .utf8)
    guard let name = paymentInformation.billingContact?.name else { return }
    let nameFormatter = PersonNameComponentsFormatter()
    nameFormatter.string(from: name)
    let json: [String: Any] = [
        "card": [
            
            "address_city": paymentInformation.billingContact?.postalAddress?.city,
            "address_country": paymentInformation.billingContact?.postalAddress?.country,
            "address_line1": paymentInformation.billingContact?.postalAddress?.street,
            "address_state": paymentInformation.billingContact?.postalAddress?.state,
            "address_zip": paymentInformation.billingContact?.postalAddress?.postalCode,
            "name": name
        ],
        "muid": UIDevice.current.identifierForVendor?.uuidString,
        "pk_token": pkToken,
        "pk_token_instrument_name": paymentInformation.token.paymentMethod.displayName,
        "pk_token_payment_network": paymentInformation.token.paymentMethod.network?.rawValue,
        "pk_token_transaction_id": paymentInformation.token.transactionIdentifier
    ]
    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: json)
    let task = URLSession.shared.dataTask(with: request) { (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],
              let token = json["id"] as? String else {
                print("Error getting Stripe token")
                return
            }
        print("\(token)")
        self.stripeToken = token
        
    }
    
    task.resume()
    
    
    let error = NSError()
    completion(paymentIntentClientSecret, error)
    
}

I didn't have an endpoint for the API call so I created this request for a token. This is the function I have at my API endpoint:

exports.createStripeToken = functions.https.onRequest(async (req, res) => {
var cardAddressCity = req.body.card.address_city;
var cardAddressCountry = req.body.card.address_country;
var cardAddressLine = req.body.card.address_line1;
var cardAddressProvince = req.body.card.address_state;
var cardAddressPostalCode = req.body.card.address_zip;
var cardHolderName = req.body.card.name;

var muid = req.body.muid;
var pkToken = req.body.pk_token;
var pkTokenInstrument = req.body.pk_token_instrument_name;
var pkTokenNetwork = req.body.pk_token_payment_network;
var pkTokenTransactionID =  req.body.pk_token_transaction_id;

const token = await stripe.tokens.create({
  card: {
    "address_city": cardAddressCity,
    "address_country": cardAddressCountry,
    "address_line1": cardAddressLine,
    "address_state": cardAddressProvince,
    "address_zip": cardAddressPostalCode,
    "name": cardHolderName
  },
  "muid": muid,
  "pk_token": pkToken,
  "pk_token_instrument_name": pkTokenInstrument,
  "pk_token_payment_network": pkTokenNetwork,
  "pk_token_transaction_id": pkTokenTransactionID 
});

res.send({
  id: token.id,
});

});

I'm not sure if this is the correct way, I can't find much on the internet about this at all.

I figured this was the parameters I seen in my api logs so I used the same ones and I also seen a rare post on gist.github of a guy making an API call similar to this one, but for some reason it still doesn't work at all.

dante
  • 105
  • 11

1 Answers1

0

Your statements/logs aren't being hit because Token creation internally in STPApplePayContext is failing. For background, STPApplePayContext does:

  1. Create a Token from the Apple Pay encrypted card details.

  2. Using the Token, creates a PaymentMethod object.

  3. Then triggers the didCreatePaymentMethod() delegate implementation.

And step 1 is failing.

Typically when I've seen a Token creation request 500, that typically means there might be a mismatch on the merchant ID used on XCode vs the certificate set up on Stripe account. Or it could be some combination of a PKPaymentNetwork not being supported on a Stripe account country.

I would re-do the steps of setting up the merchant ID and Apple Pay certificate, ideally on a fresh project to do away with any confusion or conflicts etc.

Since this was a 500, Stripe Support would be the right people to deal with that, as the error possibly lies on their end. I would provide them request IDs for your /v1/tokens creation request.

hmunoz
  • 2,791
  • 5
  • 11
  • I don't know man, I don't know it all, but I'm very confident that it's not cause of the reasons you explained. If there was a mismatch, the Apple Pay sheet wouldn't show up at all, also, I've only kept the networks Canada supports. I don't have an endpoint for this API call so I think that's why I was getting the 500 errors, I ended up creating one that I will update and show in the post now. @hmunoz – dante Mar 23 '21 at 18:23
  • You don't have to do what that user is doing in that gist, that is unrelated, you are already using STPApplePayContext, a helper class that makes /v1/tokens calls under the hood for you. I speak from experience, it might not be what I said exactly but that is the first place to start. Also if it helps, I was who unblocked you with interac yesterday :) – hmunoz Mar 23 '21 at 23:36
  • I know man you're the goat and I still appreciate you for that, but what if I try both things and they still don't work, I mean I already reached out to support, but still. It's just frustrating being in a place of unknown, I have so many questions to ask like if i'm using the right methods, do I also need to implement `PKPaymentAuthorizationViewControllerDelegate` methods, and etc. Also with the API calls being made under the hood, does that mean I don't need to make a http request in Swift, and a function in my Cloud Functions file? @hmunoz – dante Mar 24 '21 at 14:08
  • I would build a new project and try it but first off, I have absolutely no idea what I'm doing when it comes to this Apple Pay integration neither do I have any knowledge about the issue that much, and that would make no sense to go through all that Apple Developer program setup again just to not know what I'm doing an be stuck again, you get what I'm saying? @hmunoz – dante Mar 24 '21 at 14:15
  • For Apple Pay, you should only do the iOS steps listed here: https://stripe.com/docs/apple-pay, so no you do not implement `PKPaymentAuthorizationViewControllerDelegate` as that is not required when using `STPApplePayContext`. Don't set up a new project, I just said to redo the Apple Pay cert and merchant ID steps on the doc link here in this comment. – hmunoz Mar 24 '21 at 23:39
  • "Also with the API calls being made under the hood, does that mean I don't need to make a http request in Swift, and a function in my Cloud Functions file?" -> No all I meant is, STPApplePayContext is a helper class that creates a PaymentMethod token for you. To charge that you still need to do whatever relevant API/Firebase calls you need to make (I cannot say, I don't have visibility into how your integration works) – hmunoz Mar 24 '21 at 23:40
  • The key part here is to understand the distinct components, what they do, then how they all fit together. Going from Apple Pay to "I don't need to make a http request in Swift, and a function in my Cloud Functions file?" is a big jump, you need to break the problem down further to fully understand what the Apple Pay part is doing first, and then understand if that is related to your Firebase code or not – hmunoz Mar 24 '21 at 23:41
  • Ok so I did what you said and I get 200 OK for v1/tokens, v1/payment_methods, and v1/payment_intent. How can I actually make the payment go through now, nothing goes through currently. In my non-Apple Pay checkout, I used `STPPaymentIntentParams` and I configured that with the `STPPaymentResult` and then used the `STPPaymentHandler` to confirm the payment. How can I do that with these parameters? @hmunoz – dante Mar 25 '21 at 17:10
  • Does your STPApplePayContext createPaymentMethod delegate give you a valid PaymentMethod ID? You set that on `STPPaymentIntentParams.paymentMethodId` and then call `confirmPayment()` like you would with a non Apple Pay card – hmunoz Mar 26 '21 at 19:09
  • Lol ok i just did that, and now in the `didCreatePaymentMethod` I get a `.succeeded` status but it still shows "Payment Not Completed" on the Apple Pay sheet, and then I get an `.error` in the `didFinishWithStatus` method. Why is this happening? @hmunoz – dante Mar 26 '21 at 19:20
  • ah you're using STPApplePayContext, so you don't manually call `confirmPayment` on `STPPaymentHandler`. STPApplePayContext confirms the PaymentIntent when you call `completion(clientSecret,nil)` and that confirms the PaymentIntent and also informs the Apple Pay payment sheet to dismiss with a "payment success" message. Right now since you are not calling completion, that is why the payment sheet thinks it isn't successful and it times out, showing that error. – hmunoz Mar 26 '21 at 20:47
  • Hey man, I appreciate all the help you've given in the last week, but please for the other beginners out there like me, maybe discuss to the developer team about adding a few more details to the Apple Pay integration docs, the steps help for sure, but there's so much little things left out that can make things harder than they need to be. Either way, I fixed what I needed to fix, thanks for the help. @hmunoz – dante Mar 26 '21 at 21:57
  • glad to hear you are unblocked! would love to hear more on which parts you got stuck on and which parts the docs weren't clear on (not saying you're wrong, I see that certain docs might require certain context on how Payments at Stripe work) so would love to hear feedback. – hmunoz Mar 29 '21 at 20:15