Skip to main content
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.
type
string
Always "rfq".
broadcastId
string
Unique broadcast ID — include this in your quote reply.
deadlineIso
string
ISO 8601 deadline to submit your quote.
timeoutMs
number
Milliseconds from broadcast to deadline.
envelope
object
The full signed RFQ body.
{
  "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 pathDescription
payload.option.currentYesPriceCurrent YES price (decimal 0–1)
payload.option.strikeBpsStrike in bps of 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.
type
string
required
Must be "quote".
broadcastId
string
required
Must match the broadcastId from the RFQ.
makerId
string
required
Your unique maker identifier. If omitted, defaults to "anonymous".
quote
object
required
{
  "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

CheckRequirement
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-arbitragePrice ≤ maximum payoff for the option type
TimelinessMust arrive before deadlineIso

Winner Selection

Taker actionWinning 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());