#ryan-connect-application-fee-refund
1 messages · Page 1 of 1 (latest)
hey ryan, you'll need to review the balance transactions in this case to see that level of detail
I found that this even tends to be innacurate in certain cases
can you provide an example of that?
yea give me a second
pi_2Ja4DaUmS57H7yUM0anAJZK6
so we do a partial refund direct to the buyer and avoid taking money from the Connect account
This happens when we have taken too much in taxes and want to do a partial refund direct to the customer because it was part of the application fee that directly went to us
however when we look at the last refund re_2Ja4DaUmS57H7yUM0L4J0fU3
There is no way to see how much has come out of the primary(my) stripe account
As the partial refund was never logged as a application fee refund so when we do the full refund it lists that it is doing a full refund of the application fee when in reality it is only doing part of it because we already refunded a certain amount.
I know we could do an application fee refund then do a reverse transfer so it correctly shows up in stripe, but that means I could incur a double exchange fee when that may not be necessary
I'm not sure about that last part, but looking at the refund eg, does the balance transaction not show you what you are looking for here with the amount moved from the account?
It shows the full amount moved from my account in EUR but I can't find how much was moved from the Connect account
Ah i think i see now
so looking at the charge/refund, you'd want to inspect the transfer_reversal : https://stripe.com/docs/api/refunds/object#refund_object-transfer_reversal
which in this case reveals the amount withdrawn in eur
Did that get you the info you needed?
where are you looking, exactly?
we looked in transfer_reversal, we looked in charge.refunds we looked in charge.application_fee.refunds
hrm it might work though
let me try
nope doesn't show enough info. We refund 100 EUR, transfer reversal says 100 EUR. We have no idea how much came out of the connect account or our account as it kinda mushes it together
so lets say we have 110 EUR charge with 25 EUR application fee.
We do an initial partial refund of 10 EUR from my account to the buyer because of a tax error.
Then we do a 100 EUR refund. I think stripe pulls 100 EUR from the connect account and take 15 EUR from my account
But there is no way to see the 15 EUR from the account. I can do math on my side to figure it out, but this isn't always accurate due to exchange rates changing over time. So it might actually pull say 15.50 EUR to account for a fluctuation in the charge amount exchange rate
It would be so much simpler though if we could just get the net changes in my account and the seller account after a given transaction
@eternal flint What matters here is the BalanceTransaction. This represents the real movement of funds in your own balance. Every object that represents money movement (Charge, Refund, Transfer, TransferReversal, etc.) has an associated balance_transaction property with all the information you're after. What you can do is use the https://stripe.com/docs/expand feature to expand those in full BalanceTransaction objects
Does that make sense?
it does however how do I know the amount that came out of the Connect account then?
Every single object has a BalanceTransaction like I mentioned, so you find the information on the relevant object
If you have a Destination charge you have a Charge on the platform (ch_123) that creates a Transfer (tr_123) still on the platform and that creates what we call the "destination payment" on the connected account which is a Charge (py_123)
When you refund the charge you get a Refund (re_123) and you also pull funds back from the connected account by reversing the transfer and getting a TransferReversal (trr_123) and that refunds the "destination payment" so you get a Refund on the connected account (pyr_123)
Each of those objects (+ the ApplicationFee and ApplicationFeeRefund if you use that) will have the balance_transaction property with the information you want
Can you share some code on how you create a refund today via the API? Then I can show you how to tweak it
I honestly believe my code is too far gone at this point
Stripe::Refund.create(
charge: charge_id,
amount: amount_cents, # 90000
refund_application_fee: true,
reverse_transfer: true,
expand: ['balance_transaction', 'charge.application_fee.balance_transaction'],
)
When I look at the transfer_reversal here I only see 90000.
yeah you don't expand enougj objects really
charge: charge_id,
amount: amount_cents, # 90000
refund_application_fee: true,
reverse_transfer: true,
expand: [
'balance_transaction', # BT for the Refund on your account
'source_transfer_reversal.balance_transaction', # BT for the transfer reversal
'source_transfer_reversal.destination_payment_refund.balance_transaction', # BT for the refund on the connected account
],
})```
try ^, this should show you most of the relevant objects. The only tricky one left is Application Fee because they are harder to debug. But let's start with this and you looking at each relevant object
source_transfer_reversal is null for me
ah yes my bad, sorry all the names are so close to each other you want transfer_reversal
Basically it's Refund re_123 -> transfer_reversal -> TransferReversal trr_123 -> destination_payment_refund -> Refund pyr_123
and the way back it's Refund pyr_123 -> source_transfer_reversal -> TransferReversal trr_123 -> source_refund -> Refund re_123
so the original charge is in GBP, the Connect account is in EUR
the refund.transfer_reversal.destination_payment_refund.balance_transaction returns the full refund amount in EUR
which doesn't tell me the net amount that comes out of the refund
I was able to get the application fee but it is a really ugly process
but that is the application fee only in the Connect currency and not my account
the way I get it now is by going into refund.charge.refunds and refund.charge.application_fee.refunds and filtering them for past refunds and then subtracting that from the refund.charge.application_fee.amount_refunded using the many exchange_rates that are returned in the response. The logic to get the exchange rates is really confusing though because depending on which currencies are the buyers and connect accounts they have different edge cases
We noticed that when we did our own math to calculate the account balances, when we compared them to stripe they were quite a bit off due to subtle exchange rate differences over time and the hidden exchange_rate fee that built into the exchange_rate
I have a feeling there isn't a simple way of getting that information and should just do the math on our side separately and tell accounting we can't track it and just write it off to revenue control
I don't really understand what math you're doing on your own? Like overall, we have an exchange rate and an FX fee too, this is all blended in your pricing and you should trust our numbers
One example is that when we look at our charge.application_fee.balance_transaction
If we multiply charge.application_fee.amount with charge.application_fee.balance_transaction.exchange_rate The value that results tends to be higher than charge.application_fee.balance_transaction.amount
do you have a concrete/specific example?
yea sure
there's some rounding involved but it should just be off by a cent, not higher and getting details information (exact object ids, exact values/amounts and your math would help
looking at fee fee_1Ja4DbRtqiHiNTNRhFh3v1wQ on charge ch_2Ja4DaUmS57H7yUM0njMu96d
fee.amount = 67592
fee.currency = 'gbp'
fee.balance_transaction.exchange_rate = 1.3828
fee.balance_transaction.amount = 91597
fee.balance_transaction.currency = 'usd'
fee.amount * fee.balance_transaction.exchange_rate = 93466.2176
which ends up being a diff of 1869.2176000000036
this ends up being about 2% of the entire charge. We figured it was stripe fees. Currency conversion incurs a 2% fee atop market exchange rates. https://stripe.com/blog/new-currencies
correct, that's the FX fee in that case
We can get that on the initial charge easily
Out of curiosity, did you consider moving away from application fees and using transfer_data[amount] instead to transfer less to the connected account? It tends to make reconciliation a lot easier
but getting that value on refunds is super hard
oh interesting?
I have not heard of this
Basically there are 2 approaches to taking a fee as a platform. One is Application Fees and the other is to just transfer less
App fee: Charge $100, send the funds to the connected account (all $100) and then get back $10 to yours as an application fee
Transfer: Charge $100, but configure to only send $90 to the connected account and then keep $10 yourself
it's quite similar though there are less objects to keep track of and less currency conversion(s)
one downside is that with the second flow you can't just keep your fee. So you can't charge $100, take $10 as an app fee, but later if you refund the connected account owes the $100 and you keep your $10
but you seem to not keep your fee already
yea we refund any fees
interesting we will give it a shot?
when we do a partial refund, will refund_application_fee still work?
there's still currency conversion but less, and AppFee<>FeeRefund are really hard to reconcile so you're solving that too
well you don't pass refund_application_fee at all anymore, the partial refund is already done from your share of the charge
(as long as you also pass reverse_transfer: true which you already do)
neat
and then if we want to refund only from us we just use reverse_transfer: false
this does make it a lot easier
and I am guessing the balance transactions will make a bit more sense
exactly
I mean there are still a ton of BTs
like with one refund, it's 6 separate objects, each with their BT, but it's still easier
okay... this seems like the long term option
but it means we would have to have two different paths for refunding while we support old transactions
okay thanks so much
Sure thing! I'm sorry this is so hard, we know that exchange rates and refunds make this extremely complex for platforms like you, it's just not a problem with an easy solution especially with fluctuating exchange rates 😦
one thing that would be nice was if the exchange_rate variable fee was transparent
or have the exchange_rate match the math in the data
I have a feeling what is happening is that there is a hidden fee when we convert from buyer to connect and then that gets sent along to the application fee