Quotes

Soft and firm quotes: request fields, responses, safe retries and common failures.

A quote prices one trade: token_in to token_out, for amount of token_in, on chain_id. Ask for a soft quote to show a price, and a firm quote when the user is ready to trade.

Request fields

FieldRequiredMeaning
token_inYesAddress of the token the user sends
token_outYesAddress of the token the user receives
amountYesRaw base-unit quantity of token_in, as a string. Convert with token_in.decimals from discovery
chain_idYesThe chain both token addresses live on
slippage_bpsNoSlippage tolerance in basis points. When omitted, Rave applies the route default and echoes it. Set 0 only for an exact binary fill
recipientFirm onlyYour wallet address: the output tokens settle there
quote_attempt_idNo, firm onlyYour own UUID for safe retries
sourceNoApplication label, such as a wallet or dapp name. Send a string of at most 64 characters; labels are trimmed and case-insensitive
end_userNoAddress of the wallet that will trade, which can differ from the output recipient

We recommend sending source and end_user with every request. They help us serve your users' real trades reliably when demand is high, which means more firm quotes and better execution for your flow.

source and end_user are optional metadata on both soft and firm requests. They are not price inputs, are not echoed in the quote, and are excluded from the quote_attempt_id identity. Adding or changing them on an otherwise identical retry does not create a conflict. Non-string values are ignored; omitting either field is safe. end_user never changes where tokens settle: the output still goes to recipient.

There is no side field: the direction is token_in to token_out. Do not send V1 fields (asset, side, quote_asset); they return 422.

Soft quote

curl -s "$RAVE_API/v2/quotes/soft" \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "token_in": "0x55d398326f99059ff775485246999027b3197955",
  "token_out": "0x390a684ef9cade28a7ad0dfa61ab1eb3842618c4",
  "amount": "100000000000000000000",
  "chain_id": 56,
  "slippage_bps": 50
}
JSON
{
  "type": "soft_quote",
  "schema_version": 2,
  "quote_id": "64ec0a6f-8d98-499f-a1b2-090dd2967dc5",
  "token_in": { "symbol": "USDT", "address": "0x55d398326f99059ff775485246999027b3197955", "decimals": 18 },
  "token_out": { "symbol": "AAPLon", "address": "0x390a684ef9cade28a7ad0dfa61ab1eb3842618c4", "decimals": 18 },
  "amount_in": "100000000000000000000",
  "amount_out": "292558761888100307",
  "price": "341.81167350663256234402428564",
  "expires": "2026-09-26T11:09:47.855097475Z",
  "valid_for_secs": 60,
  "slippage_bps": 50,
  "chain_id": 56
}

The pair is an example; take token_in, token_out and chain_id from discovery. amount_in and amount_out are raw base units; price is a decimal string. Soft-quote IDs are not stored, so GET /v2/quotes/{quote_id} returns 404 for them.

Firm quote

Same body, plus recipient. Complete the approval first. The API cannot tell a typo or a burn address from a real wallet, and tokens sent to the wrong address cannot be recovered.

curl -s "$RAVE_API/v2/quotes/firm" \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  --data @- <<'JSON'
{
  "token_in": "0x55d398326f99059ff775485246999027b3197955",
  "token_out": "0x390a684ef9cade28a7ad0dfa61ab1eb3842618c4",
  "amount": "100000000000000000000",
  "chain_id": 56,
  "slippage_bps": 50,
  "recipient": "YOUR_WALLET_ADDRESS"
}
JSON

The response adds execution.transaction:

{
  "type": "firm_quote",
  "schema_version": 2,
  "quote_id": "550e8400-e29b-41d4-a716-446655440000",
  "token_in": { "symbol": "USDT", "address": "0x55d398326f99059ff775485246999027b3197955", "decimals": 18 },
  "token_out": { "symbol": "AAPLon", "address": "0x390a684ef9cade28a7ad0dfa61ab1eb3842618c4", "decimals": 18 },
  "amount_in": "100000000000000000000",
  "amount_out": "292558761888100307",
  "price": "341.81167350663256234402428564",
  "expires": "2026-09-26T11:10:17Z",
  "valid_for_secs": 30,
  "slippage_bps": 50,
  "chain_id": 56,
  "execution": {
    "safety_label": "execution-preparatory",
    "transaction": { "to": "0xa53B869C883B5036dDf8D7a12B7618e4612C503e", "data": "0x...", "value": "0", "chain_id": 56 }
  }
}

Submit execution.transaction unchanged before expires. If the user changes token_in, amount, recipient, chain or slippage, request a new firm quote. Firm quotes can also carry input_capability; treat it as optional (see Variable Input).

Expiry

Read valid_for_secs and expires on every quote instead of assuming a fixed window. Firm quotes are short-lived, typically 30 seconds. A packet submitted after expires reverts.

Safe retries with quote_attempt_id

Send your own UUID as quote_attempt_id on a firm request. An exact retry with the same body and ID returns the same unexpired quote instead of a new one, provided current eligibility still permits it. A later eligibility change or temporary control outage can withhold that replay; it does not cancel a packet already issued. See temporary quoting-control outages and reconcile any possible broadcast before requesting another trade. The same ID with a changed body returns 409. Use a new UUID for each new attempt.

Common failures

StatusExample bodyWhat to do
400{ "error": "amount must be positive" }Fix the value
400{ "error": "recipient required for firm quotes" }Add recipient
404{ "error": "asset not found for pair 0x.../0x..." }The pair is not published on that chain. Re-read levels
409Reused quote_attempt_id, or capacity exhausted. New ID, or back off
422{ "error": "invalid quote request" }Body does not match the schema, for example a number instead of a string for amount
503{ "error": "price-stream depth does not cover requested amount for 0x.../0x... on chain 56" }Size is above current depth, or quoting is paused. Re-read limits and levels, reduce size

The full table is in Errors.


Did this page help you?