#jev-webhooks-express
1 messages · Page 1 of 1 (latest)
Hello! We'll be with you shortly. Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- jev-tipping-connect?, 55 minutes ago, 12 messages
Hello 👋
You can listen to webhook events on your server and manipulate your database accordingly
https://stripe.com/docs/webhooks
I think that is a complicated approach, i am managing confirmPayment and confirmCardPayment, on confirmCardPayment I could make some fetch to my endpoint to manipulate like this:
const response = await axios.post('/api/v1/stripe/create-payment-intent', {
amount: amounts.total,
currency: 'mxn',
customerId: customerId,
paymentMethodId: paymentMethodId, // Usa el método de pago guardado
})
const clientSecret = response.data.client_secret
// Confirma el pago con el método de pago guardado
const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {
payment_method: paymentMethodId,
return_url: `http://localhost:5173/success`,
})
if (error) {
setErrorMessage(error.message)
} else {
// Maneja el éxito del pago aquÃ
// TODO redirigir a success o cerrar todos los modales y mostrar notificacion
const response = await axios.post(`/api/v1/stripe/confirm-payment`, {
venueId: params.venueId,
billId: params.billId,
amount: amounts.amount,
tipPercentage: tipPercentage,
avoFee: amounts.avoFee,
})
navigate(`/success?payment_intent=${paymentIntent.id}`)
showNotification()
}
i want something similar on my confirmPayment
I mean it's upto you on how to handle this. If you make these calls from your client-side code then it's easy for an fraudster to modify your code and mess with your application.
Well, this payment only applies when I get a response from my backend that the payment is completed, if not then the payment will not be applied
Generally, I've seen folks use webhook events to trigger database related changes.
Well, this payment only applies when I get a response from my backend that the payment is completed, if not then the payment will not be applied
Right but in the code you shared, I see that you're creating PaymentIntent using your client-side code which exposes your private API key.
oh wait
nvm I read it wrong
Dont worry
I just want to make this approach on my confirmPayment
try {
const { user } = getUserLS()
const response = await axios.post(`/api/v1/stripe/create-payment-intent`, {
amount: amounts.total,
currency: 'mxn',
customerId: user.stripeCustomerId,
})
const { client_secret: clientSecret, id } = response.data
const { error } = await stripe.confirmPayment({
elements,
clientSecret,
confirmParams: {
return_url: `http://localhost:5173/pene`,
},
})
if (error) {
handleError(error)
} else {
console.log('THIS DOES NOT GET EXECUTED')
const response = await axios.post(`/api/v1/stripe/confirm-payment`, {
venueId: params.venueId,
billId: params.billId,
amount: amounts.amount,
tipPercentage: tipPercentage,
avoFee: amounts.avoFee,
})
setShowTipModal(false)
// Maneja el éxito del pago aquÃ
}
} catch (error) {
setErrorMessage(error.message)
} finally {
setLoading(false)
}
}
This is the one I want to solve
again, upto you on how you want to handle it.
Based on the code above, on a successful payment you'd be redirected to http://localhost:5173/pene
That's where you should check if the pi_xxx was confirmed successfully and if so, you can make the other request to your server
const response = await axios.post(`/api/v1/stripe/confirm-payment`, { venueId: params.venueId, billId: params.billId, amount: amounts.amount, tipPercentage: tipPercentage, avoFee: amounts.avoFee, }) setShowTipModal(false)
I'm guessing the above code doesn't execute because you're getting redirected?
But in confirmCardPayment, i did almost the same approach
so the http://localhost:5173/pene should be a backend route? verify if the data is correct and then redirect to the /success component correcly?
confirmPayment is different from confirmCardPayment
confirmPayment is also used for payment methods that require a redirect to different page (like klarna, etc...)
If you're only processing card payments then you can set redirect: if_required in confirmPayment
https://stripe.com/docs/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect
import useModal from '@/hooks/useModal'
import { useQuery } from '@tanstack/react-query'
import axios from 'axios'
import { Link, useSearchParams } from 'react-router-dom'
import Receipt from './Receipt'
import { Button } from '@/components/Button'
const Success: React.FC = () => {
const [searchParams, setSearchParams] = useSearchParams()
const paymentIntentId = searchParams.get('payment_intent')
const { openModal, closeModal, isModalOpen } = useModal()
const { data, isLoading, isError, error } = useQuery({
queryKey: ['paymentIntent', paymentIntentId],
queryFn: async () => {
const response = await axios.get(`/api/v1/stripe/payment-intent/${paymentIntentId}`)
return response.data
},
})
if (isLoading) {
return <div>Loading...</div>
}
if (isError) {
return <span>Error: {error.message}</span>
}
return (
<div>
<h1>Payment Successful!</h1>
<p>Pagaste: {data.amount / 100}</p>
<Receipt isOpen={isModalOpen.receipt} closeModal={() => closeModal('receipt')} paymentIntentId={paymentIntentId} />
<Button type="button" text="Obtener recibo" onClick={() => openModal('receipt')} />
<Link to={-1}>Volver a la página principal</Link>
</div>
)
}
export default Success
this is on my success route
You'd need to test the code 🙂 We can't say what's wrong with it just by looking at it
yes, but each time some user gets redirected to this route, the user can reload the page and the payment would get applied again
Yeah so you'd need to prevent that from happening!
this is also something you'd avoid if you handle database manipulations server-side using webhooks as the webhook event will only be delivered once
sure
Refer the doc: https://stripe.com/docs/webhooks#webhook-endpoint-def
It covers everything 🙂
In what part I need to implement the webhook in my code?
When the payment gets applied then what
HI 👋
I"m taking over and catching up. You've posted a lot of code but, in order to help me, can you describe in simple steps what your integration is doing?
NVm, i have a new question, i dont know each time i pay something, the webhook gets 4 events why?
each time i pay something
- What are you using to collect payment?
- What are the event types you are receiving?
200, im using stripe trigger CLI
What command are you using?
stripe trigger payment_intent.succeeded
Okay, in order to work, that trigger runs a set of fixtures
So for a payment intent to succeed first it must be created, which fires an event. Also, when a payment intent is paid it creates a Charge object which fires events as well
ok but it would not create multiple database mutations?
That is something you get to work out in terms of how you design your integration to respond to webhook events.
I didnt understand, Im afraid that if I get 3 responses, then the database will be manipulated 3 times..
Only if your code manipulates the database. You have a choice there.
But lets step back. The webhook events fire to inform you of changes. What is the problem with the database being updated 3 times?
well, if in the webhook i will add a payment, then it will add 3 payments
But that doesn't make sense. The Payment Intent returned in payment_intent.created and payment_intent.payment_succeeded is the same Payment Intent with the same ID
Ok, i will get back to that, now i dont know why on this webhook:
const doTest = (request, response) => {
const sig = request.headers['stripe-signature']
let event
console.log('sig', sig)
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret)
console.log('event', event)
} catch (err) {
console.error(`Error message: ${err.message}`)
console.error(`Error stack: ${err.stack}`)
response.status(400).send(`Webhook Error: ${err.message}`)
return
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntentSucceeded = event.data.object
// Then define and call a function to handle the event payment_intent.succeeded
break
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`)
}
// Return a 200 response to acknowledge receipt of the event
response.send()
}
i only can use it once i delete the try event, there is an error on this part:
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret)
errors
Response body
Webhook Error: No webhook payload was provided.
Error message: Webhook payload must be provided as a string or a Buffer (https://nodejs.org/api/buffer.html) instance representing the raw request body.Payload was provided as a parsed JavaScript object instead.
Signature verification is impossible without access to the original signed material.
The error message is fairly clear. You need to load the raw request. This is something Express requires you to specify.
Take a look at our starter code here: https://stripe.com/docs/webhooks/quickstart?lang=node
That should give you an example you can work off of
i think its becasue im using app.use(express.json())
Anything that transforms the payload from it's raw state will cause the signature verification to fail
😒
As you will see in the webhook code in the doc I shared, we use express.raw
jev-webhooks-express