mike lewis

Stripe Connect Multiple Currency Handling

If you’re using Stripe Connect with multiple currencies but a single settlement currency, you need to handle conversion properly. The documentation often glosses over this, implying Stripe handles “all” conversion, which is true for payouts, but not necessarily for platform-to-account transfers.

The Problem

The Stripe Connect docs focus heavily on how easy it is to pay out to users worldwide and how they handle all the conversion for you. This led me to assume I could simply transfer the original charge currency. I tried this:

# This fails if your settlement currency is USD
stripe.Transfer.create(
    amount=1000,
    currency="gbp", # Charging in GBP
    destination="acct_xxx",
    source_transaction="ch_yyy"
)

The Reality Check

  1. You charge the customer in GBP.

  2. Stripe converts that to USD (your settlement currency) at their internal rate.

  3. Stripe holds USD in your platform account.

  4. When you try to transfer GBP, the transaction fails because your platform ledger only contains USD.

The Solution

You must transfer in your settlement currency, not the charge currency. To avoid losing money on exchange rate discrepancies or rounding errors, you need to pull the exact rate Stripe used for that specific transaction.

Here is the implementation that handles the Decimal conversion and rounding safely:

from decimal import Decimal, ROUND_HALF_UP
import stripe

# 1. Retrieve the charge and expand the balance_transaction
charge = stripe.Charge.retrieve("ch_yyy", expand=["balance_transaction"])

# 2. Extract the exact exchange rate Stripe applied
# This is cleaner than trying to calculate it yourself and hitting rounding drift
exchange_rate = Decimal(str(charge['balance_transaction']['exchange_rate']))

# 3. Convert your intended transfer amount to USD
# Example: transfer_amount is the 'major' unit (e.g., 10.00 GBP)
transfer_amount_usd = Decimal(str(transfer_amount)) * exchange_rate

# 4. Convert to cents (integers) and round to the nearest cent
transfer_amount_cents = int(
    (Decimal('100') * transfer_amount_usd).quantize(Decimal('1'), rounding=ROUND_HALF_UP)
)

# 5. Execute the transfer in your settlement currency
stripe.Transfer.create(
    amount=transfer_amount_cents,
    currency="usd",
    destination="acct_xxx",
    source_transaction="ch_yyy"
)

Key Takeaway

Don’t guess the exchange rate or use a third-party API. By expanding balance_transaction, you’re using the exact numbers Stripe used to fund your account, which eliminates “missing penny” bugs that are a nightmare to reconcile at the end of the month.