#ced_refund-amount-events
1 messages ยท Page 1 of 1 (latest)
๐ 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/1253363519856840737
๐ Have more to share? Add details, code, screenshots, videos, etc. below.
payment_intent.succeeded is triggered when the payment succeeds (so that has to be before any refund is created)
That's why it wouldn't show amount after refunds
You should separately listen for charge.refunded: https://docs.stripe.com/api/events/types#event_types-charge.refunded
To get notified for refunds that will come later (after payment_intent.succeeded)
OK I am confused because I got a case where the refund was done before succeed (SEPA) so we receive the payment_intent.succeeded after the charge.succeeded
And the payment_intent.succeeded contains the refund data as pending.
So I can I know that the late payment_intent.succeeded does not contain proper information?
The payment intent.succeeded amount will always contain the original amount charged. So you'd need to do the math yourself
How can I do the math if the refund state is still pending is the webhook when I already received charge.succeeded with the amount_refunded filled?
Should not the order of the events be corrected? payment_intent.succeeded and then charge.succeeded?
For synchronous payment intents yes. But sepa is async and takes time to process.
Can you share an event where this happened though?
So I can make sure everything is normal?
pi_3PJg3fCYunyA92951YwmMfOW
Indeed I do not mind if the events are not ordered but the event sent later should not contain old data
The payment intent amount will always reflect the original amount charged
Always
Refunds are tracked on separate objects
So what happened in the above example, was the payment was refunded prior to it succeeding (since sepa is async). That refund went into a pending state until charge succeeded. Once charge succeeded, then the refund cleared. https://dashboard.stripe.com/events/evt_1PNkxYCYunyA9295yfi9sV08
Sign in to the Stripe Dashboard to manage business payments and operations in your account. Manage payments and refunds, respond to disputes and more.
OK but the payment_intent.succeeded event contains the refunds but it is an old version because it is pending.
Yep
That's why you need to listen for charge.refund.updated
To be notified when it succeeds
So this means that I can not trust the data from the events and I must request a read on the objects to get the latest data?
I already listen to it but this came before the payment_intent.succeeded so the information from charge.refund.updated has be override by the data from payment_intent.succeeded (but they are wrong).
You get multiple charge.refund.updated events
You got one earlier before payment_intent.suceeded
But the one I linked above came after
The succeeded one
That came on 2024-06-04 00:10:40
Payment intent succeeded was on 2024-05-28 00:10:17
So the refund succeeded days later
Oops I mean charge.succeeded instead of charge.refund.updated
The charge.succeeded received first contain the amount_refunded but the payment_intent.succeeded received later don't
The charge.refund.updated is not helpful for me because it does not contain the full picture of charge.
Hi ๐
I'm stepping in as my colleague needs to go soon
If you need more details about the charge you can always retrieve it via the API.
https://docs.stripe.com/api/charges/retrieve
But it is a shame to not be able to track correctly the final amount with just the event data
Sorry there is a lot of back and forth here so it' s hard to be clear. What exact data are you looking for here?
I try to follow the exact amount is received for a payment.
So I listen to events like payment_intent.succeeded and charge.succeeded.
From payment_intent.succeeded I store the 'amount_received',
and from charge.succeeded i store 'amount' - 'amount_refunded'.
I have only one record for the payment intent and charge with a field amount to keep up to date.
So the problem is that payment_intent.succeeded was received after charge.succeeded. And that 'amount_received' is not updated to the real amount received.
Sorry what do you mean by "the real amount recieved"? Also, do you have an example event ID I could review?
"the real amount recieved" is the money that I will have at the end. (so amount - amount_refunded)
pi_3PJg3fCYunyA92951YwmMfOW
Okay so the issue here is that the amount: 11621 is what is returned in the PI but you need to calculate your own final amount using charge.amount - charge.amount_refunded. In that case would not charge.succeeded work as an event to listen to?
What is on the Payment Intent that you need?
I do not know. This is a new object that I need to create now. Before I used only charge and it was fine.
But now I see that charge.amount_refunded is filled even if the refund is pending. But there is not charge.updated event after the refund is succeeded.
so now I do not know what data I can trust
amount_refunded is filled even if the refund is pending
Do you have an example I can review?
evt_3PJg3fCYunyA9295184stajF
The refund may show as pending but the funds had left your Stripe balance so I think that is accurate in terms of what track on your end
May it fail later? If yes would there be an event other than charge.refund.*
I think you mean charge.refund.updated
I'm asking this because from charge.refund.updated I do not have enough information to compute charge.amount - charge.amount_refunded without having to fetch the payment (which I would like to avoid).
I think trying to hard to avoid the second API call is causing more friction that it is worth. In some scenarios where you need more data I think it makes sense to retrieve the object that has the data you want.
OK but this does not answer my question about refund failing later.
It may if we are unable to communicate with bank that the refund is being sent to.
And in this case what are the events that will be triggered?
charge.refund.updated like I mentioned earlier. We have a doc that describes how this works for both sync and async payment methods here: https://docs.stripe.com/refunds#failed-refunds
but no charge.refunded or charge.updated? Because the charge.amount_refunded must have been updated no?
That doc describes the event we emit in the case of a refund failure.
OK then I will have to read the charge but will the charge.amount_refunded be updated to remove the failing refund amount?
I recommend you test this out yourself. We actually provide testing card numbers that specifically trigger an asynchronous refund failure here: https://docs.stripe.com/testing#refunds
That way you can design your integration to handle this scenario and be sure how it will respond
I tested and charge.amount_refunded is updated