Stablecoin FX slippage: how live quotes turn the quoted rate into the rate you get

FX slippage is the gap between the rate a stablecoin on-ramp or off-ramp shows and the rate that settles. Why quote freshness is a liquidity signal, and how to check a quote-then-execute flow.

An on-ramp converts fiat money into stablecoins: dollars in a bank account become USDC in a wallet. An off-ramp does the reverse: USDC or USDT becomes local currency in a bank account, over a rail like Pix or SPEI. Every on-ramp and off-ramp payment has an exchange rate, and FX slippage is the gap between the rate you were shown and the rate that actually settled.

A live quote is how a provider closes that gap. How fresh the quote is, and whether it is binding, tells you more about a provider's liquidity than any coverage map.

What is FX slippage in a stablecoin payment?

FX slippage is the difference between the quoted exchange rate and the settled exchange rate. It shows up when a provider displays one rate, executes the conversion later, and settles at whatever the market says at that later moment.

The formula is short:

slippage (bps) = (quoted rate - settled rate) / quoted rate x 10,000

An illustrative example. An app shows a user 5.40 reais per USDC on a 10,000 USDC off-ramp, so the screen says 54,000 reais. The provider executes a minute later at 5.37. The recipient gets 53,700 reais. That is 300 reais missing, about 56 basis points of slippage, and nobody agreed to it.

Slippage can run in your favor too. It doesn't matter. A cost that moves randomly is still a cost you can't price, reconcile, or promise to a customer.

What is the difference between a live, indicative, and stale quote?

Quote typeWhat it isIs it binding?Who carries the rate risk
Live quoteCalculated at request time, with an id and an expiryYes, inside the windowThe provider, until expiry
Indicative quoteAn estimate based on a recent market rateNo; execution happens later at marketYou, or your recipient
Stale quoteA rate that was live once, then cached or shown past its expiryNoYou, and you may not know it

A stale quote is the sneaky one. It looks like a live quote on screen. The number just stopped being true a while ago. The most common cause is an application that fetches a rate when a page loads and lets the user sit on it for ten minutes.

For the full quote lifecycle, including what happens when a quote expires and how window length should shape your UX, read on/off ramp liquidity with live quotes.

Why is quote freshness a liquidity signal?

Because a provider can only commit to a rate it can fill. Freshness and bindingness are what real liquidity looks like from the outside.

A provider that holds local-currency inventory, or has direct access to market makers who do, can price a trade and hold that price for a few minutes. It knows it can deliver. A provider that has to go find the reais after you confirm can't make that promise, so it gives you an indicative rate instead and settles at whatever it gets.

Three things to read from a provider's quotes:

  • Does it bind at all? No quote id, no expiry, no liquidity commitment.
  • How long is the window? Very short windows, under 10 seconds on a consumer flow, usually mean thin liquidity or a provider pushing its risk onto you.
  • Does the rate hold across sizes? A spread that stays flat from 500 to 50,000 dollars means the depth is real. A spread that widens fast means the good inventory runs out early.

This is the same test as in what a liquidity market is: the quote is the visible edge of the liquidity behind it.

How does a provider build a live quote?

A live quote has four ingredients, calculated in one synchronous request:

  1. A reference rate. The current market rate for the pair, from interbank FX feeds and trading venues.
  2. The provider's source of liquidity. Its own inventory, market makers, or local exchange partners, at the size requested.
  3. Spread and fees. The provider's margin on the rate, plus any flat or percentage fees and network costs.
  4. A lock window. How long the provider will honor the result. The provider carries the market risk inside that window, which is why windows are minutes, not hours.

A well-built quote response shows the first and third ingredients side by side, so you can see the spread. At BlindPay, every payout quote returns commercial_quotation (the market rate) next to blindpay_quotation (the rate after BlindPay's margin), plus sender_amount, receiver_amount, and each fee. The gap between the two rates is the spread, on every quote. Stablecoin API quotes explained walks through every field.

Spread vs slippage: which one are you paying?

Both, possibly. They are different kinds of cost.

  • Spread is the provider's margin, visible in the quote, agreed before you send.
  • Slippage is an unagreed difference that shows up after the payment settles.

A binding live quote converts potential slippage into visible spread. The provider prices its risk for the window into the rate, and you see that price before you say yes. So a live quote with a slightly wider spread can cost less than a tight indicative rate plus slippage. The only way to know is to compare settled amounts, not screen rates. Stablecoin liquidity providers vs bank FX desks covers the rest of the hidden-cost list.

What should you check before trusting a quote-then-execute flow?

Run through this list against any provider's docs and sandbox:

  1. Rate lock duration. The quote response states an expiry, and you read it from the response instead of hardcoding it.
  2. Slippage tolerance. The payment executes at the quoted rate or is rejected. Any tolerance band, even 0.5 percent, means the quote is not binding.
  3. Settlement guarantee. The recipient gets the quoted receiver_amount, not an amount recalculated at execution.
  4. Expiry behavior. Submitting against an expired quote fails with a distinct error code, so your client knows to re-quote instead of retrying blindly.
  5. Mid-transaction expiry. You know what happens when a slow step, like an on-chain approval, outlasts the window. The safe answer is to re-quote before executing.
  6. One quote per payment. A quote id backs a single payment, which adds a second layer against double-sends on top of your idempotency keys.
  7. Itemized fees. Rate, spread, flat fee, and network fee are separate fields, so the amount on screen matches the amount that settles.
  8. Sandbox parity. Expiry and rejection behave the same in sandbox as in production, or your failure paths ship untested.

BlindPay's answers, for reference: payout quotes expire five minutes after creation by default (SEPA quotes can be shorter), with expires_at in epoch milliseconds. A quote backs one payout, and an expired quote is rejected rather than executed at a new rate. The payout runs on the quote's numbers when you create it inside the window.

What does a quote-then-execute flow look like in an API?

A typical REST flow for an off-ramp payout has five steps. This is BlindPay's shape, but most stablecoin APIs follow the same pattern.

Step 1. Request a quote.POST /v1/instances/{instance_id}/quotes with the destination bank_account_id, request_amount in minor units (10000 means 100.00), currency_type (which side the amount is on), cover_fees (who pays), and the funding network and token.

Step 2. Read the response and show it. The response returns the quote id, expires_at, commercial_quotation, blindpay_quotation, sender_amount, receiver_amount, and fees. Display receiver_amount with a countdown driven by expires_at.

Step 3. Authorize the funding, if needed. For a self-custodied EVM wallet, sign the ERC-20 approve for the exact amount in the quote's contract payload. A BlindPay-managed wallet skips this step.

Step 4. Execute against the quote.POST /v1/instances/{instance_id}/payouts/evm with the quote_id and the sender wallet address, before expires_at. If the quote expired, request a new one, show the new numbers, and execute against the new id.

Step 5. Confirm settlement. Listen for the payout.complete webhook, which fires when the payout reaches completed, failed, or refunded. Store the quoted and delivered amounts together for reconciliation.

The same flow runs from the terminal with the BlindPay CLI (blindpay quotes create, then blindpay payouts create --quote-id qu_...) and from the official SDKs for Node.js, Python, and Go, as well as PHP and Swift.

How do you measure slippage in production?

Log three numbers on every payout: the quoted rate at confirmation, the quoted receiver_amount, and the amount that actually landed. Then track, per corridor:

  • Realized slippage. Delivered amount against quoted amount. On a binding quote, this should be zero, every time.
  • Expiry rate. The share of quotes that expire before the user confirms. A high rate means your UX fetches quotes too early or the window is too short.
  • Re-quote delta. How much the amount moves between an expired quote and its replacement. Large deltas on a corridor are a volatility warning.

If realized slippage is ever non-zero on a "live" quote, you have learned something important about your provider.

What to do next

Pick one corridor and run the eight-point checklist in a sandbox: request a quote, let it expire, submit it anyway, and confirm you get a clean expiry error. Then read the payout quotes documentation for the full request and response, or follow the payout quickstart to run the whole flow on a development instance.

This article is general information, not legal, tax, or financial advice.

FAQ