FX spread is the gap between the mid-market rate and the rate you are actually given. You calculate it as the mid rate minus the offered rate, divided by the mid rate, times 100, with both rates written as units received per unit sent. On a USD 20,000 payment, a 0.50% spread costs USD 100 before any fee.
Best for: finance and payments teams that need to check a cross-border quote against a market reference before accepting it.
How stablecoin payout pricing works covers where each cost hides in a payout; this guide stays on the calculation.
Mid-market rate, offered rate and spread: what each number is
The mid-market rate is the midpoint between the price at which dealers buy a currency and the price at which they sell it in the wholesale market. The offered rate (the customer rate or final rate) is what the provider applies to your payment. The distance between the two is the customer spread, also called markup or margin.
A dealer's bid-ask spread, the gap between buy and sell prices on a trading screen, is a different measure. It is (ask - bid) / mid x 100: a bid of 5.1990 and an ask of 5.2010 around a mid of 5.2000 is 0.0020 / 5.2000 = 0.04%. The customer spread is measured against the mid, not against the other side of the book, and it usually contains the bid-ask gap plus the provider's margin. A fee is separate again, and a quote with no fee line can still carry a wide spread.
On Lumx, the base exchange rate is the raw mid-market reference rate, and the final rate is that rate after fees. No FX margin is built into the base, so the gap between the two printed rates is fees only: the Lumx fee, any partner fee and, on a 1 or 5 minute lock, the lock fee. Still check the base against your own mid taken in the same minute.
What is the formula for FX spread?
The spread in percent is (mid rate minus offered rate) divided by mid rate, times 100. The other measures follow from it, and the all-in cost catches fees and spread together.
Four ways to express the cost of a quote, on USD 20,000 with a mid of 5.2000 and an offered rate of 5.1740 reais per dollar (example numbers, not a live quote).
Measure | Formula | Example |
Spread in percent | (mid - offered) / mid x 100 | (5.2000 - 5.1740) / 5.2000 = 0.50% |
Spread in basis points | spread in percent x 100 | 50 bps |
Cost in money | spread in percent x amount sent | 0.50% x USD 20,000 = USD 100 |
All-in cost | 1 - received / (sent x mid) | 1 - 103,480 / 104,000 = 0.50% |
Basis points (bps) are hundredths of a percent, and Lumx's quote response reports its fee rates that way. Here there is no fee, so the all-in cost equals the spread. With a fee, the all-in figure is the one to compare.
Write every rate as units received per unit sent. Buying dollars with reais at 5.2260 reais per dollar is also 0.50% above mid, yet you receive 99.50% of the mid amount, a shortfall of 49.75 bps instead of 50.00. Keep one direction for every provider you compare.
On Lumx, both ends of the all-in formula are on the quote: the source amount and the final target amount.
How do you calculate the spread on a USD to BRL payment?
A company sends USD 20,000 in USDC and delivers reais to a supplier over Pix (Brazil's instant payment system, run by the Central Bank). Every rate below is an assumed round number.
Capture the mid at the minute of the quote: 5.2000 reais per dollar.
Check the direction. The offered rate is also reais per dollar, 5.1740.
Compute the spread: (5.2000 - 5.1740) / 5.2000 = 0.0050, so 0.50% or 50 bps.
Convert it to money: 0.50% of USD 20,000 is USD 100.
Check from the receiving side. At mid, USD 20,000 buys R$ 104,000. At the offered rate it buys R$ 103,480. The R$ 520 gap divided by the 5.20 mid is USD 100.
On Lumx, this payout is an off-ramp from a USDC balance to a Pix destination, and the quote returns the source amount, the base target amount and the final target amount, the inputs for steps 3 to 5.
Where to get a mid-market rate you can trust
Where a mid-market rate comes from, and what each source is good for.
Source | When it is set | Best use |
Live mid from a market data feed or trading screen | Continuously during market hours | Benchmarking a quote you are about to accept |
Central bank daily reference (PTAX, published by the Banco Central do Brasil from four daily windows; FIX, published by Banxico once per banking day) | A few times a day or once a day | Contracts, accounting, a sanity check |
A stablecoin price against the dollar | Continuously, on the venue that prices it | Quotes in USDC or USDT, which can sit slightly off one dollar |
Why a payout cannot settle at PTAX is in PTAX vs a live quote. If the quote sits below the rate Google shows, see the off-ramp rate versus Google. A rate on a website is not a quote, see indicative versus binding quotes.
On Lumx, a floating rate is a real-time reference rate with no fee, meant for showing an estimate, and a locked rate carries an expiry. Sample your own mid in the minute you request the locked rate, and the comparison is like for like.
Which quote is cheaper: "no fee" or a fee and a tighter rate?
The example sends USD 10,000 to pesos over SPEI (Mexico's interbank transfer system, run by Banxico), with an assumed mid of 18.0000 pesos per dollar, so the payment is worth MX$ 180,000 at mid.
Two assumed quotes for the same payment.
Quote A: "no fee" | Quote B: fee and tighter rate | |
Fee | USD 0 | USD 25, taken before conversion |
Offered rate | 17.7300 | 17.9100 |
Amount converted | USD 10,000 | USD 9,975 |
Recipient gets | MX$ 177,300.00 | MX$ 178,652.25 |
Shortfall against mid | MX$ 2,700.00 | MX$ 1,347.75 |
All-in cost | 1.50%, USD 150.00 | 0.75%, USD 74.88 |
Quote A looks free and costs twice as much. In Quote B the USD 25 comes out before conversion.
I tell finance teams to treat the first quote as a measurement, not a price. Pull the mid in the same minute, write down the amount sent and received, compute the all-in cost, and only then compare providers. I would rather a team compare three quotes taken at one timestamp than ten taken across a day, because the comparison then ends up measuring the clock.
On Lumx, the API reference for exchange rates lists a fees object with the Lumx fee, the partner fee and the total, each with a rate in bps, a flat amount and a total amount, so the all-in figure is a subtraction on the response, with each fee in its own field.
Two legs, two spreads: how a cross rate adds them up
A payment through USDC between two non-dollar currencies is two conversions, each with its own spread. Combined cost = 1 - (1 - s1) x (1 - s2), close to s1 + s2 when both are small.
Take R$ 52,000 delivered in pesos, with USDC treated as one dollar. Assumed mids are 5.2000 reais and 18.0000 pesos per USDC, a mid cross of 3.4615 pesos per real. Leg 1 offers 5.2156 reais per USDC, which on a received-per-sent basis (USDC received per real) is 0.299% below mid, about 0.30%. Leg 2 offers 17.9280 pesos per USDC, 0.40% below mid.
At mid, R$ 52,000 buys 10,000.00 USDC, which buys MX$ 180,000.00.
At the offered rates, it buys 9,970.09 USDC, which buys MX$ 178,743.77.
The shortfall is MX$ 1,256.23, or 0.698% (0.299% and 0.400% compounded), about 70 bps, and the all-in cross is 3.4374 pesos per real against the 3.4615 mid cross.
The walkthrough with quote fields is in BRL to MXN through USDC.
Pairs with a Lumx pair page.
Pair | Local rail | Page |
USDC to BRL | Pix | |
BRL to USDC | Pix | |
USDC to MXN | SPEI | |
USDC to COP | Bre-B or ACH Colombia |
On Lumx, each leg is its own transaction: reais collected over Pix become USDC in the company's custodial wallet, and an off-ramp sends USDC over SPEI. A locked quote (the exchange rate id) exists on a standalone transaction. If the BRL leg converts through an autoconversion rule, it converts at market and cannot take a locked quote. PIX and SPEI run 24/7/365 per the payment rail cut-off times page in the Lumx docs, and Lumx coverage lists the rest.
How to read an FX quote, line by line
What each line of an FX quote tells you.
Line | What it tells you | What to check |
Pair and direction | What you send and receive | Units received per unit sent, or the inverse? |
Rate type | Indicative, or firm with an expiry | A rate with no expiry is not a price you can hold |
Amount sent, amount received | Both ends of the all-in formula | Recompute the all-in cost from them |
Fees | Anything charged beside the rate | Before or after conversion, in which currency |
Expiry | How long the numbers hold | Whether your flow can submit inside it |
On Lumx, the rate type is chosen on the request. A floating rate has no lock and no fee. A locked rate has three windows: 30 seconds with no fee, and 1 minute or 5 minutes with a fee for the volatility risk. A lapsed lock returns the error EXCHANGE_RATE_EXPIRED, so a flow where a person confirms should request a longer window.
When a spread calculation is the wrong tool
A spread shows what a conversion cost at one moment and misleads in two cases.
The rate can move after you have it. A spread says nothing about the days between a quote and the day the money is needed. That exposure is a treasury decision for your own bank or FX broker. A natural FX hedge reduces it without one.
The ticket is large. A percentage from a small payment does not carry to a large one, so quote at your real size.
On Lumx, a locked quote holds its rate for the window you chose and is consumed once: reusing it returns EXCHANGE_RATE_ALREADY_USED.
What a Lumx quote looks like on a Pix payout
Lumx is stablecoin payments infrastructure for businesses that move money between Latin America and the rest of the world: one API to collect, hold, convert, and pay out in BRL, MXN, COP, USD, EUR, and GBP or in USDC and USDT, over local rails such as PIX, SPEI, PSE, Bre-B, ACH, FEDWIRE, SEPA, and Faster Payments, with SWIFT and on-behalf-of payments and collections (POBO and COBO) in USD, EUR, and GBP, plus named virtual accounts, custodial wallets, and KYB/KYC built in.
A payout starts with a request to the exchange rates endpoint: rail, source, target, amount and, for a locked quote, a window. The response carries the base exchange rate and base target amount (the conversion before fees), the final exchange rate and final target amount (what you receive), an expiry and the fees object. The sample below is from the remittances use-case guide in the Lumx docs, read on November 1, 2026.
The sample is an exercise, not a Lumx price, with a 1-minute lock. A request for 500 USDC shows a base target amount of 2,587.50 reais at 5.1750 and a final target amount of 2,581.81 at 5.1636. The gap is R$ 5.69, about 1.10 USDC, or 0.22% of the base amount. That gap is fees only, with no FX margin inside it, and the docs sample does not break out the lock fee.
If a platform adds its own margin, it goes in a partner fee, set in bps, as a flat dollar amount, or both. There is no default partner fee: it applies only when the request carries the partner fee id, and it then shows in the fees object next to Lumx's fee. To settle at the quoted price, pass the quote's id as the exchange rate id on the transaction.
The pricing model is a monthly platform fee plus usage-based per-transaction fees, transparent FX on locked quotes, no pre-funding; no published plans. No pre-funding means you do not park capital in settlement accounts before a payment, because conversion and settlement happen when the transaction starts. The standard agreement carries a monthly minimum. Specific rates come from Lumx sales, so hold a provider to the number on your own quote. Stablecoin API pricing compared lists what other providers publish, and global payments describes the product around the quote. Background: stablecoin corridors, what USDC is and BRL to USDC for treasury.
Methodology and sources
Every rate, amount and fee in the worked examples is assumed. None is a live quote, a market rate or a Lumx price. The one real set of figures is the sample response in the Lumx remittances guide, labeled as a sample. PTAX in Brazil and the FIX in Mexico appear only as daily references and enter no calculation. No range for business payment spreads is cited because the ones found could not be verified.
Product behavior comes from the Lumx docs on exchange rates, the exchange rates API reference, the remittances use-case guide, partner fees, errors, coverage and payment rail cut-off times, all read on November 1, 2026.
Verified on November 1, 2026. Operational context, not legal, tax, or investment advice.
Cover photo: Laura Ockel on Unsplash.
How do you calculate FX spread?
Subtract the offered rate from the mid-market rate, divide by the mid-market rate and multiply by 100, with both rates in units received per unit sent. A mid of 5.2000 and an offered rate of 5.1740 give 0.50%, or 50 basis points, which is USD 100 on USD 20,000. On Lumx, a locked quote returns the base and final rates and amounts, so you can run the same subtraction on your own request.
What is a normal FX spread?
There is no single number, and this guide cites no benchmark because the ones found could not be verified. It depends on the pair, the amount, the time of day and the route, so a spread is high or low only against quotes for the same pair and amount, at the same minute. Compare quotes taken at one timestamp with a mid from that minute. Lumx's conversion fees scale by monthly volume tier, with specific rates from sales, and every quote shows a base rate, a final rate and a fees object.
Where can I find the mid-market exchange rate?
A live feed shows a real-time mid. Central bank references such as PTAX in Brazil and the FIX in Mexico are set from earlier data, so use them as a sanity check, not the benchmark. On Lumx, a floating rate is a real-time reference with no fee and a locked rate has an expiry, so take your own mid in the minute you request the locked rate.
How do I read the spread in a Lumx quote?
Lumx's conversion fee sits on top of the mid-market reference rate, so first check the base exchange rate (the conversion before fees) against your own mid. The gap from there to the final exchange rate (what you receive) is fees only, and the fees object itemises the Lumx fee, the partner fee and the total in basis points. For a quote you will act on, request a locked rate: 30 seconds has no fee, and 1 or 5 minutes carry one. A lapsed lock returns EXCHANGE_RATE_EXPIRED.





