Skip to content
UDX
On this page

Requesting Quotes

Create a request for quote, watch the quotes it attracts, and accept one, over REST or WebSocket.

An RFQ asks makers to price a trade directly. For what an RFQ is, who sees what, and how last look decides the outcome, see RFQs. This walkthrough shows the taker’s operations; the maker’s side is Creating Quotes. It assumes the environment and API key from the Quick Start.

Every RFQ and quote write is asynchronous: the response confirms the exchange accepted the submission, and the outcome is read afterward. Over WebSocket you can create RFQs, stream both your RFQs and the quotes answering them, and accept a quote.

Create an RFQ

Create the RFQ with your client_rfq_id, the market by ticker or an ad-hoc legs list, a size in quantity or cash_quantity, and the side you intend to execute:

{
  "client_rfq_id": "my-rfq-1",
  "ticker": "UDX-EXAMPLE-MARKET-A",
  "side": "buy",
  "quantity": "100"
}

The 202 Accepted response echoes your client_rfq_id. The exchange assigns rfq_id once the RFQ lands, so list your account’s RFQs with your account_id, filtered by client_rfq_id and status=open until it appears with status open, and keep its rfq_id.

Subscribe to the rfqs channel first, as described under Follow the RFQ, so the RFQ’s own frames confirm it. Then send create_rfq. An rfq_create_submitted frame echoing your client_rfq_id acknowledges the accepted submission, and the rfq_opened frame on your subscription confirms the committed RFQ, correlated by the same client_rfq_id. A rejected request returns a type: "error" frame and leaves the connection open.

{
  "id": 5,
  "cmd": "create_rfq",
  "params": {
    "client_rfq_id": "my-rfq-1",
    "ticker": "UDX-EXAMPLE-MARKET-A",
    "side": "buy",
    "quantity": "100"
  }
}

Name one market by ticker or a legs array, and size by quantity or cash_quantity, exactly one of each. An idempotency_key is accepted but not yet used for deduplication, so a retry that reuses it can create a second RFQ. See Create an RFQ for the full parameter contract.

Follow the RFQ

List your RFQs for the RFQ’s status, and list the RFQ’s quotes by rfq_id to watch the quotes it attracts. Reading these responses requires access to the account that created the RFQ. Each quote names its maker only by the opaque quoter_id, carries a side, price, and quantity, and is live while its status is open. Quotes stop arriving at the RFQ’s expires_at.

Open the rfqs channel with the shared subscribe command:

  • Omit tickers to create one subscription covering every RFQ visible to you, including new arrivals.
  • Supply a tickers list to create one independent subscription per ticker. An RFQ matches a ticker subscription if any leg has that ticker.
{
  "id": 6,
  "cmd": "subscribe",
  "params": {
    "channels": [
      {
        "channel": "rfqs",
        "tickers": ["UDX-EXAMPLE-MARKET-A"]
      }
    ]
  }
}

Each subscription is acknowledged with its channel, ticker, and sid.

Each change arrives as its own frame carrying that one RFQ at the next seq:

Frame RFQ status Meaning
rfq_opened open Opened and still soliciting quotes.
rfq_accepted accepted A quote was accepted and last look is running.
rfq_closed closed Concluded after last look, canceled, expired, or otherwise closed.
rfq_rejected rejected Rejected by the exchange.

A multi-leg RFQ reaches every subscription whose ticker is one of its legs. See Stream RFQ Data for the full message contract.

Accept a Quote

Accept the chosen quote by its rfq_id and quote_id, echoing the quote’s price and quantity, the opposite side, and a client_order_id for the order the trade will create:

{
  "side": "buy",
  "price": "0.55",
  "quantity": "100",
  "client_order_id": "my-rfq-1-fill"
}

The 202 Accepted response carries the order_id the trade will use. Acceptance opens last look. Poll the quote: it reads accepted while the window is open, then confirmed if the maker confirms or canceled if the maker cancels or the window lapses. confirmed is the maker’s decision, not the trade. The trade lives on the order the accept created: read the order by the order_id from the accept response, or its fills correlated by your client_order_id. A filled order is the trade; a rejected order means the exchange rejected the execution even though the maker confirmed.

Accept the chosen quote with accept_quote, naming its quote_id and rfq_id and echoing the quote’s price and quantity, the opposite side, and a client_order_id for the order the trade will create:

{
  "id": 9,
  "cmd": "accept_quote",
  "params": {
    "quote_id": "c4ca4238",
    "rfq_id": "8f14e45f",
    "side": "buy",
    "price": "0.55",
    "quantity": "100",
    "client_order_id": "my-rfq-1-fill"
  }
}

The quote_accept_submitted response carries the order_id the trade will use — the exchange accepted the submission, not the trade:

{
  "id": 9,
  "type": "quote_accept_submitted",
  "msg": {
    "quote_id": "c4ca4238",
    "order_id": "45c48cce",
    "client_order_id": "my-rfq-1-fill"
  }
}

Acceptance opens last look, and the outcome reaches the quotes subscription: the quote arrives as quote_accepted when the window opens, then quote_confirmed if the maker confirms or quote_canceled if the maker cancels or the window lapses. quote_confirmed is the maker’s decision, not the trade: read the order by the response’s order_id for the execution, filled or rejected. An rfq_id that is unknown — or not yours — answers a quote_not_found error; a quote_id naming no live quote on that RFQ is rejected (permission_denied), exactly as over REST. idempotency_key is carried but not deduplicated on yet: treat a lost response as unresolved and check your orders by client_order_id before resubmitting.