#heisend3rp-refund
1 messages · Page 1 of 1 (latest)
Hi! It looks like the refund didn't fail, but it's pending.
In the event you issue a refund to a customer that results in a negative Stripe balance, the refund will show as “pending.” The refund will not be sent to your customer until your balance is repaid and brought back into the positive and the full refund amount is available
https://support.stripe.com/questions/pending-refunds-due-to-insufficient-funds-or-stripe-balance
{
"id": "pyr_1KlqVCFQFr5kixFfmMabyTKA",
"object": "refund",
"payment_intent": "pi_3Kj4EIFQFr5kixFf0IrBtUzX",
"status": "failed",
"amount": 2300,
"balance_transaction": "txn_1KlqVDFQFr5kixFfpJCdYp9X",
"charge": "py_3Kj4EIFQFr5kixFf03rPd6AW",
"created": 1649319338,
"currency": "eur",
"metadata": {
"orderId": "szQd8bBMA2RqJWApvxI6"
},
"reason": null,
"receipt_number": null,
"source_transfer_reversal": null,
"transfer_reversal": null
}
That looks like failed to me 😅
Oh you are right, it first had a pending status, and now it's failed. Give me a few minutes to look into this.
Hey, taking over from @gloomy sierra - checking on this
any updates? @last canyon
I'm not sure why it failed. I know there normally an account review after an initial SEPA debit refund request: https://stripe.com/docs/payments/sepa-debit#refunds
But this was done before this refund was created
Have to retried to refund? It'll be safe to just re-attempt
ok, we will reatempt
retried refund did not update yet after 10 minutes...
@last canyon can you check again?
pyr_1KlqVCFQFr5kixFfmMabyTKA
but it seems to be the same refund object as the last one
you can see the new refund attempt in the activity of the payment intent
Hmm, weird. I didn't expect that
we are setting a idempotency key in the refund request. might this be the reason it is the same refund object?
Ah, yep
Those should be unique per request. Otherwise you're just re-attempting the previous request
You should only really re-use an idempotency key if the request returns a 500 error: https://stripe.com/docs/idempotency
we are using it since we are using cloud functions with at least once policy
But you received a 200 response
this will be tricky to do with our current implementation
You should never re-use the same idempotency key within a 24 hour window
why
?
Clients can safely retry requests that include an idempotency key as long as the second request occurs within 24 hours from when you first receive the key (keys expire out of the system after 24 hours). For example, if a request to create a charge doesn’t respond because of a network connection error, a client can retry the request with the same idempotency key to guarantee that no more than one charge is created.
just saw that the payment was disputed or at least it showed up just now
might this be the reason it failed in the first place?
Exactly. You received a 200 (sucessful) response the first time, by making the same API call with the same idempotency key you're just going to get back the exact same successful 200 response. We won't actually retry the refund (hence why the same pyr_xxx ID was returned)
I don't know, maybe. Either the customer has disputed the payment, or the bank has disputed it because there's insfficient funds: https://stripe.com/docs/payments/sepa-debit#disputed-payments
Ok, so at least we understand now why the refund failed.
coming back to the idempotency keys:
Let me explain again. We are using an asynchronous system with cloud functions for handling the payments. The cloud functions have an at least once policy, meaning that each function trigger gets executed at least once. Meaning it is possible that a certain function runs two times for one request. This is unlikely but possible.
To not charge customers twice for the same request we are using the idempotency key, generated by data in our database to ensure we use the same request.
As far as I understood til now, this is the way to go. The points you were mentioning above, made me unsure about our current implementation. This is why I want to dig deeper here a little bit.
Furthermore, we have another question. Is it possible to set a minimum amount that should stay available on the connected accounts? So when a refund is initiated we can guarantee, that the account has sufficient funds.
I know we could switch to manual payouts, but that would make reporting impossible for us, since the docs say we cannot see the pi that build up the payout for manual payouts.
To not charge customers twice for the same request we are using the idempotency key, generated by data in our database to ensure we use the same request.
Yep, that's an approriate use case for the idempotency key. In reality you should just accept the200response and prevent that function/API call from being re-attempted
Because in instances like this, where you actually need to retry a API call (i.e. the refund re-attempt), you want a unique key
afaik its not possible for us to prevent the second function execution
Furthermore, we have another question. Is it possible to set a minimum amount that should stay available on the connected accounts? So when a refund is initiated we can guarantee, that the account has sufficient funds.
There's no way to do that without manually managing the balance and payouts, no
since the docs say we cannot see the pi that build up the payout for manual payouts
Where does it state this?
ok, thanks for the info 🙂
Many external APIs (such as Stripe) let you supply an idempotency key as a parameter. If you are using such an API, you should use the event ID as the idempotency key.
Maybe there is a kind of hacky way for us where we are using transaction based databse writes that ensures the stripe api is only called once
Yep, as I said that's fine. But in the particular case of this refund it tripped you up. So you just need to be wary of that
But I guess I need to dig deeper into our codebase for this 😅
Ok. I feel like im ontop of the problem again. I understand now why it failed. But guess we need to refactor a little bit again
Thanks a lot for your help, Stripe support is amazing 🥰
Np!