---
title: "How to refund a cross-border payment after the exchange rate moved"
seoTitle: "Refunding a cross-border payment after FX moved"
description: "Refund the local amount, the dollar amount, or the current rate? Who absorbs the FX difference, how stablecoin payout refunds work, and a policy to copy."
date: "2026-10-15"
updated: "2026-10-15"
category: "payments"
author: "BlindPay Team"
faq:
  - q: "Should a cross-border refund return the local currency amount or the dollar amount?"
    a: "Most consumer-facing businesses refund the exact local amount the customer paid, because that is what the customer sees on their bank statement and what card processors do by default. The business then absorbs any exchange rate difference. Refunding the original dollar amount moves the FX risk to the customer, which is easier to defend in B2B contracts where the invoice was in USD."
  - q: "Who pays the difference when the exchange rate moves before a refund?"
    a: "Whoever's currency is not fixed. If you refund the original local amount, you pay more or less in dollars depending on the move. If you refund the original dollar amount, the customer receives more or less local currency. Write the choice into your terms before the first refund, not during a dispute, so support and finance give the same answer every time."
  - q: "How do card processors convert refunds on currency-converted payments?"
    a: "Stripe documents that a refunded or disputed currency-converted payment is converted back at the current exchange rate, so the amount deducted from the merchant balance can be more or less than the original payment. The customer always gets back the exact amount they paid, in the currency they paid in. The merchant carries the exchange rate difference."
  - q: "What happens to the money when a stablecoin payout is refunded?"
    a: "On BlindPay, a payout in refunded status means the stablecoins were returned to the funding source instead of being converted to fiat. Because the conversion never ran, there is no exchange rate loss to absorb. On Pix and other non-USD local rails the refund is automatic, while USD payouts and payouts whose review times out are refunded after an operator review."
  - q: "How do I send a refund in an exact local currency amount?"
    a: "Treat the refund as a new payout and price it with its own quote. On BlindPay, a payout quote with currency_type set to receiver takes the request amount in the currency the bank account receives, so you can fix the local amount and see how much stablecoin it costs before you execute. The quote locks the rate and fees for its window."
  - q: "Is a failed payout the same as a refunded payout?"
    a: "No. A refunded payout returned the stablecoins to the funding source. A failed payout does not automatically refund the sender, and BlindPay's docs tell you to contact support if a payout looks stuck. Your refund logic should branch on the exact status from the payout webhook, not on the word failure in a support ticket."
---

Refund the amount whose currency your terms fixed. If the customer paid R$ 5,400, most businesses send back R$ 5,400 and absorb the dollar difference. If the contract was in USD, you can refund USD and let the local amount float. Decide which side is fixed before the first refund, then price the refund with a fresh quote.

Refunds are where exchange rate risk shows up late. The sale happened weeks ago at one rate, the refund happens today at another, and someone has to eat the gap. The good news: it's a policy decision, not a math problem. The math is two divisions.

**Key takeaways**

- A refund after an FX move always leaves one side's currency floating. Pick which one in your terms.
- Refunding the exact local amount is the customer-friendly default and the one card processors use.
- Refunding the original dollar amount moves FX risk to the customer. It fits B2B invoices priced in USD.
- A refund you send is a new payout with a new quote at today's rate. Fix the receiver side to hit an exact local amount.
- A refunded stablecoin payout never converted, so there is no FX loss on it at all.
- Branch on payout status. Refunded and failed mean different things.

## Why does a refund cost a different amount than the original payment?

Because the refund converts at today's rate, not the sale's rate. Exchange rates move every day; Brazil's central bank publishes a new PTAX dollar rate each business day in its [open data portal](https://dadosabertos.bcb.gov.br/dataset/dolar-americano-usd-todos-os-boletins-diarios). A refund three weeks later crosses a different rate, so either the dollar cost or the local amount changes.

Nothing is wrong when that happens. The original payment was priced correctly, and so is the refund. They just ran at two moments. The [FX gap between a sale and a payout](/resources/more/fx-gap-between-sale-and-payout) is the same effect in the other direction.

## Which amount should stay fixed: the local currency or the dollar amount?

The one your customer agreed to pay in. If the price was shown in reais, refund reais. If the invoice was in dollars, refund dollars. Everything else follows from that choice.

Three policies cover almost every business:

| Policy | Fixed amount | Who absorbs the FX move | Fits |
| --- | --- | --- | --- |
| Refund the original local amount | What the customer paid, in their currency | You | Consumer checkout, marketplaces, anything priced in local currency |
| Refund the original USD amount | What you received, in dollars | The customer | B2B invoices issued in USD, contracts that name USD |
| Refund at the original rate, split the difference | Neither, by agreement | Shared | Negotiated enterprise contracts |

The first policy is the default for a reason. A customer who paid R$ 5,400 and gets back R$ 5,180 calls support, no matter how clearly the rate moved. That ticket costs more than the FX difference on most refunds. [Passing through or absorbing FX costs](/resources/more/pass-through-or-absorb-fx-costs) covers the same trade-off for the original sale.

## How do card processors handle refunds on converted payments?

They fix the customer's side. Stripe's [localized pricing docs](https://docs.stripe.com/payments/currencies/localize-prices) say that if a currency-converted payment is disputed or refunded, the amount you received is converted back to the presentment currency at the current exchange rate, so the amount deducted from your balance "might be more or less than the original payment." Stripe also says it always refunds the customer "the exact amount they paid and in the currency they paid in."

Stripe's own example: a 60 USD payment converted at 0.88 EUR per USD settled as 52.80 EUR. At 0.86 on the refund date, 51.60 EUR came out of the merchant's balance. The merchant came out ahead that time. Next time it could go the other way.

That's the norm customers already know from cards. A stablecoin payout flow that refunds the dollar amount instead will feel worse to them, even if it's fair.

## Illustrative example: what does a R$ 5,400 refund cost three weeks later?

Illustrative example. A marketplace sells an item for R$ 5,400 and converts it at 5.40 BRL per USDC, so the sale is worth 1,000 USDC. Three weeks later the buyer asks for a refund. Two scenarios for the refund-day rate:

| Refund-day rate | Refund R$ 5,400 (local fixed) | Refund 1,000 USDC worth (USD fixed) |
| --- | --- | --- |
| 5.70 BRL per USDC (real weakened) | 5,400 / 5.70 = 947.37 USDC. You keep 52.63 USDC | 1,000 × 5.70 = R$ 5,700. Customer gets R$ 300 more |
| 5.10 BRL per USDC (real strengthened) | 5,400 / 5.10 = 1,058.82 USDC. You pay 58.82 USDC extra | 1,000 × 5.10 = R$ 5,100. Customer gets R$ 300 less |

Fees are left out on purpose. On BlindPay, per-transaction fees vary by rail and network and are disclosed in the live quote before execute, so the real refund cost is the quote's `sender_amount`, not this table.

Look at the second row under "USD fixed." That's the refund that produces the angry ticket. Under "local fixed," the business pays 58.82 USDC to avoid it. Over a year of refunds, the gains and losses in the first column tend to offset each other, since nobody can reliably call the direction of the next move.

## What happens when a stablecoin payout is refunded instead of delivered?

The stablecoins come back unconverted, so there's no FX difference to settle. BlindPay's [payouts docs](/docs/payouts) define `refunded` as: the stablecoins were returned to the funding source instead of being converted to fiat.

BlindPay operates as a non-custodial payment processor for payout flows from customer-controlled wallets: you authorize the exact amount and BlindPay executes that single transaction. If a payout cannot be delivered after the stablecoins are collected, BlindPay refunds them to the quote's refund wallet, or to the sending wallet when none is set; on Pix and other non-USD local rails the refund is automatic, while USD payouts and payouts whose review times out are refunded after an operator review.

Two cases to keep separate in code:

1. **`refunded`.** Stablecoins are back. Re-quote and resend, or return them to whoever funded the payout.
2. **`failed`.** Not an automatic refund. The docs tell you to contact support rather than assume it resolves on its own.

[Payout statuses explained](/resources/more/stablecoin-payout-statuses-explained) lists every state and what to do in each.

## How do you send a refund with a payout quote?

As a brand-new payout. A refund to a customer's bank account is a payout like any other: bank account, quote, execute. The quote locks the rate and fees for 5 minutes, and the window can be shorter on SEPA and Faster Payments ([cut-off times](/docs/kb/cut-off-times)), so read `expires_at` from the response.

To hit an exact local amount, set `currency_type: receiver` on the [payout quote](/docs/payout-quotes). `request_amount` is then in the currency the bank account receives, in minor units. R$ 5,400.00 is `540000`. The response tells you how much stablecoin that costs at the current rate. To refund a fixed dollar value instead, use `currency_type: sender` and pass the stablecoin amount.

Set `cover_fees` deliberately too. With `cover_fees: true` the sender pays the fees on top, so the customer receives the full R$ 5,400. With `false`, fees come out of the amount received, and the customer sees less than they paid. For refunds, that's usually the wrong default.

## What should your refund policy say?

Four lines, written before you need them:

1. **Fixed currency.** "Refunds return the amount you paid, in the currency you paid." Or the USD version, if your invoices are in USD.
2. **Rate.** "Refunds convert at the rate on the day we send them."
3. **Fees.** Who pays the payout fee on a refund. Most businesses cover it.
4. **Timing.** How long after approval the refund is sent, and which rail it goes over.

Then give finance a line in the ledger for refund FX gains and losses, separate from the original sale. [Recording stablecoin payouts in the ledger](/resources/more/stablecoin-payout-accounting-entries) covers that entry, and the [support playbook for payout amount questions](/resources/more/payout-amount-support-playbook) has the reply to send when a customer asks why the dollar value changed. For how providers earn on the conversion itself, see [how on/off-ramp providers make money](/resources/more/how-onramp-offramp-providers-make-money).

## What to do next

On a development instance, create a payout quote with `currency_type: receiver` and `cover_fees: true` for your typical refund amount, and compare its `sender_amount` with the original sale. The [payout quotes docs](/docs/payout-quotes) list every field.
