#alexzada - error
1 messages · Page 1 of 1 (latest)
await handleNextActions(paymentIntentClientSecret)
paymentIntentClientSecret comes from my server
Can you send me the entire function?
yep, 1 sec
`const handlePay = async () => {
setLoading(true)
const { paymentMethod, error: createPaymentMethodError } = await createPaymentMethod({
paymentMethodType: 'Card',
})
if (createPaymentMethodError) {
Alert.alert('Error', 'Houve um erro ao executar o pagamento. Por favor, tente novamente.')
return
}
await createPaymentIntent({
createPaymentIntentParams: {
paymentMethodId: paymentMethod.id,
},
onSuccess: async (data) => {
const { error: createIntentPaymentError, status, paymentIntentClientSecret } = data
if (createIntentPaymentError) {
Alert.alert('Error', 'Houve um erro ao executar o pagamento. Por favor, tente novamente.')
return
}
if (status === 'active') {
Alert.alert('Success', 'Pagamento efetuado com sucesso!')
}
if (status === 'incomplete') {
await handleNextActions(paymentIntentClientSecret)
}
},
onError: () => console.log('error'),
})
setLoading(false)
}`
export const createPaymentIntent = async ({ createPaymentIntentParams, onSuccess, onError, }:{ createPaymentIntentParams?: { paymentMethodId?: string, paymentIntentId?: string, }, onSuccess: (data: { paymentIntentClientSecret: string, status: string, error?: string, }) => void, onError: () => void }) => { try { const { data } = await axiosInstance.post('http://192.168.0.131:4242/pay', createPaymentIntentParams) onSuccess(data) } catch (error) { onError() } }
Hey apologies that I dropped off this thread for a bit. Can you try using just handleNextAction? As far as I can tell, we actually do not have a function defined that is called handleNextActions
I'm sorry, I missed a snippet of code, the handleNextActions function is a custom function of mine that calls handleNextAction inside it
`const handleNextActions = async (paymentIntentClientSecret: any) => {
const { error: requiresActionError, paymentIntent } = await handleNextAction(paymentIntentClientSecret)
if (requiresActionError) {
Alert.alert(`Error code: ${requiresActionError.code}`, requiresActionError.message)
return
}
if (paymentIntent.status === PaymentIntent.Status.RequiresConfirmation) {
await createPaymentIntent({
createPaymentIntentParams: {
paymentIntentId: paymentIntent.id,
},
onSuccess: (data) => {
const { error: requiresActionResponseError } = data
if (requiresActionResponseError) {
Alert.alert('Error', requiresActionResponseError)
return
}
Alert.alert('Success', 'Pagamento efetuado com sucesso!')
},
onError: () => Alert.alert('Error', 'Erro ao efetuar pagamento!'),
})
} else {
Alert.alert('Success', 'Pagamento efetuado com sucesso!')
}
}`
Sorry about the delay, been busy here, taking another look at this
ok, no problems
👋 stepping in. Can you confirm you are importing handleCardAction in that file?
And what version of the React Native SDK are you using?
of course, it's here, import { CardField, useStripe, initStripe, PaymentIntent, } from '@stripe/stripe-react-native'
const { createPaymentMethod, handleNextAction } = useStripe()
You don't initialize handleCardAction from useStripe
estava usando a 0.8.0 até hoje de manhã, atualizei para 0.9.0 há algumas horas
there is no handleCardAction there so I tried importing handleNextAction but it keeps giving the same error
Ah I misread before and thought you were attempting to use handleNextAction. Yes, handleCardAction is not a method in our SDK.
You would need to use handleNextAction
Let's back up a moment
ok
I assume you are attempting to handle 3DS if it is required, yes?
exactly
Okay and you look to be using CardField
yep
Is there a reason you aren't confirming client-side using confirmPayment?
the integration we are doing is synchronous with completion on the server, I believe that confirmPayment would not work for this case
basically our flow is, the customer puts the card information, I make a call to the route that creates a subscription in the backend and this route returns the status
Ah okay you are following our docs for manual confirmation
That flow wouldn't really be the same here for a Subscription... though it could work
The typical flow would be to create the Subscription with status: incomplete and pass the client_secret client-side to confirm with confirmPayment
what could i do for my case then?
I'd recommend using the flow I just mentioned. If you so desire, you can instead use handleNextAction .... handleCardAction is a typo in our docs and is a Stripe.JS method: https://stripe.com/docs/js/payment_intents/handle_card_action
I'll get that fixed up in the docs
but I keep getting the error that handleNextAction is not a function 😕
The screenshot you provided isn't an error?
It is just showing you how the method works
Unless you are talking about the original error that you started the thread with?
this screenshot?
Which makes sense because you didn't have handleNextAction imported
Sorry I was referring to the most recent one
yep
Yeah you need to import handleNextAction
but even after i imported it correctly, it keeps giving the error
import { CardField, useStripe, initStripe, PaymentIntent, handleNextAction, } from '@stripe/stripe-react-native'
yep
What do you see in Metro?
because of my implementation, nothing
` const { error: requiresActionError, paymentIntent } = await handleNextAction(paymentIntentClientSecret)
if (requiresActionError) {
Alert.alert(`Error code: ${requiresActionError.code}`, requiresActionError.message)
return
} `
since requiresActionError is true it puts an Alert on the screen
Thanks that helps
Actually I think I know the issue.... pretty sure this flow doesn't work if you don't have confirmation_method: manual set on the PaymentIntent. That is a weird error for us to throw though.
Can you try using confirmPayment instead of handleNextAction here and let me know what happens?
of course, I directly import like handleNextAction?
Yep
just change where there is handleNextAction by confirmPayment?
would it be this? const { error: requiresActionError, paymentIntent } = await confirmPayment(paymentIntentClientSecret, { paymentMethodType: 'Card', })
Yeah I think thats right except it would be const {paymentIntent, error} = await confirmPayment()
I don't think the error will specifically be a requiresActionError
is that I have error defined just above, so I just renamed the variable
Ah right right
nothing happened, neither on the emulator nor on the Metro
What test card are you using?
4000 0000 0000 0341
Can you provide the PaymentIntent ID that you are testing with?
Why are you using this card? 🙂
It declines on charge
where can i get this?
If you want to test 3DS you should be using one of the cards here: https://stripe.com/docs/testing#3d-secure-mobile-challenge-flows
can i use this 4000 0025 0000 3155?
Yeah that should work too
nothing happens yet
If you go to https://dashboard.stripe.com/test/logs in your Dashboard can you grab your most recent request and provide the ID here (req_xxxxx)?
I tested it on my fixed cell phone and it gave an error
req_zVqaSn94bliEfY
Okay can you log out the client_secret that you are using with confirmPayment?
not logging in where I put the log, I'll see what happened, a moment
I had changed the wifi and forgot to change the url in the api call...
this error appears now
lol glad we figured that out
` const { error: requiresActionError, paymentIntent } = await confirmPayment(paymentIntentClientSecret, {
paymentMethodType: 'Card',
})
console.log('paymentIntent', paymentIntent)`
this log paymentIntent undefined
Cause you hit an error above
About paymentMethodType
But paymentMethodType looks right to me there.... 🤔
for me too 🤷
Can you try just setting type: 'Card'
Yeah okay that's right... it should be paymentMethodType so that should error
but putting type works, I'm confused
Oh okay
Ah okay okay
I think your Android version is behind
For the Stripe Android SDK
Wonder if that is why you saw the error previously about the method not existing as well
how can we check this?
ah, ok
Okay so open your gradle.properties
Should be in your android/src directory I believe
I'm using expo, I believe I don't have that
lol ah didn't realize you are using expo
That is the issue
Okay so Expo is tied to a specific Stripe React Native version
So it sounds like you tried to install the latest Stripe RN SDK (0.9.0) while using Expo
As opposed to using expo install @stripe/stripe-react-native which will install the correct version for your Expo SDK
so i remove the dependency i installed earlier and install using expo install @stripe/stripe-react-native?
Yes
ok, one moment
ok, one moment
installed this version "@stripe/stripe-react-native": "0.2.3",
Yep okay
That's the latest version of our SDK supported on Expo
Alright so this is likely also why you were seeing the error with handleCardAction earlier... that was changed to handleNextAction in 0.7.0: https://github.com/stripe/stripe-react-native/blob/master/CHANGELOG.md#070
Okay so now back to the beginning.
The recommended route here is to just use confirmPayment
I think you can also use handleCardAction if you so desire, and want to then confirm the PaymentIntent later (though I haven't tested this on a Subscription flow so you would need to test).
But if you want to charge immediately upon the customer completing 3DS then you should just be using confirmPayment
what is the difference between handleCardAction and confirmPayment?
handeCardAction is designed to allow you to control when you actually complete the payment.
So with the manual confirmation flow a server-side confirmation is still required after handleCardAction is resolved successfully
That is the flow detailed here: https://stripe.com/docs/payments/accept-a-payment-synchronously?platform=react-native
We really don't recommend this flow.
It just adds complexity
There are a few use-cases that require it, so we support it. But really you should just confirm the payment when the card details are entered and handle it all client-side without needing to re-confirm on your server thereafter
While we're at it, let me ask you a question, we're currently using this synchronous stream that ends in the backend. Since our app connects customers with drivers who can transport objects and the main flow is, a customer requests a ride, pays for it, and this payment can be made in installments, and after payment confirmation the driver goes to the customer and takes his order, what would be the recommended flow for this type of app that needs payment confirmation right away?
I'm confused, why does that flow require backend confirmation?
The payment is up front for the ride, no?
because it was the way we found to confirm that the payment was actually made
Ah okay so you aren't using Webhooks then
nop
yep
Gotcha
So yeah the recommended route here is to use Webhooks
That said... this synchronous flow does function as a workaround to ensure you aren't missing reconciling payments
But it is pretty limiting
but, how would I tell my frontend at the time of payment that the payment was completed using webhooks?
You either handle the result of confirmPayment or you could wait for the webhook.
It depends on what you need to do on your frontend.
I don't quite understand this part yet 😣
Sure so confirmPayment will resolve into a paymentIntent when successful.
You can test this out right now
I don't remember exactly what we return via the SDK
But you can take a look at that response. If it isn't enough information, you would pass that PaymentIntent ID back to your server and retrieve the PaymentIntent from there (using: https://stripe.com/docs/api/payment_intents/retrieve)
That will give you full details on the PaymentIntent
This isn't foolproof though, which is why we recommend Webhooks.
It is possible that the client drops off after completing 3DS and the promise doesn't resolve client-side. In this case you want your Webhook to catch that payment
And also in this case your client dropped off so you don't need to worry about displaying anything client-side in that case.
there are so many buts haha, but ok, I'll try to absorb it all and give the guide another read
Really you should ignore the guide you were looking at before.
This is the flow you should really follow: https://stripe.com/docs/billing/subscriptions/build-subscriptions?ui=elements
Since you are using Subscriptions
In that flow, replace any time it discusses Elements with using the CardField with React Native
ok, thank you very much for your willingness to help