Open a persistent WebSocket connection to receive live RFQ broadcasts and submit quotes. This is the primary integration path for market makers.
Endpoint
wss://api.convallax.com/maker/v1/ws
If the relay requires authentication:
wss://api.convallax.com/maker/v1/ws?apiKey=<your-key>
Connection Lifecycle
On successful connection, the server sends a confirmation:
{
"type" : "connected" ,
"protocolVersion" : 1 ,
"serverTime" : "2026-06-15T12:00:00.000Z" ,
"authRequired" : false
}
If authRequired is true and no valid apiKey query parameter is provided, the connection is closed with code 4001.
The server sends a WebSocket ping every 30 seconds. Your client must respond with a pong to maintain the connection. Most WebSocket libraries handle this automatically.
Server → Maker Messages
rfq — New RFQ Broadcast
Sent when a trader submits a signed request for quote. The envelope contains the full signed RFQ body, including the nested payload with market, option, and trade sub-objects.
Unique broadcast ID — include this in your quote reply.
ISO 8601 deadline to submit your quote.
Milliseconds from broadcast to deadline.
The full signed RFQ body. EIP-712 signature from the taker wallet.
Nested RFQ payload. RFQ protocol version (currently 2).
Contains conditionId (bytes32), yesTokenId (uint256 string), question (string).
Contains strikeBps, expiryMs, optionType, tauDays, sigmaL, currentYesPrice, isResolutionExpiry.
Contains side ("buy"/"sell") and size (whole options).
{
"type" : "rfq" ,
"broadcastId" : "broadcast-456" ,
"deadlineIso" : "2026-06-15T12:00:00.800Z" ,
"timeoutMs" : 800 ,
"envelope" : {
"signature" : "0x..." ,
"signatureEncoding" : "eip712" ,
"payload" : {
"version" : 2 ,
"rfqId" : "abc-123" ,
"wallet" : "0xTrader..." ,
"createdAt" : "2026-06-15T12:00:00.000Z" ,
"market" : {
"conditionId" : "0xa4ddc18895cc7b14..." ,
"yesTokenId" : "51508280778..." ,
"question" : "Will there be a Hantavirus outbreak in 2026?"
},
"option" : {
"strikeBps" : 50 ,
"expiryMs" : 1735689600000 ,
"optionType" : "call" ,
"tauDays" : 7 ,
"sigmaL" : 2.0 ,
"currentYesPrice" : 0.62 ,
"isResolutionExpiry" : false
},
"trade" : {
"side" : "buy" ,
"size" : 10
}
}
}
}
Key fields for pricing
Extract these from the nested envelope.payload for your pricing model:
Field path Description payload.option.currentYesPriceCurrent YES price (decimal 0–1) payload.option.strikeBpsStrike in bps of 1 ( e . g . ‘ 50 ‘ = 1 (e.g. `50` = 1 ( e . g .‘50‘ = 0.50) payload.option.optionType"call" or "put" (or 0/1)payload.option.expiryMsExpiry in milliseconds payload.option.tauDaysTime to expiry in days payload.option.sigmaLImplied volatility (logit space) payload.trade.sideTaker’s side: "buy" or "sell" payload.trade.sizeNumber of whole options
Maker → Server Messages
quote — Submit a Quote
Reply to an RFQ broadcast with your quoted price. Must arrive before deadlineIso.
Must match the broadcastId from the RFQ.
Your unique maker identifier. If omitted, defaults to "anonymous".
Must match envelope.payload.rfqId.
"buy" or "sell" — must match the taker’s requested side (identifies which trade you’re quoting for). Your price is the ask if "buy", or the bid if "sell".
Your quoted price per option. Must be in (0, 1).
Number of whole options. Must be ≥ 50% of requested size.
Optional greeks: delta, gamma, theta, vega.
Optional bid-ask spread in basis points.
Optional quote validity in milliseconds.
{
"type" : "quote" ,
"broadcastId" : "broadcast-456" ,
"makerId" : "my-mm-id" ,
"quote" : {
"rfq_id" : "abc-123" ,
"side" : "sell" ,
"price" : 0.12 ,
"size" : 10 ,
"greeks" : { "delta" : 0.45 , "theta" : -0.02 },
"spread_bps" : 200 ,
"expires_in_ms" : 5000
}
}
Quote Validation
Check Requirement broadcastIdMust match an active broadcast quote.rfq_idMust match envelope.payload.rfqId quote.sideMust match the taker’s requested side quote.size≥ 50% of requested size quote.priceMust be in (0, 1) No-arbitrage Price ≤ maximum payoff for the option type Timeliness Must arrive before deadlineIso
Winner Selection
Taker action Winning quote Buying optionsLowest valid price wins Selling optionsHighest valid price wins
Example: Full Integration
import WebSocket from 'ws' ;
const ws = new WebSocket ( 'wss://api.convallax.com/maker/v1/ws' );
ws . on ( 'open' , () => console . log ( 'Connected to relay' ));
ws . on ( 'message' , ( raw ) => {
const msg = JSON . parse ( raw );
if ( msg . type === 'connected' ) {
console . log ( `Protocol v ${ msg . protocolVersion } ` );
}
if ( msg . type === 'rfq' ) {
const { broadcastId , envelope } = msg ;
const { payload } = envelope ;
const { option , trade } = payload ;
console . log ( `RFQ ${ payload . rfqId } : ${ option . optionType } @ K= ${ option . strikeBps } ` );
// Your pricing logic here
const price = computePrice ( option , trade );
ws . send ( JSON . stringify ({
type: 'quote' ,
broadcastId ,
makerId: 'my-mm' ,
quote: {
rfq_id: payload . rfqId ,
side: trade . side ,
price ,
size: trade . size ,
},
}));
}
});
ws . on ( 'ping' , () => ws . pong ());