stripe / stripe-terminal-android

Stripe Terminal Android SDK
https://stripe.dev/stripe-terminal-android/
Other
94 stars 46 forks source link

PaymentIntentCallback does not give PaymentIntent when onSuccess is called (not an offline payment) #390

Closed richardhuff closed 11 months ago

richardhuff commented 1 year ago

Summary

Android SDK v3.1 returns a PaymenIntent with a null ID when PaymentIntentCallback onSuccess is using Terminal retrievePaymentIntent (this clientSecret is properly set). I understand that payment intent id will be null for offline payments, but our account is not setup for offline payments.

The StripeTerminal SDK for iOS does not have this issue with our account.

Code to reproduce

  1. Initialize payment by calling retrievePaymentIntent with a client secret.
  2. PaymentIntentCallback calls onSuccess but the PaymentIntent object has no ID
  3. Payment status changed to WAITING_FOR_INPUT
  4. INFO sent for "Insert / Swipe / Tap"
  5. Tap card
  6. INFO sent for "Remove Card"
  7. In the log I see "class=RestClient message="url=https://api.stripe.com/v1/payment_intents/null request={}"
  8. REST call fails
  9. INFO sent for "CONFIRMATION_REQUIRED"

Android version

API 33

Impacted devices (Android devices or readers)

M2 readers

SDK version

StripeTerminal:3.1.0

Other information

billfinn-stripe commented 1 year ago

Hi @richardhuff -- can you share a reader serial number and a payment intent ID where you are seeing this behavior?

richardhuff commented 1 year ago

Payment Intent ID: bb219089-113b-440f-5a61-08dbd65023de

M2 Serial Number: STRM26138013054

billfinn-stripe commented 1 year ago

Hi @richardhuff -- can you share the Payment Intent ID that was returned by stripe.com when you created the Payment Intent using your backend? Can you describe how you are currently creating the Payment Intent?

We cannot reproduce the problem you are seeing, so we'd like to look closer at the logs.

richardhuff commented 1 year ago

I think the intent ID you are looking for is: pi_3O5Y9oDLDNlxUPbb0rOT4gvH

billfinn-stripe commented 1 year ago

Hi @richardhuff -- thanks for the extra info. I do see that Payment Intent successfully created, and I also see the error in our logs. I am still not able to reproduce the failure, so I have a few follow-up questions.

  1. Does this error happen every time, or is it intermittent?
  2. Can you share some code snippets that show exactly how you are retrieving the Payment Intent and passing it to collectPaymentMethod?
richardhuff commented 1 year ago

@billfinn-stripe, I get this issue every time. Here are screen shots of my code to show the flow. It is a Xamarin binding library. The intent is generated from our API, otherwise, I'm dealing with the client secret. image

image

image

image

billfinn-stripe commented 1 year ago

Got it. Thanks. Everything you're doing in the Java snippets looks like it should work.

@richardhuff -- we use Moshi for JSON serialization/deserialization. Do you have any special build rules or configurations related to Moshi that may be conflicting with the SDK? Can you share a bit more about your app architecture, including how your Xamarin binding fits into the picture?

Some other paths to explore:

richardhuff commented 1 year ago

Something I keep noticing is "CONFIRMATION_REQUIRED". Stripe documentation says that this occurs when source is set to "manual" and our backend API is not setting it to manual. This happens right after "remove card".

billfinn-stripe commented 1 year ago

Hi @richardhuff -- this sounds like a different issue, and it's best and fastest if you start with our support channel. Please reach out directly to our support team: https://support.stripe.com/contact.

billfinn-stripe commented 1 year ago

Hi @richardhuff -- have you had any luck either reproducing this issue with the example build or reproducing with a native Android app?

richardhuff commented 1 year ago

@billfinn-stripe -- Yes. The example app works. I even replaced the gradle dependencies with all the dependencies in my app to check for collisions or issues and that also works just fine. I also applied the proguard rules found in another issue reported regarding serialization ( [https://github.com/stripe/stripe-terminal-android/issues/386] ). This did not fix the issue in my app.

I did notice that the example app has the terminal creating the payment intent. That is different from us since our backend is generating the intent and passing the client secret to the client.

billfinn-stripe commented 1 year ago

@richardhuff -- it should be pretty straight-forward to change the example application to create the payment intent using the example backend and then use retrievePaymentIntent. We have an internal development app where I am able to create PIs via a backend and retrieve them without any problems.

I suspect there's something fishy going on with the Xamarin binding, but I can't be sure.

richardhuff commented 12 months ago

@billfinn-stripe -- I have tried both the docker container and the Ruby example and I keep getting errors.

  1. I am required to create a location before connecting. I cannot get the location from the reader onClick since it is not connected yet. The Android example did not have that endpoint implemented. So, I added createLocation in Retrofit and call it from the service.

@FormUrlEncoded @POST("create_location") Call<Location> createLocation(@Field("address") Address address, @Field("display_name") String name);

  1. It always gives me a "Payment Required" error when I call the service (create_location). getConnectionToken() does not throw an error so I know the service is running correctly, and the Terminal is successfully initialized. At this point, I am just trying to connect to the terminal, not even starting the payment lifecycle.

  2. Am I not getting a location from the reader since a payment intent is not being created from the terminal from the example app as is?

  3. I need a location via create_location before calling create_payment_intent to generate the intent. Again, I have to implement this in the Android code since the example application does not have this (just like create_location).

So, I'm stuck with the example app giving me "Payment Required" 402 before I can really do anything.

billfinn-stripe commented 12 months ago

I have tried both the docker container and the Ruby example and I keep getting errors.

Can you try hosting it using Render? It shouldn't matter, but that's how we do our testing.

I am required to create a location before connecting.

If your account already has a location created, you should not need to wire up creating a location within the example app. If you don't have a location created, you can create one using curl and use it within the application. Then, after tapping "Discover readers", tap "Last used location" and select the location that is associated with your account. Then, tap the reader that you want to connect to.

Similar to above, I suspect there's something going on with the Xamarin bindings. You can still try to create Payment Intents using the example backend, retrieve them via the SDK, and it should work.

richardhuff commented 11 months ago

@billfinn-stripe -- I figured out my problem. I have binding projects in Xamarin for the dependencies. My SquareUp Wire jars needed updated. Thanks for your help.