Skip to main content
A quote prices a move before you create it. Send an asset pair and an amount to 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 amount large 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 returns 422 AMOUNT_OUT_OF_RANGE (details.reason: source_rounds_to_zero), with details.amount echoing the amount you sent. Branch on details.reason rather than the message text to tell this apart from the other causes of that error.

Step 1 — Price it

Send source, 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, no destinationCountry. One option, with rail: null — there’s no payout leg to route.

Conversion and payout

Different assets plus a destinationCountry. 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.
A rail eligible for the route but not for a payout to that corridor (or the reverse) is left out — it’s never defaulted in. A corridor with no eligible rail at all still returns 201 with options: [], not an error.

Withdrawal only

The same asset on both sides, plus a destinationCountry. One option per available rail, and rate: null on each — there’s no FX leg to price, only a rail fee:
The same asset with no 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 in options[] 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 with quoteOptionId 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 order executes at the option’s locked rate and fees — nothing is re-priced. Keep in mind:
  • The option is single-use and short-lived. expiresAt is about 5 minutes out.
  • A payout-mode option’s autoPayout must match what the option priced. Its rail must equal the option’s own, and — for a fiat payout — its recipient.postalAddress.country must equal the destinationCountry you quoted. Every payout-mode option has an on-chain source, because a fiat-to-fiat pair is never quoted with a destinationCountry.
  • 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 / lockSide instead — pricing will resolve against the real recipient.

End-to-end

  1. POST /v2/quotes — get back options[].
  2. Show the customer a price from the option you want (its endUserRate, recipientAmount, totalDebit).
  3. POST /v2/orders with that option’s quoteOptionId (plus autoPayout for a payout-mode option).
  4. 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, or autoExecute: true on 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 autoPayout redemption shares.
  • Errors — the full QUOTE_* error reference.