POST /v2/quotes and you get back one or more priced options — no resource ids and no recipient. It answers “what would this cost” so you can show a customer a price before they commit.
If you take your own margin, declare it on the quote — once we have switched the field on for the API; until then it returns 403 FEATURE_NOT_ENABLED. Send markupBps, markupAmount, or both, and every option comes back priced with it — so the price you show your customer is the price the redeeming order charges. The order then declares nothing: see Redeem the option.
Test this flow in sandbox. Drive a conversion end-to-end with simulated
money first — start with the sandbox quickstart, then
conversion simulation — then apply the same request
shape to a quote.
Prerequisites
- Your API key.
- A source and destination asset pair Conduit prices — an unpriceable pair returns
422 UNSUPPORTED_PAIR. Withdrawal mode prices a rail fee only and needs no pair. - An
amountlarge enough that neither side rounds to zero. When you lock the destination, Conduit divides by the rate to derive what you send. If that result rounds to zero at the source asset’s precision, the quote returns422 AMOUNT_OUT_OF_RANGE(details.reason: source_rounds_to_zero), withdetails.amountechoing the amount you sent. Branch ondetails.reasonrather than the message text to tell this apart from the other causes of that error.
Step 1 — Price it
Sendsource, destination, lockSide, and amount. Two more things decide what you get back: whether source and destination name the same asset, and whether you include destinationCountry — the payout recipient’s domicile. There’s no separate mode field — these two signals discriminate three modes.
Conversion only
Different assets, nodestinationCountry. One option, with rail: null — there’s no payout leg to route.
Conversion and payout
Different assets plus adestinationCountry. One option per rail actually available: the domestic US rails (fedwire, rtp, fednow) are evaluated for a USA recipient, and the UK schemes (faster_payments, chaps) for a GBR one, regardless of what country you send — a valid routing number or sort code proves the account’s country, so those rails appear whenever the corridor otherwise supports them; swift is the one rail actually routed to the destinationCountry you send.
Two different fiat currencies plus a destinationCountry return 400 VALIDATION_ERROR: no order can redeem a payout leg chained off a fiat-to-fiat conversion. Price that move in two steps — quote and create the conversion with no destinationCountry, then send from the destination virtual account with a standalone payout.
201 with options: [], not an error.
Withdrawal only
The same asset on both sides, plus adestinationCountry. One option per available rail, and rate: null on each — there’s no FX leg to price, only a rail fee:
destinationCountry returns 400 VALIDATION_ERROR — there’s nothing to price.
The envelope around options[]
sourceAssetRef and destinationAssetRef echo the pair you asked for. They name an asset — a code, plus a chain when the asset is on-chain — and never carry an amount. They’re deliberately not called sourceAsset / destinationAsset: an order response uses those two names for money, amount included, and one client type can’t mean both.
amount is the amount the quote locked, in the asset of the side lockSide names. It’s money-shaped like every other amount in a /v2 response, so you never infer its asset from lockSide yourself.
Step 2 — Read an option
Each entry inoptions[] prices one path. A conversion-only or payout-mode option is redeemable in Step 3; a withdrawal-mode option (rate: null) is preview-only — it prices a rail’s fee for a standalone payout, and redeeming it as an order returns 422 INVALID_ORDER_COMBO. Because nothing redeems it, a withdrawal quote refuses markupBps and markupAmount; declare the margin on the payout itself.
Step 3 — Redeem the option
Create the order withquoteOptionId instead of amount / lockSide — the order inherits both from the option, so sending either alongside quoteOptionId returns 400 VALIDATION_ERROR. A redemption also always names an explicit source (wallet or virtual account); sourceAsset (deposit funding) is refused alongside quoteOptionId, since there’s no funding window to check against the option’s locked rate. A redemption declares no margin of its own. If you priced the quote with markupBps or markupAmount, the option carries that margin, the order charges it at the option’s locked rate, and it accrues to you — so sending either field alongside that option returns 400 VALIDATION_ERROR. Declaring the margin twice would charge your customer a price the quote never showed.
On an option you priced with no margin, markupAmount is still available, and it behaves differently here than on a fresh order: the option’s sourceAmount and destinationAmount are already locked and never recomputed, so markupAmount always adds to totalDebit — on both lock sides — rather than reducing the principal the way it would on a source-locked order created directly. markupBps is refused on every redemption, because a percentage only exists inside a locked rate and redemption never recomputes one. Declare it on the quote instead.
A payout-mode option needs autoPayout naming the recipient (quotes carry no recipient), and it’s subject to the same documentation and whitelist policy as a standalone payout — most purposes need at least one documents id:
- The option is single-use and short-lived.
expiresAtis about 5 minutes out. - A payout-mode option’s
autoPayoutmust match what the option priced. Itsrailmust equal the option’s own, and — for a fiat payout — itsrecipient.postalAddress.countrymust equal thedestinationCountryyou quoted. Every payout-mode option has an on-chain source, because a fiat-to-fiat pair is never quoted with adestinationCountry. - A withdrawal-mode option (
rate: null) can’t be redeemed as an order — it only informs a standalone payout. - Recipient-type pricing is rare, but possible. If a pricing rule scoped to this payout’s recipient type would have priced the option differently, redemption is refused rather than collecting the wrong amount. Create the order directly with
amount/lockSideinstead — pricing will resolve against the real recipient.
End-to-end
POST /v2/quotes— get backoptions[].- Show the customer a price from the option you want (its
endUserRate,recipientAmount,totalDebit). POST /v2/orderswith that option’squoteOptionId(plusautoPayoutfor a payout-mode option).- The order is created already priced at the quote’s locked rate — proceed exactly as you would for any other order:
POST /v2/orders/{orderId}/execute, orautoExecute: trueon create. See Convert crypto and Send a payout for what happens next.
See also
- Convert crypto — creating a conversion order directly, without a quote.
- Send a payout — the standalone payout endpoint a withdrawal-mode option informs, and the documentation/whitelist policy an
autoPayoutredemption shares. - Errors — the full
QUOTE_*error reference.