#resin - requires payment method

1 messages ยท Page 1 of 1 (latest)

potent hare
#

Can you share the payment intent id?

foggy vessel
#

the latest one is:

#

pi_3LfAHSJWQTk4ZLla06AhSTVv

potent hare
#

Yeah so you never add a payment method to the payment intent. You need to confirm with a payment method first. Here's the only 2 requests related to the payment intent: https://dashboard.stripe.com/logs/req_GOIBEnXZhytvW9 and https://dashboard.stripe.com/logs/req_4AM9yDITK9fmCt

#

What integration guide are you following?

foggy vessel
#

Unfortunately I dont have access to those logs. They are a client of ours (the Chicago Cubs). So wont be able to review them.

#

FYI, out of thousands of successful payments, we only see this happen a couple times.

potent hare
#

Oh that's good to know

#

Thanks

#

Let me see if I can get a colleague to help on this

foggy vessel
#

Awesome! thanks for the help

halcyon tundra
#

Hello ๐Ÿ‘‹ Stepping in to help out since the server is running a little busy

foggy vessel
#

Hi. Thanks!

halcyon tundra
#

So it looks like you're using manual capture for the payments
Can you share what your collectPaymentMethod and processPayment functions look like?

foggy vessel
#

private void collectPayment(@NotNull PaymentIntent paymentIntent,
StripePaymentResponseHelper stripePaymentResponse) {

    Terminal.getInstance().collectPaymentMethod(paymentIntent,
            new ReaderDisplayListener() {
                @Override
                public void onRequestReaderInput(@NotNull ReaderInputOptions readerInputOptions) {
                    stripePaymentResponse.onReaderMessage(readerInputOptions.toString());
                }

                @Override
                public void onRequestReaderDisplayMessage(@NotNull ReaderDisplayMessage readerDisplayMessage) {
                    stripePaymentResponse.onReaderMessage(readerDisplayMessage.toString());
                }
            },
            new PaymentIntentCallback() {
                @Override
                public void onSuccess(@NotNull PaymentIntent paymentIntent) {
                    processPayment(paymentIntent, stripePaymentResponse);
                }

                @Override
                public void onFailure(@NotNull TerminalException e) {
                    stripePaymentResponse.onFailure(e);
                }
            });
}

private void processPayment(PaymentIntent paymentIntent,
                            StripePaymentResponseHelper stripePaymentResponse) {

    Terminal.getInstance().processPayment(paymentIntent, new PaymentIntentCallback() {
        @Override
        public void onSuccess(@NotNull PaymentIntent paymentIntent) {
            stripePaymentResponse.onSuccess(paymentIntent);
        }

        @Override
        public void onFailure(@NotNull TerminalException e) {
            stripePaymentResponse.onFailure(e);
        }
    });
}
#

if they are manual then how come only a few out of thousands fails when processing on the php server side?

halcyon tundra
#

So the reason you're seeing the error is somehow your code is trying to capture the payment intent before it has been confirmed with a payment method

For example
https://dashboard.stripe.com/logs/req_fpnYV9zQx4ymy1
If you look at this request, it confirms the PaymentIntent with the collected PaymentMethod information and moves the PaymentIntent to requires_capture status

For the PaymentIntent that you've shared above, that isn't the case. We're not seeing a request to confirm the PaymentIntent with the collected PaymentMethod. Instead your code is still trying to capture the PaymentIntent. Without additional logs from the device, its hard to tell what's exactly causing collectPaymentMethod to fail or why it still keeps on going with processPayment even without the payment method information.

foggy vessel
#

wont be able to view those logs as its a clients account

looking at my code, theres no way to call processPayment without collectPaymentMethod returning onSuccess. so I agree, its strange. Just to give you more info on the process we have setup. Once processPayment is successful in our app, we send the payment to out backend for processing. It only at that point the error is thrown.

This is out backend code:

            \Stripe\Stripe::setApiKey((string) Config::getInstance()->stripe->secretkey);
            $intent = \Stripe\PaymentIntent::retrieve($order['reference']);
            $intent = $intent->capture();

This is the error again:

This PaymentIntent could not be captured because it has a status of requires_payment_method. Only a PaymentIntent with one of the following statuses may be captured: requires_capture

halcyon tundra
#

Do you have the serial number of the reader that's running into this issue?

Also, have you observed any pending/un-captured PaymentIntents of the same amount getting created?

foggy vessel
#

Unfortunately the devices are in Chicago and Im in Vancouver lol so wont have SN's. I could get them in a couple days but not right now.

Amounts on failed transaction are not always the same.

couple of questions:

  • how/where is manual or automatic payment capture defined?
  • can processPayment onSuccess return requires_capture status? Maybe this is whats missing in the code. the onSuccess is call but requires_capture is not checked, causing the payment processing on the backend to fail
halcyon tundra
#

1/ You're passing capture_method: manual while creating the PaymentIntent which tells the API to not automatically capture it when PaymentMethod is collected.

2/ With manual capture, you'd typically use processPayment's onSuccess block to tell your server to capture the PaymentIntent.

Terminal.getInstance().processPayment(paymentIntent,
You do get access to PaymentIntent object here though so you can theoretically check if the PaymentIntent is in requires_capture status and if not, you can just re-run collectPaymentMethod

foggy vessel
#

this is our payment intent creation. maybe Im missing something. I dont see where to set the capture method

#

private void initiatePayment(int amount,
String currency,
StripePaymentResponseHelper stripePaymentResponse) {

    PaymentIntentParameters params = new PaymentIntentParameters.Builder()
            .setAmount(amount)
            .setCurrency(currency != null ? currency.toLowerCase(Locale.ENGLISH) : "usd")
            .build();

    Terminal.getInstance().createPaymentIntent(params, new PaymentIntentCallback() {
        @Override
        public void onSuccess(@NotNull PaymentIntent paymentIntent) {
            collectPayment(paymentIntent, stripePaymentResponse);
        }

        @Override
        public void onFailure(@NotNull TerminalException e) {
            stripePaymentResponse.onFailure(e);
        }
    });
}
halcyon tundra
foggy vessel
#

sorry mate, again, wont be able to see these logs. I dont have the Cubs dashboard login access

halcyon tundra
#

OH, I see. My bad, I thought you didn't have access to device logs ๐Ÿ˜…

foggy vessel
#

no worries lol now you see what im working with

#

Do you know if that capture_method manual POST is coming from the php backend or the android app?

halcyon tundra
#

The creation request's source is Android SDK so I believe its coming from the app

foggy vessel
#

So the app's processPayment call is sending capture method of manual. Can you see if this is the case for all payments of only a few?

halcyon tundra
#

I believe its createPaymentIntent that's setting the capture method
Checking the API ref to make sure its not the SDK setting it by default

foggy vessel
#

good idea. thanks

halcyon tundra
#

While I'm looking, if you have a test environment setup and are able to create a new PaymentIntent then it'd be faster to get there

foggy vessel
#

also good idea. just check getCaptureMethod() ?

halcyon tundra
#

or just create a new PaymentIntent in test mode and I can just look up the request

foggy vessel
#

heres a couple more intent id's to check if manual method was used

#

pi_3LfA9SJWQTk4ZLla1H2Ib5m4
pi_3LgDwzJWQTk4ZLla1MZn0eof
pi_3LgDwVJWQTk4ZLla1Kc5y42h
pi_3LfB0wJWQTk4ZLla0QOEIWrf

halcyon tundra
#

yup all of them have capture_method: manual

foggy vessel
#

hmm strange that most process without error and only very few fail then

#

im assuming they are all manual captures at this point

halcyon tundra
#

I'd recommend modifying your code in processPayment to check wether the PaymentIntent has requires_capture status and only then proceed with capturing

foggy vessel
#

in the docs it says "For manual capture of payments, a successful processPayment call results in a PaymentIntent with a status of requires_capture.".
Wont all payments return requires_capture?

#

sorry, just so I understand, its possible for processPayment->onSuccess to be fired without requires_capture status and I should return an error to the user at that point?

halcyon tundra
#

sorry, just so I understand, its possible for processPayment->onSuccess to be fired without requires_capture status and I should return an error to the user at that point?
Yes, it's unlikely but I think that's what's happening here. I don't know why its happening (without looking into device logs, it isn't possible to know) but if you add in a conditional before calling the capture API then you should be able to handle this in the app gracefully and possibly trigger payment method collection again.

foggy vessel
#

ok will play around with it. thanks!

#

btw, ive worked with many CC processors over the years and this discord dev support is a great idea