For the complete documentation index, see llms.txt. This page is also available as Markdown.

Integration Best Practices

Recommendations that make a Multiply integration faster and smoother for your end users — drawn from the patterns we see in the best-performing terminals.

Everything here is optional — the API works without any of it. These are the choices the smoothest, fastest integrations tend to make, with the reasoning and the payoff for your end users spelled out, so you can decide what's worth adopting for your platform.


Draft on page load, promote on commit

What a best-in-class integration does: renders the trading screen from a draft quote (POST /draft-quotes), and only creates a real quote (POST /promoted-quotes/{draft_quote_id}) when the user actually commits.

Why it matters: creating a real quote reserves capacity against your account's notional limit and holds it until the quote expires — that reservation is what guarantees the user can open at the quoted terms. If your screen quotes on load, every end user who is just browsing leverage and fees holds a slice of your limit. At scale, a room full of browsers can reserve your entire limit, and the users who genuinely want to trade get turned away with quote_partner_position_limit_exceeded even though nothing is open. (The limit counts open positions plus in-flight quotes — see in_flight_notional_usd_pips in the error params.)

The payoff for your users: a draft runs the identical pricing pipeline — same entry price, fees, liquidation price, max leverage — but reserves nothing, so your display is always available and your real capacity stays free for people ready to trade. When they commit, promotion succeeds instantly at the drafted terms if the market hasn't moved; if it has, you re-quote — exactly what a stale /quotes result would have forced anyway.

POST /quotes in one shot is a great fit when you already know the quote will be used — server-side flows, or a frontend firing at the moment of confirmation. Details: Draft quotes · Promote draft quote.


Turn a rejection into a one-tap correction

What a best-in-class integration does: reads the params on a rejected quote and uses it to move the user straight back into a valid state, rather than showing a dead-end error.

Why it matters: most quote rejections carry the value that would work — the maximum leverage the model allows, the largest collateral the book supports, the minimum notional, the collateral floor, the slippage ceiling. They're there precisely so your interface can act on them instead of leaving the user to guess.

The payoff for your users: the difference between "Request failed, try again" and a slider that snaps to the allowed maximum with a clear note — "Leverage adjusted 8× → 5×" — and a one-tap path to sign. Concretely:

  1. Clamp the offending input to the value in params (rounding to the market's leverage.step_bps where relevant).

  2. Re-quote and show plainly what changed, so the user stays in control.

  3. On accept, go straight to promote and open the wallet for signature.

Dispatch on code, then read the keys you expect — never regex-parse message. Full table of which codes carry which params: Errors with structured hints. One worth handling explicitly: quote_leverage_exceeds_collateral_floor can't be resolved by lowering leverage — raise collateral to min_collateral_usd_pips instead.


Let the WebSocket drive your market list

What a best-in-class integration does: treats the WebSocket as the primary source for market state — market.discovered, market.eligibility_changed, market.max_leverage_changed — and uses polling only as a periodic safety net.

Why it matters: max leverage and eligibility can change by the second during a live game or a volatile crypto move. A market list refreshed on a timer will quote against values that have already shifted, and those quotes come back rejected.

The payoff for your users: a leverage slider and market list that are correct at the moment they act, so quotes land the first time and trading feels immediate. Keep polling GET /markets every 5–10 minutes as reconciliation — it catches drift and covers a dropped connection — but let the socket be how you learn a cap moved. Market events are the ones that most affect trading feel; position events over the socket are a nice extra for per-user UX.

Details: WebSocket — Market event types.


Render pre-trade numbers from the fee report

What a best-in-class integration does: when a screen only needs to display cost and potential gain, it calls POST /fee-reports rather than a quote endpoint.

Why it matters: a quote takes a few seconds — it pulls live data from several internal and external sources and runs the risk model over it. The fee report computes the same cost and max-gain breakdown from notional and leverage using the market's fee rates, and returns fast enough to paint on load. It creates nothing and signs nothing.

The payoff for your users: fees and potential gain appear instantly as they size a position, instead of a spinner while a full quote resolves. One note to carry into your UI: the fee report's liquidation price is a deterministic at-entry estimate — the binding quote uses a TWAP/inference-based price that may differ — so label it as an estimate wherever you show it.


What's next

Last updated