#nikivi_webhooks
1 messages ยท Page 1 of 1 (latest)
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.
- nikivi_code, 7 minutes ago, 78 messages
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! We typically respond in a few minutes, but in some cases we might need a bit more time (e.g., server's busy, you've got a complex question, etc.).
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1254804551354028102
๐ Have more to share? Add details, code, screenshots, videos, etc. below.
.get('/webhooks/stripe/payment-success', async ({ headers, error, request }) => {
let event: Stripe.Event
assertString(webhookSecret)
const signature = headers['stripe-signature']
if (!signature) {
return error(400, 'missing signature')
}
const payload = await request.text()
try {
event = await stripe.webhooks.constructEventAsync(payload, signature, webhookSecret)
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error'
console.error(err)
console.error(`[stripe-webhook] Error message: ${errorMessage}`)
return error(400, `Webhook Error: ${errorMessage}`)
}
// Successfully constructed event.
console.log('[stripe-webhook] Success:', event.id)
try {
console.log(event, 'event')
} catch (err) {
console.error('[stripe-webhook] Error handling event:', err)
return error(500, 'Error handling event')
}
return { message: 'Received' }
})
is my code for webhook
I ran stripe listen --forward-to localhost:8787/webhooks/stripe/payment-success
in terminal
Hello
hey
trying to make sense as for how to make sure stripe checkouts get completed
and I need to get productId from metadata
.post(
'/create-product',
async ({ body }) => {
const { productTitle, productDescription, productPrice, productRoninId } = body
const session = await stripe.checkout.sessions.create({
success_url: 'https://solbond.co/payment-success',
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: productTitle,
description: productDescription
},
unit_amount: Math.round(Number(productPrice) * 100)
},
quantity: 1
}
],
mode: 'payment',
metadata: {
productRoninId: productRoninId
}
})
const checkoutSessionUrl = session.url
return checkoutSessionUrl
},
{
body: t.Object({
productTitle: t.String(),
productRoninId: t.String(),
productDescription: t.String(),
productPrice: t.String()
})
}
)
i have this endpoint to create checkout sessions
I get back url
I'm seeing that the Event you provided was indeed received by your endpoint and your endpoint returned a 200, however it also returned a response body of Error: NOT_FOUND
So you'll want to look in your code for where you send that response
.get('/webhooks/stripe/payment-success', async ({ headers, error, request }) => {
let event: Stripe.Event
assertString(webhookSecret)
const signature = headers['stripe-signature']
if (!signature) {
return error(400, 'missing signature')
}
const payload = await request.text()
try {
event = await stripe.webhooks.constructEventAsync(payload, signature, webhookSecret)
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error'
console.error(err)
console.error(`[stripe-webhook] Error message: ${errorMessage}`)
return error(400, `Webhook Error: ${errorMessage}`)
}
// Successfully constructed event.
console.log('[stripe-webhook] Success:', event.id)
try {
console.log(event, 'event')
} catch (err) {
console.error('[stripe-webhook] Error handling event:', err)
return error(500, 'Error handling event')
}
return { message: 'Received' }
})
is my web hook code
don't see NOT_FOUND mm
Alright well first thing I would do is add a log right at the start of your endpoint
And then re-test
console.log(webhookSecret, 'secret!!')
const signature = headers['stripe-signature']
if (!signature) {
return error(400, 'missing signature')
}
const payload = await request.text()
console.log(payload, 'payload')
ok trying with
trying it out
From your code though it looks like you aren't really handling any specific type of Event here. Like you can see in https://docs.stripe.com/webhooks/quickstart?lang=php that you will want a switch case to handle the specific Event types
Yep
So now you want to debug from there
ok fixed the assert thing
i do pass the secret 100% now
const signature = headers['stripe-signature']
if (!signature) {
return error(400, 'missing signature')
}
can I test this in my http gui app
i don't want to fill in the stripe checkout every time
its too long ๐ฆ
You can use the CLI to trigger Events to test
stripe trigger checkout.session.completed
@heavy cloud how can this be
if i hit it myself it works
but if i do it with stripe
its error
like its calling wrong url
stripe listen --forward-to localhost:8787/webhooks/stripe/payment-success
like there is something off with
Hmmm so the endpoint isn't hit at all?
yes
Your framework is returning the not found for that endpoint?
its hitting wrong endpoint
stripe is trying to hit wrong endpoint
that endpoint is there
i.e.
localhost:8787/webhooks/stripe/payment-success
stripe listen --forward-to localhost:8787/webhooks/stripe/payment-success
should work
in my eyes
๐
console.log(payload, 'payload')
try {
event = await stripe.webhooks.constructEventAsync(payload, signature, webhookSecret)
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error'
console.error(err)
console.error(`[stripe-webhook] Error message: ${errorMessage}`)
return error(400, `Webhook Error: ${errorMessage}`)
}
// Successfully constructed event.
console.log('[stripe-webhook] Success:', event.id)
try {
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`)
// Then define and call a method to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
break
case 'payment_method.attached':
const paymentMethod = event.data.object
// Then define and call a method to handle the successful attachment of a PaymentMethod.
// handlePaymentMethodAttached(paymentMethod);
break
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`)
}
} catch (err) {
i added switch
trying to get what event I want
i just want payment succeeded
Where are you setting metadata?
and be able to read the
metadata: {
productRoninId: productRoninId
}
const session = await stripe.checkout.sessions.create({
success_url: 'https://solbond.co/payment-success',
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: productTitle,
description: productDescription
},
unit_amount: Math.round(Number(productPrice) * 100)
},
quantity: 1
}
],
mode: 'payment',
metadata: {
productRoninId: productRoninId
}
})
const checkoutSessionUrl = session.url
return checkoutSessionUrl
its like this
.post(
'/create-product',
Okay so that metadata will be on the Checkout Session itself
payment_intent.succeeded
But you could pass metadata down to the PaymentIntent if you use payment_intent_data.metadata
this is one i care about?
Then you can just listen for payment_intent.succeeded
const paymentIntent = event.data.object
i get this
so the session is on that object?
No
You can look at our API Reference for what attributes are on each object. For instance for Checkout Sessions: https://docs.stripe.com/api/checkout/sessions/object
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
Checkout Sessions are "high-level" objects
So PaymentIntents live "below" Checkout Sessions
You would go Checkout Session --> PaymentIntent
Not the other way around
so given payment intent
i can somehow find the right session?
.post('/webhooks/stripe/payment-success', async ({ headers, error, request }) => {
let event: Stripe.Event
assertString(webhookSecret)
const signature = headers['stripe-signature']
if (!signature) {
return error(400, 'missing signature')
}
const payload = await request.text()
console.log(payload, 'payload')
try {
event = await stripe.webhooks.constructEventAsync(payload, signature, webhookSecret)
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error'
console.error(err)
console.error(`[stripe-webhook] Error message: ${errorMessage}`)
return error(400, `Webhook Error: ${errorMessage}`)
}
// Successfully constructed event.
console.log('[stripe-webhook] Success:', event.id)
try {
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`)
cause at this point
i only have paymentIntent
i think
and payload i guess
which has the events i parse
case 'payment_intent.succeeded':
const paymentIntent = event.data.object as Stripe.PaymentIntent
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`)
// Retrieve the Checkout Session associated with this PaymentIntent
const sessions = await stripe.checkout.sessions.list({
payment_intent: paymentIntent.id
})
if (sessions.data.length > 0) {
const session = sessions.data[0]
console.log('Associated Checkout Session:', session.id)
console.log('Checkout Session metadata:', session.metadata)
// Here you can access session details like:
// session.customer_details
// session.line_items (you might need to expand this when retrieving the session)
// session.metadata (where you stored custom data)
} else {
console.log('No associated Checkout Session found')
}
break
trying this
What information do you care about in the Checkout Session object?
Just the metadata?
Or other info as well?
metadata: {
productRoninId,
userBuyingId
}
i need this
to make a db
entry
i think just that is enough for me
Okay so then when you create your Checkout Session you should use payment_intent_data.metadata instead of metadata
Then in your Webhook handler you can just listen for payment_intent.succeeded and that metadata will be set on the PaymentIntent object
const session = await stripe.checkout.sessions.create({
success_url: 'https://solbond.co/payment-success',
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: productTitle,
description: productDescription
},
unit_amount: Math.round(Number(productPrice) * 100)
},
quantity: 1
}
],
mode: 'payment',
metadata: {
productRoninId,
userBuyingId
}
})
ok trying to get where payment_intent.succeeded goes
getting this weird error
i pass correct details I think mm
not sure about stripe using url-encoded post bodies
That error is coming from a library you are working with, not the Stripe API
ok turned it into json with this
and it works
ok testing checkout
๐
i get empty Checkout Session metadata
oh wait
case 'payment_intent.succeeded':
const paymentIntent = event.data.object as Stripe.PaymentIntent
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`)
// Retrieve the Checkout Session associated with this PaymentIntent
const sessions = await stripe.checkout.sessions.list({
payment_intent: paymentIntent.id
})
if (sessions.data.length > 0) {
const session = sessions.data[0]
console.log('Associated Checkout Session:', session.id)
console.log('Checkout Session metadata:', session.metadata)
// Here you can access session details like:
// session.customer_details
// session.line_items (you might need to expand this when retrieving the session)
// session.metadata (where you stored custom data)
} else {
console.log('No associated Checkout Session found')
}
break
this code should get the metadata from intent itself now
paymentIntent.metadata
i guess
Yep
case 'payment_intent.succeeded':
const paymentIntent = event.data.object as Stripe.PaymentIntent
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`)
console.log('---------------')
console.log(paymentIntent.metadata, 'metadata')
console.log('---------------')
ok trying
stripe trigger checkout.session.completed
this triggers intent.succeeded too right?
Yes
Can you give me that Event ID
.post(
'/create-product',
async ({ body }) => {
const { productTitle, productDescription, productPrice, productRoninId, userBuyingId } = body
const session = await stripe.checkout.sessions.create({
success_url: 'https://solbond.co/payment-success',
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: productTitle,
description: productDescription
},
unit_amount: Math.round(Number(productPrice) * 100)
},
quantity: 1
}
],
mode: 'payment',
payment_intent_data: {
metadata: {
productRoninId,
userBuyingId
}
}
})
const checkoutSessionUrl = session.url
return checkoutSessionUrl
},
{
body: t.Object({
productTitle: t.String(),
productRoninId: t.String(),
productDescription: t.String(),
productPrice: t.String(),
userBuyingId: t.String()
})
}
)
1 sec
evt_1PVEdZEApj6WQ8u04U35kX61
i think
thats the completed one
productRoninId should be rec_l4l501bmvf8lswr6
and userBuyingId 300
Oh sorry you are using the CLI here?
yes
You need to actually create the Checkout Session yourself
The CLI won't set this metadata for you
so this gives me
https://checkout.stripe.com/c/pay/cs_test_a1hn5jLXEIDnNm8E6MfXeqvFqmRklgFaZqon2gEUUHYAqT8i3kdVLVofN4#fidkdWxOYHwnPyd1blpxYHZxWjA0VUpLVDZARHVvM1JUPXA1Y1J3fFBVamt9SF9jNlFXSVRxdmxcb1V2cGdNfXFnZEBuakhjSUBWXWBwYU83UFdpNXx8UTxObDJnfDVSUVc8NlFXSEdSb2JUNTV%2FX25LVVZyTycpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl
this is what i will open for users for the product
so they buy it
let me try complete it
๐
๐
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
I can't seem to find how to pass cover image
to product
Hmm don't think you can do that inline
const session = await stripe.checkout.sessions.create({
success_url: 'https://solbond.co/payment-success',
line_items: [
{
price_data: {
currency: 'usd',
product_data: {
name: productTitle,
description: productDescription
},
unit_amount: Math.round(Number(productPrice) * 100)
},
quantity: 1
}
],
mode: 'payment',
payment_intent_data: {
metadata: {
productRoninId,
userBuyingId
}
}
})
Ah nvm
so I can't pass image
You can
?
oo