RFQ
RFQ markets match a taker's request against a maker's quote instead of a continuous book. Product behavior — who can quote, how prices are validated, how funding is sampled — is described in RFQ Markets. This page covers the SDK calls.
Request a quote (taker)
import { Side } from "@n1xyz/nord-ts";
const { actionId, orderId } = await user.placeRfqOrder({
marketId,
side: Side.Bid,
size: 0.5,
price: 50000,
timeout: { seconds: 5 }, // optional request lifetime
minimalFill: 0.1, // optional minimum acceptable fill
isReduceOnly: false, // optional
clientOrderId, // optional
});
price is the limit for the request: the resulting execution may be better, never
worse. orderId identifies the request to makers.
Fill a request (maker)
Makers watch for requests and respond with fillRfqOrder:
const result = await user.fillRfqOrder({
marketId,
orderId,
price,
minimumSize, // optional
maximumSize, // optional
isReduceOnly, // optional
timeout, // optional
});
The result distinguishes a real trade from a price observation:
if (result.execution === null) {
// Funding sampling only: no trade, no balance or position change.
} else {
const { filledSize, executionPrice, tradeId } = result.execution;
}
result also carries actionId, orderId, makerAccountId, and
takerAccountId.
A null execution is not a failure and not a fill. Treating it as a trade
double-counts volume and corrupts position tracking. This replaced the older
RfqFillStatus field — see the Changelog entry for
v20.0.0.
Watch for requests
const rfqSub = nord.subscribeRfqFills("BTCUSD"); // symbol or marketId
rfqSub.on("message", (update) => console.log(update));
rfqSub.on("error", (error) => console.error(error));
A maker loop typically subscribes to RFQ fill requests, prices each one from its
own model, and calls fillRfqOrder while the request is still live. Requests
expire, so respond within the request's timeout rather than retrying later.