How to test an off-ramp's liquidity depth before you commit: a quote-ladder protocol

Quote $500, $5,000, $50,000, and $250,000 at the same moment, three times a day, and compare the rate. The protocol, log table, and pass rule.

To test an off-ramp's liquidity depth, request quotes for the same corridor at $500, $5,000, $50,000, and $250,000 within the same few seconds. Repeat at three times of day on three days, and compare the rate each size gets in basis points. A rate that stays flat across sizes means real depth. One that falls fast means inventory runs out early.

Earlier guides on on/off-ramp liquidity with live quotes and liquidity markets explain why depth matters and suggest a quick three-size check. This is the full protocol: the top rung, the time-of-day runs, the log, and a pass rule you can hand to a finance team.

Key takeaways

  • Change only the amount. Same corridor, bank account, network, token, fee setting, and the same few seconds.
  • Measure the rate before flat fees. Fixed fees make small payouts look expensive and hide what size does to the rate.
  • Depth slope = (rate at $500 - rate at the rung) / rate at $500 x 10,000. Under 10 bps at the top rung is a pass.
  • Run three sessions a day on three days. Depth that only exists at midday is not depth for a payout that runs at night.
  • A quote window that shrinks as size grows, or a binding quote that turns indicative at the top rung, is a failed test.

What does liquidity depth mean for an off-ramp?

Liquidity depth is the amount a provider can convert on one corridor before its rate gets worse. Deep inventory fills a $250,000 payout at nearly the same rate as a $500 one. Thin inventory has to reach for worse prices, or a third party with its own markup, as the order grows.

Coverage maps do not show this. A provider can list Brazil and still fill only small tickets well. The quote API is the honest witness, as long as you ask it the same question at different sizes. The terms used below (live quote, depth, spread, basis point) are defined in the on/off-ramp liquidity glossary.

What do you need before you start?

Four things, set once and kept constant for every run.

  • Production quote access. A quote moves no money until you execute it. Sandbox prices do not reflect real inventory, and BlindPay development instances run on testnets with USDB. Sandbox vs production covers what a sandbox can and cannot tell you.
  • One approved recipient bank account per corridor. Quotes are priced against a specific destination.
  • A fixed funding leg. Same network and token on every request, for example USDC on Polygon. Check pairs against supported chains.
  • Limits that cover the top rung. BlindPay checks per-customer limits on the stablecoin amount: $10,000 per transaction for KYC Standard, $30,000 for KYB Standard, and $50,000 for KYC Enhanced by default, per the customers reference. Raise them with a limit increase, or cap the ladder at your largest real payout. A rung above a limit can come back as an error; log it as a limit, not as thin liquidity.

What sizes should you test?

Four rungs, spanning a factor of 500, plus your own largest payout if it falls outside them.

RungAmountWhat it tells you
1$500Baseline rate. Flat fees dominate the all-in cost here
2$5,000A typical supplier invoice or contractor payment
3$50,000A payroll batch or a weekly treasury move
4$250,000A large transfer. Thin inventory usually breaks here

The fourth rung is the one most evaluations skip, and it is where providers that route to a partner at quote time show their seams.

How do you run the quote ladder?

Fire all four quotes in parallel so they see the same market, then save the responses. With BlindPay's payout quote endpoint, request_amount is in minor units, so $500 is 50000.

Bash
# Same corridor, same moment, four sizes. Quotes are never executed.
for amount in 50000 500000 5000000 25000000; do
  curl -s "https://api.blindpay.com/v1/instances/$INSTANCE_ID/quotes" \
    -H "Authorization: Bearer $BLINDPAY_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{\"bank_account_id\":\"$BANK_ACCOUNT_ID\",\"currency_type\":\"sender\",\"cover_fees\":false,\"request_amount\":$amount,\"network\":\"polygon\",\"token\":\"USDC\"}" \
    > "quote_$amount.json" &
done
wait

Then compute the spread and the depth slope for each rung.

Python
import json

base = None
for amount in [50000, 500000, 5000000, 25000000]:
    q = json.load(open(f"quote_{amount}.json"))
    rate, market = q["blindpay_quotation"], q["commercial_quotation"]
    base = base or rate
    spread_bps = (market - rate) / market * 10_000
    slope_bps = (base - rate) / base * 10_000
    print(amount / 100, market, rate, round(spread_bps, 1), round(slope_bps, 1), q["expires_at"])

Two columns matter. commercial_quotation across rungs shows whether the market price itself moves with size. blindpay_quotation is the rate you actually get before flat fees. Keep flat_fee in the log, but leave it out of the depth calculation.

How do you read the results?

Compare the rate at each rung with the rate at $500. The change, in basis points, is the depth slope.

Illustrative example. Two providers quote USDC to BRL at the same moment. The market rate is 5.4000 BRL per USDC.

RungProvider A rateA slopeProvider B rateB slope
$5005.37300 bps5.37300 bps
$5,0005.37300 bps5.37201.9 bps
$50,0005.37300 bps5.346050.3 bps
$250,0005.37300 bps5.2920150.8 bps

Provider B's top rung: (5.3730 - 5.2920) / 5.3730 x 10,000 = 150.8 bps. On $250,000 that is 250,000 x 0.0810 = R$20,250 less for the recipient, about $3,769 at Provider A's rate (20,250 / 5.373). Same corridor, same minute, same quoted "spread" on a small ticket.

What time of day matters?

The hours when the destination currency trades most. The BIS 2025 Triennial Survey found that sales desks in the UK, US, Singapore, and Hong Kong handled 75% of FX trading in April 2025. Currencies like BRL and MXN also trade heavily in their own onshore hours.

Run each ladder three times a day:

  1. Destination morning, shortly after the local FX market opens.
  2. London and New York overlap, roughly 8:00 to 12:00 New York time, when the two largest FX trading centers are both open.
  3. After the destination market closes, when a provider has to hold risk until the next open.

Do it on three business days. Run any weekend ladder separately and compare it only with other weekend runs: Pix settles 24/7, but the price of reais on a Saturday carries Monday's risk.

What counts as a pass?

Use the top-rung slope from the worst of your nine runs, not the average. A payout that runs at the worst moment gets the worst rate.

Worst top-rung slopeVerdictWhat to do
10 bps or lessDeep at this sizeProduction-ready for payouts up to the top rung
10 to 50 bpsUsable with careSplit large payouts, or test a middle rung to find where the rate breaks
Over 50 bpsThinInventory runs out early. Keep large payouts elsewhere
No binding quoteFailThe provider cannot hold a price at that size

These thresholds are rules of thumb, not an industry standard. Two more failure signals:

  • The window shrinks with size. If expires_at gets closer as the amount grows, the provider is protecting itself from a book it cannot fill.
  • Last look on the top rung. The FX Global Code defines last look as a final chance for the quoting firm to accept or reject your request against its quoted price. A large quote that can be rejected after you execute has not passed a depth test, whatever its rate.

One caution on interpretation. The BIS Markets Committee noted that internalised trading makes liquidity harder to measure from the outside. Quote ladders measure what you can get, not what a provider holds, and that is the number your payouts depend on.

What should you log?

Copy this table into a spreadsheet and fill one row per rung per run.

DateTime (UTC)CorridorRung (USD)commercial_quotationblindpay_quotationflat_feereceiver_amountWindow (s)Spread (bps)Slope (bps)Notes

Window (s) is expires_at minus the request time, divided by 1,000, since expires_at is in epoch milliseconds. Keep the raw JSON too. When a provider's rates change after you go live, this log is your baseline.

How does BlindPay show up on this test?

Every BlindPay payout quote returns commercial_quotation next to blindpay_quotation, itemized fees, and a 5-minute expires_at, so the ladder runs on the public API without a sales call. Quotes are funded when you execute them, with no pre-funding. Plans are on the pricing page, and per-transaction fees appear in each quote.

Run the ladder yourself and judge the slope. For who holds the rate while the window is open, see who carries FX risk in a stablecoin payout. For where the inventory behind a quote comes from, see what a market maker is in stablecoin payments. The slippage guide covers the next test after depth: whether the settled rate matches the quoted one. Depth is one row in the full on/off-ramp provider checklist.

How we know: BlindPay fields and limits come from the payout quotes and customers documentation. Market structure figures come from the BIS and the FX Global Code, linked above.

What to do next

Pick your largest corridor and run the four-rung ladder once today against the payout quote endpoint. Save the JSON, fill the log, and schedule the other eight runs for the next three days.

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

FAQ