Variable Input
Route from levels. If a side is variable, Rave handles a short delivery. Do not size a funding floor from the firm quote.
What variable input is
A firm quote is a signed transaction packet. Historically that packet settled only if the caller
delivered the exact amount_in it was quoted for. That is fine when the user's wallet funds the
trade directly, and a problem when a Rave leg is funded from the proceeds of a previous hop, because
those proceeds move between quote and settlement. The packet reverted, and the user's whole
transaction failed.
Variable input removes that failure. On a side published as variable, Rave accepts a short
delivery and settles pro rata. You do not compute a funding floor. You do not re-size the path from
the firm quote. Build the route from levels, request a firm quote for the size you already chose,
and submit the packet.
This contract is the same on every chain Rave publishes.
How to use it
- Route from levels or the stream. Read
pairs[].quoteability.buy.input_capability.modeand
pairs[].quoteability.sell.input_capability.modeseparately. Key any cache on the caller's
credential or partner view identity plus(chain_id, base.address, quote.address, side). Do not
store the raw API key as the identity. Do not copy one side onto the other. - If
modeis"variable", Rave handles a short delivery. Size the path from levels as you
already do. Request a firm quote for that size. Submitexecution.transactionunchanged. If less
thanamount_inarrives, we settle what arrived. - If the field is missing, unrecognized, or
"exact", the fullamount_inmust be available.
Do not put that side behind a hop whose output can land short. - Request the firm quote with
token_in,token_out,amount,chain_id,recipient, and
optionallyslippage_bps. There is nosidefield: direction istoken_intotoken_out. - Submit
execution.transactionunchanged beforeexpires. Firm quotes are short-lived
(valid_for_secs, typically 30 seconds). An expired packet reverts regardless of funding.
input_capability is additive and optional. After checking that the object is present, read mode.
If the object is absent, treat the side or quote as exact.
What you do not do
- Do not size the upstream hop from firm-quote window fields.
- Do not derive a minimum from
min_input_bps. - Do not treat
quoteability.<side>.limits.min_input_amountas a funding floor. That is the
human-denominated trading minimum for the side, not the settlement window.
Firm quotes may still include min_input_bps, max_input_bps, and min_input_amount_raw. Those
fields describe the packet we signed. They are not a second sizing API.
Surfaces
input_capability appears on market levels, stream pair books, and firm quotes. The first two share
one mode-only object. The firm quote may also carry the signed window. Reading one shape as if it
were the other is unnecessary: route from mode, then submit the packet.
| Where it appears | What it carries | What it is for |
|---|---|---|
Each quoteability side of GET /v2/markets/levels, under pairs[].quoteability.buy and pairs[].quoteability.sell | mode, and nothing else | Deciding where a short delivery is allowed |
Each quoteability side of a /v2/stream price frame, under pairs[].quoteability.buy and pairs[].quoteability.sell | mode, and nothing else | The same routing signal on the live stream |
A firm quote response, POST /v2/quotes/firm | mode, and on today's packets min_input_bps, max_input_bps, plus min_input_amount_raw when variable | The signed packet. Not a sizing step. |
The signal is scoped to your published provider view and resolved per leg. variable means every
venue admitted to your view that could win that buy or sell can absorb a short delivery. Buy and
sell are independent, so always read the field from the side you are routing. The same asset can be
exact against one quote token and variable against another on the same chain, in the same
response.
On a firm quote
A variable firm quote using neutral token placeholders:
curl --request POST "https://api.rave-trading.com/api/v2/quotes/firm" \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
--data '{
"token_in": "TOKEN_IN_ADDRESS",
"token_out": "TOKEN_OUT_ADDRESS",
"amount": "200000000000000000",
"chain_id": 56,
"recipient": "RECIPIENT_ADDRESS",
"slippage_bps": 50
}'{
"type": "firm_quote",
"schema_version": 2,
"quote_id": "e1ed9314-c7ce-4a50-86d2-e961749cb0dd",
"token_in": { "symbol": "TOKEN_IN", "address": "TOKEN_IN_ADDRESS", "decimals": 18 },
"token_out": { "symbol": "TOKEN_OUT", "address": "TOKEN_OUT_ADDRESS", "decimals": 18 },
"amount_in": "200000000000000000",
"amount_out": "61189778680331763787",
"price": "305.948893401658818935",
"expires": "2026-08-15T09:33:45Z",
"valid_for_secs": 30,
"slippage_bps": 50,
"chain_id": 56,
"input_capability": {
"mode": "variable",
"min_input_bps": 1,
"max_input_bps": 10000,
"min_input_amount_raw": "20000000000000"
},
"execution": {
"safety_label": "execution-preparatory",
"transaction": { "to": "ROUTER_ADDRESS_FROM_QUOTE", "data": "0x...", "value": "0", "chain_id": 56 }
}
}An exact quote carries the same object with the window closed:
{ "mode": "exact", "min_input_bps": 10000, "max_input_bps": 10000 }When a firm quote includes input_capability, that object carries mode, min_input_bps, and
max_input_bps. A client may read all three after checking that the object is present. If the object
is absent, use the exact fallback. Only min_input_amount_raw is conditional inside the object: it
is present on firm variable quotes and nowhere else. You do not use it to size the route.
amount_in is the most the packet will take. Delivering more does not revert; settlement takes
amount_in and leaves the surplus with you.
On market levels
curl "https://api.rave-trading.com/api/v2/markets/levels?chain_id=56&base_token=TOKEN_BASE_ADDRESS"e_token=TOKEN_QUOTE_ADDRESS" \
-H "Authorization: Bearer ***"{
"pairs": [
{
"pair_id": "PAIR_ID",
"chain_id": 56,
"base": { "symbol": "TOKEN_BASE", "address": "TOKEN_BASE_ADDRESS", "decimals": 18, "chain_id": 56 },
"quote": { "symbol": "TOKEN_QUOTE", "address": "TOKEN_QUOTE_ADDRESS", "decimals": 18, "chain_id": 56 },
"bids": [{ "level": 1, "base_amount": "0.2", "base_amount_raw": "200000000000000000", "quote_amount": "61.189778680331763787", "quote_amount_raw": "61189778680331763787", "price": "305.948893401658818935" }],
"asks": [{ "level": 1, "base_amount": "0.2", "base_amount_raw": "200000000000000000", "quote_amount": "61.250000000000000000", "quote_amount_raw": "61250000000000000000", "price": "306.25" }],
"available": true,
"quoteability": {
"buy": { "status": "available", "tradable": true, "input_capability": { "mode": "variable" } },
"sell": { "status": "available", "tradable": true, "input_capability": { "mode": "exact" } }
},
"min_base_amount": "0.2",
"max_base_amount": "0.2",
"min_base_amount_raw": "200000000000000000",
"max_base_amount_raw": "200000000000000000",
"indicative": true,
"valid_until": "2026-08-16T09:32:00Z"
}
],
"market_open": true,
"as_of": "2026-08-16T09:31:30Z"
}That is the whole object. A levels side never carries min_input_bps, max_input_bps or
min_input_amount_raw. Route from mode.
On stream pair books
Connect from your backend and authenticate in the first client frame. Never place the partner API
key in browser code; expose the data to browsers through your own authenticated relay.
import WebSocket from "ws"; // Backend Node.js only.
import { getPartnerCredential } from "./server-credentials.js";
const credential = await getPartnerCredential(); // Backed by your server-side secret manager.
if (!credential) throw new Error("Partner credential is required");
const ws = new WebSocket("wss://api.rave-trading.com/api/v2/stream");
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ type: "auth", api_key: credential }));
});Price frames use the same mode-only quoteability object as market levels:
{
"type": "price_frame",
"schema_version": 2,
"prices": [],
"market_open": true,
"timestamp": "2026-08-16T09:31:30Z",
"pairs": [
{
"pair_id": "PAIR_ID",
"chain_id": 56,
"base": { "symbol": "TOKEN_BASE", "address": "TOKEN_BASE_ADDRESS", "decimals": 18, "chain_id": 56 },
"quote": { "symbol": "TOKEN_QUOTE", "address": "TOKEN_QUOTE_ADDRESS", "decimals": 18, "chain_id": 56 },
"bids": [],
"asks": [],
"available": true,
"quoteability": {
"buy": { "status": "available", "tradable": true, "input_capability": { "mode": "variable" } },
"sell": { "status": "available", "tradable": true, "input_capability": { "mode": "exact" } }
},
"min_base_amount": "0.2",
"max_base_amount": "0.2",
"min_base_amount_raw": "200000000000000000",
"max_base_amount_raw": "200000000000000000",
"indicative": true,
"valid_until": "2026-08-16T09:32:00Z"
}
]
}Field reference
| Field | Surface | Type | Meaning |
|---|---|---|---|
mode | Both | string | "exact" or "variable". On a levels or stream side: whether Rave will handle a short delivery on that leg. On a firm quote: whether that packet will. |
min_input_bps | Firm quote only | integer | Signed lower bound, in basis points of amount_in. Not a sizing input. |
max_input_bps | Firm quote only | integer | Signed upper bound. 10000 on every side published today, so the packet never takes more than amount_in. |
min_input_amount_raw | Firm variable quotes only | string | Signed floor in token_in base units. Present on firm variable quotes only. Not a sizing input. |
The field names are min_input_bps and max_input_bps. There are no min_fill_bps /
max_fill_bps fields on the API.
Delivering outside the quoted amount
- Exact side, short delivery: reverts. The whole user transaction fails and gas is spent.
- Variable side, short delivery: settles at what arrived, scaled pro rata.
- Above
amount_in: does not revert. The settlement takes the quoted amount and leaves the
surplus with you. - After
expires: reverts. Request a fresh firm quote rather than resubmitting.
Neither reverting case is retryable with the same packet. Re-quote instead.
An exact-side revert uses FillOutOfSignedWindow(uint256,uint256,uint16,uint16), selector
0x42aa024f, when the delivery is below the signed floor.
Key rules
- Route from levels or stream
mode. If it isvariable, Rave handles a short delivery. - Absent field, unknown
mode, orexactall mean the same thing: make the fullamount_in
available. The packet consumes no more than that amount. - Do not size a funding floor from the firm quote.
- Overshooting does not revert. Only an exact underfund does.
- Capability is per
(caller credential or partner view identity, chain_id, token_in, token_out, side),
never per asset. Do not store the raw API key as the identity. - Nothing about variable input changes the packet you submit: pass
execution.transactionthrough
unchanged, exactly as for an exact quote.
Updated about 11 hours ago