Quotes & smart routing
What a quote contains, when it can be filled, how long it lasts, and where fees and warnings show up
A quote prices a trade on one outcome across every venue that lists it, and returns the split
that fills best. You then fill the quote by its quoteId. See
Execution for the fill.
GET /orderbook/{venueMarketOutcomeId}/routeAPI reference: Get a quote (smart route).
Request
| Query param | Use |
|---|---|
side | buy (default) or sell. |
maxSpend | Buy: the most to spend, in USD. Required for a buy. |
sellShares | Sell: how many contracts to sell. |
slipCapBps | Slippage cap in basis points. |
allowedVenues | Only route to these venues. Repeat the param for several. |
compareVenues | true adds per-venue single-venue quotes in venueSoloQuotes[], each with its own quoteId. |
deepEstimate | true lists one-time setup costs in feeBreakdown.setupCosts. Hyperliquid's account activation is budgeted on every quote that routes to Hyperliquid either way; this flag only controls whether it, and the other setup items, appear as breakdown lines. |
mode | live (default) or paper. |
signingAddress, fundingAddresses | Self-custody only. See Self-custody trading. |
appFeeBips, appFeeBipsByVenue, referrer, referrerFeeBips, referrerFeeBipsByVenue | Per-trade fee overrides. Send the ...ByVenue maps as JSON strings, for example appFeeBipsByVenue={"polymarket":20,"hyperliquid":10}. Need x-app-api-key. See Fees. |
const quote = await client.getSmartRoute({
venueMarketOutcomeId: outcomeId,
tradeSide: "buy",
maxSpend: 25,
});In the SDK the trade direction is tradeSide. For signingAddress or fundingAddresses, use
the HTTP query as shown in Self-custody trading.
- Quote
status(ok,no_orderbooks) is not a fill HTTPcode(quote_not_found). slipCapBpscaps slippage;appFeeBipsis your fee rate, not slippage.status: "no_orderbooks"means the quote cannot be filled; a warningreasonofno_orderbookonly skips one venue.- A preview has no user JWT; an executable quote has the user's JWT.
Preview vs executable
| Sent | Result |
|---|---|
x-app-id only | A preview quote. Use it to show a price. It cannot be filled, because it is not tied to a user. |
x-app-id and the user's Authorization | An executable quote, sized against that user's balances. Fill it with POST /execution/fill. |
A sell quote always needs a signed-in user. Filling a quote that belongs to someone else, or a
preview quote, returns 400 with code: "quote_user_mismatch".
Can it be filled?
Check status before you fill:
status | Meaning |
|---|---|
ok | A route was found. Check warnings and use an authenticated quote before filling. |
insufficient_balance | The user does not have enough funds. |
insufficient_position | Not enough shares to sell. See positionAvailability. |
insufficient_depth, no_orderbooks, no_bids_above_min_price | Not enough liquidity. |
min_order_size_violated, insufficient_input_amount | The amount is too small for the venue. |
infeasible, checker_rejected, solver_error, invalid_input, engine_unavailable | No valid route could be built. |
When status is not ok, read error. message is informational. Only fill quotes with status: "ok".
Sellable shares
Every sell quote, ok included, carries positionAvailability: the user's shares when the quote
was built, on the venues the request allows.
| Field | Meaning |
|---|---|
totalSellableShares | Shares the user can sell in total. Asking for more returns insufficient_position. |
venueMarketOutcomes[].availableShares | Shares sellable on that leg. A leg is a tradeable position or a resolved, redeemable one. |
Use it to cap the size you request, for example behind a "Max" button. It is a snapshot, not a reservation: the fill re-checks the live venue balance, so it can still fail if the position changed after the quote.
Expiry
Every quote carries two timestamps:
| Field | Meaning |
|---|---|
refreshAt | From this time, fetch a new quote before showing a price. The current one still fills. |
expiresAt | After this time the quote cannot be filled. |
A quote currently lasts about 45 seconds, with refreshAt about 15 seconds after it is created.
Some routes expire sooner. Always read expiresAt; never hard-code the window.
A fill after expiry returns 400 with code: "quote_not_found" or "quote_expired". Follow
Errors, retries & idempotency. fallbackToLatest is on
Execution.
A quoteId fills at most once. See Errors, retries & idempotency.
What the quote contains
| Field | Meaning |
|---|---|
quoteId | Pass to POST /execution/fill. |
fills[] | One entry per venue leg: venue, venueMarketOutcomeId, avgPrice, venueQty, venueFee, and the price levels used. |
totalFilled | Total shares across legs. |
feeBreakdown | Line-item costs. See below. |
totalCostIncFees | Total the user pays, including app and referral fees. |
estimatedPayout | Payout if the outcome wins, net of settlement fees. |
estimatedProfit, returnPct | Payout minus cost, in USD and percent. |
slippage | Volume-weighted price against the reference midpoint. |
allocations[], bridgeSteps[] | Which chain's funds pay for which venue, and any cross-chain moves needed. |
warnings[] | Venues left out or flagged, without blocking the quote. |
Fees in the quote
feeBreakdown is the number to show before the user commits.
| Field | Meaning (USD) |
|---|---|
rawExecCost | Price times shares, before fees. |
venueFees | Venue trading fees. |
builderFee | Builder-code fee, when present. |
bridgeFees | Expected cross-chain transfer fees. |
executionGas | Estimated network gas for execution. |
totalCost | The sum of the lines above. Excludes app and referral fees. |
appFee | Your app fee on this trade, if it fills in full. A sell is charged on gross proceeds. Present only when above 0. |
referralFee | A user-paid referral fee, when present. |
setupCosts | One-time setup items, only with deepEstimate=true. Its hyperliquidActivation line shows $1.25: bridging to a new HyperCore address costs about $1.23 (Hyperliquid's 1 USDC plus Relay's ~$0.20 delivery cost, both deducted from the bridged amount), rounded up. |
Use totalCostIncFees for the all-in number. Fees explains each kind.
Warnings
warnings[] lists venues the route skipped or flagged. Each entry has venue,
venueMarketOutcomeId, and reason. The quote is still usable. Known reasons include
low_liquidity, low_balance, stale_orderbook, empty_book, crossed_book, no_orderbook,
app_fee_unsupported, referral_unpaid_on_solana, and referrer_not_activated_on_hypercore.
Geo warnings. A quote can still include venues unavailable in the user's country. The
warning reason reads Venue not available in your region (XX) when the country is known.
Before offering a fill, re-quote with allowedVenues restricted to eligible venues, or show
that trading is unavailable. A sell quote warns on the held legs it would sell; those cannot be
re-routed. The fill checks location again and can return 403 with code: "geo_blocked". See
Venue geo availability.
Self-custody quotes also carry custodyWarnings[]. See
Self-custody trading.