Stablecoin API quotes explained: expiry, fee direction, and minor units

A stablecoin API quote locks the rate, fees, and amounts for a few minutes. How expiry works, which side pays the fee, and the field that flips meaning.

A stablecoin API quote is a price lock. It fixes the exchange rate, the fees, the amount the sender pays, and the amount the recipient gets, for a short window. You execute the payment against the quote's id before it expires. If it expires, nothing moves, and you ask for a new one.

Simple on paper. In practice, three fields cause most of the bugs: when the quote expires, which side pays the fee, and which currency the amount is in.

What does a quote actually lock?

Everything the user needs to say yes. A good quote response answers four questions with numbers, not estimates:

  • What rate am I getting, and what was the market rate?
  • What does this cost, fee by fee?
  • How much leaves the sender?
  • How much arrives at the recipient?

Here's a BlindPay payout quote response, straight from the payout quotes docs:

JSON

commercial_quotation is the raw market rate. blindpay_quotation is the rate net of the fee. The gap between them is the spread, visible on every quote. sender_amount and receiver_amount are the two numbers your UI shows. EVM payout quotes also carry a contract object: the ERC-20 approve payload for wallets that sign their own transactions.

If a provider's quote gives you one rate and one total, you can't tell spread from fee. Ask for the itemized version.

How long does a quote last, and why so short?

Because FX moves. A quote that lasted an hour would either carry a fat buffer (you pay for it) or leave the provider exposed. Minutes is the normal range.

At BlindPay the defaults are:

Quote typeDefault expiryException
Payin quote5 minutesOTC Pix payin quotes: 10 seconds
Payout quote5 minutesSEPA payout quotes can be shorter
Transfer quote5 minutesNone

Read expires_at from every response. Don't hardcode 5 minutes. And note the unit: expires_at is epoch milliseconds, not seconds. Divide by 1,000 before passing it to a library that expects seconds, or your countdown will say the quote expires in the year 56,000.

Every rail's window is in the cut-off times reference.

What happens when a quote expires?

The execute call fails and no money moves. That's the point: an expired quote protects both sides from a stale price.

Build the UX around it:

  1. Show the quote with a visible countdown driven by expires_at.
  2. When it hits zero, disable the confirm button and fetch a new quote.
  3. Show the new numbers. If they moved, say so.
  4. Execute against the new id.

On an external wallet flow, there's one extra trap. If the user signs an on-chain approval and the transaction is slow to mine, the quote can expire while they wait. Quote again rather than committing an expired one.

Also: a quote backs one payment. At BlindPay, a quote_id can only back one payout, and a second call with the same quote returns an error. That's a useful second layer against double-sends, but it's not a substitute for proper idempotency on your retries.

Who pays the fee: sender or recipient?

The cover_fees flag decides it, and the choice changes which number stays fixed.

cover_feesWho paysWhat happens to the amounts
falseThe recipientThe fee comes off what the recipient gets. The common case.
trueThe senderThe fee is added on top, so the recipient gets the full amount.

Payroll is the classic true case. A company paying a contractor in Mexico wants them to receive exactly 20,000 MXN, so the company absorbs the fee. A marketplace paying out sellers usually leaves it false and shows the net.

Which currency is request_amount in?

This is the one that bites. currency_type says which side of the payment request_amount refers to, and on BlindPay it means opposite things on payins and payouts:

Quotecurrency_type: "sender"currency_type: "receiver"
Payout quoteThe stablecoin being sentThe fiat the bank account receives
Payin quoteThe fiat the payer sendsThe stablecoin the wallet receives

Same field, same values, flipped direction. If you share one "build quote" helper across both flows, test both. A payout helper that assumes sender means fiat will quote the wrong side of every payment.

Why are amounts integers?

Floating point and money don't mix. 0.1 + 0.2 isn't 0.3 in JavaScript, and you don't want to find that out in a reconciliation report. So stablecoin APIs usually take minor units.

At BlindPay, request_amount is an integer and doesn't accept floats. 10000 is 100.00. 500000 is 5,000.00. Two more rules worth knowing:

  • Whole pesos. For MXN, COP, and ARS payins quoted on the sender side, the amount must be a multiple of 100. 10050 fails with request_amount_must_be_a_whole_currency_unit, because those rails settle in whole units.
  • Minimums. SWIFT payouts need at least 100 USD requested. SEPA needs 11 USDC on the sender side or 10 EUR on the receiver side.

Convert at the edge of your system, once. Store minor units everywhere else.

What should you check in a provider's quote API?

  • Is the fee itemized? Market rate, applied rate, flat fee, and partner fee as separate fields.
  • Is the expiry machine-readable? A timestamp on every response, not a number in the docs.
  • Can you choose who pays? A cover_fees style flag, not a support ticket.
  • Can you quote either side? "Send exactly X" and "receive exactly Y" are different products.
  • Is a quote single-use? It should back one payment and fail loudly on reuse.

The quote is where the price gets set, so it's also where hidden costs hide. Settlement speed matters too: see how long a stablecoin payout takes. For where the quote sits in the full flow, see how a stablecoin payment moves.

Where does BlindPay fit?

BlindPay is a stablecoin API for cross-border payouts and collections: USDC or USDT in, local currency out over Pix, SPEI, ACH, RTP, SEPA, and SWIFT (POBO/COBO) to 100+ countries, with no pre-funding. Every quote itemizes the market rate, the applied rate, and each fee, and virtual USD accounts turn ACH, wire, and SWIFT deposits into stablecoins. Pricing is on the pricing page.

What to do next

Create a payout quote on a free development instance and read the response field by field. Then flip cover_fees and currency_type and watch which numbers move. Ten minutes of that beats an hour of docs. Start with the payout quotes guide, then the payin quotes guide for the flipped direction.

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

FAQ