#theplay3r_exchange-rates

1 messages ยท Page 1 of 1 (latest)

vast ventureBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always 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/1291757326046593096

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

alpine spear
#

For one-time payments, our solution was simple - we can easily calculate the exchange rate ourself using the latest charge amount and the transfer amount.

                        val chargeAmount = BigDecimal(latestCharge.amount)
                        val transferAmount = BigDecimal(transfer.amount)

                        val exchangeRate = transferAmount.divide(chargeAmount, 10, RoundingMode.HALF_UP)

                        val taxAmount = BigDecimal(taxAmountTotal).multiply(exchangeRate)

                        TransferReversalCreateParams.builder()
                            .setDescription("Tax")
                            .setAmount(taxAmount.toLong())
                            .setRefundApplicationFee(false)
                            .build()

However for Subscriptions, this is not possible, because the amount of transfer isn't the same as the amount of the latest charge.
Our solution for Subscriptions is as follows:

                        val listParams = BalanceTransactionListParams.builder()
                            .setSource(latestCharge.id)
                            .build()

                        val exchangeRate = stripe.balanceTransactions().list(listParams).autoPagingIterable()
                            .first { it.exchangeRate !== null }
                            .exchangeRate

                        val taxAmount = BigDecimal(taxAmountTotal).multiply(exchangeRate)

                        TransferReversalCreateParams.builder()
                            .setDescription("Tax")
                            .setAmount(taxAmount.toLong())
                            .setRefundApplicationFee(false)
                            .build()

But that is not ideal and we're hoping there would be a better way.

misty vigil
#

Wouldn't you collect tax in the currency the customer was charged in (on the invoice)? Not the currency of the transfer?

alpine spear
#

We use Stripe Tax for automatic tax collection, we just need to withhold the tax from the connected account.

#

We charge the customer in USD, but the connected account might be in different currency.

#

Hence why we need the exchange rate to correctly calculate how much to transfer back to us.

misty vigil
#

Got it. Do you have a sample subscription id I can look at? I can poke around to see if there's a better way

alpine spear
#

Sure, sorry for the delay, here it is: sub_1Q5ugyER4OdDbRiBjcG9Ti02

misty vigil
#

Yeah I think getting exchange rate from the balance transaction is probably the best thing to do tbh

alpine spear
#

And how reliable is that? Currently it takes the exchange rate from the Stripe fee that gets charged on the Subscription, can I expect that to always exist?

#

(no other balance transactions have exchange_rate property filled up)

night charm
#

Hi there ๐Ÿ‘‹ jumping in as my teammate needs to step away soon. That exchange rate will be consistent, and isn't relevant to the Stripe fee being charged as far as I'm aware.

You're using on_behalf_of when creating your Checkout Sessions, so the funds from the payment will settle in the settlement currency of your Connected Account. The exchange_rate on the Balance Transaction represents the exchange rate that we used to get from the presentment currency (usd) to that settlement currency for the payment.
https://docs.stripe.com/api/balance_transactions/object#balance_transaction_object-exchange_rate

vast ventureBOT
#

theplay3r_exchange-rates

alpine spear
#

No other balance transactions retrieved have this property filled up, it's simply null.

night charm
#

The one for the payment. Can you elaborate on what other Balance Transactions you're looking at?

alpine spear
#

I'm retrieving all balance transactions using the latest charge ID.

#

It retrieves a few of them, but only the Stripe Fee's one has the exchange_rate property not-null.

night charm
alpine spear
#

I'm able to do filter by Charge ID tho?

Retrieve an Invoice pi_3Q5ugyER4OdDbRiB0RdKJEzt > payment_intent = pi_3Q5ugyER4OdDbRiB0RdKJEzt
Retrieve a PaymentIntent pi_3Q5ugyER4OdDbRiB0RdKJEzt > latest_charge = ch_3Q5ugyER4OdDbRiB0eM5rcO2
List all balance transactions, source=ch_3Q5ugyER4OdDbRiB0eM5rcO2

Retrieves:

{
    "object": "list",
    "data": [
        {
            "id": "txn_3Q5ugyER4OdDbRiB0jgO8nH6",
            "object": "balance_transaction",
            "amount": 5447,
            "available_on": 1728518400,
            "created": 1727983685,
            "currency": "czk",
            "description": "Subscription creation",
            "exchange_rate": 22.507,
            "fee": 732,
            "fee_details": [
                {
                    "amount": 732,
                    "application": null,
                    "currency": "czk",
                    "description": "Stripe processing fees",
                    "type": "stripe_fee"
                }
            ],
            "net": 4715,
            "reporting_category": "charge",
            "source": "ch_3Q5ugyER4OdDbRiB0eM5rcO2",
            "status": "pending",
            "type": "charge"
        }
    ],
    "has_more": false,
    "url": "/v1/balance_transactions"
}
#

And my concern is if I can always expect it to include at least this one balance transaction which includes the exchange_rate.

#

Because any other balance transaction that isn't Stripe processing fees for Subscription creation has the exchange_rate set as null.

night charm
alpine spear
#

Ok, and I can always expect the exchange_rate to be there?

night charm
#

If a currency conversion occurred for the payment, yes

alpine spear
#

Okay, that clears things up for me a bit.

#

Now just one more question, we only have to do this approach when the whole charged amount isn't transfered to the connected account (eg. subscriptions).

If we were to update the invoice and set application_fee_amount to something, would then the whole charged amount be sent to the Connected account in transfer and then fees applied? (Same as it works with one-time payments)

night charm
#

Is that for a one-off Invoice, or are you talking about updating the Invoice created by the Subscription? If the latter, I don't believe that is supported but may be mistaken.

alpine spear
night charm
#

Ah, good spot!

So in that case, yes, the whole amount is transferred to the Connected Account, then an Application Fee is created and pulls some of those funds back:
https://docs.stripe.com/connect/destination-charges?platform=web&ui=stripe-hosted#flow-of-funds-app-fee

So in net the Connected Account receives the full payment amount minus your application fee amount.

Create charges on your platform account, collect fees, and immediately transfer the remaining funds to your connected accounts.

alpine spear
#

Alright, that makes things easier then, thanks for the help.