Skip to main content
Preview. The maker WebSocket is available on QA only. Connecting on Production returns 404 until we enable it there. Contact Novig to start testing.
The maker WebSocket is the second way to price RFQs. You hold one connection open, Novig pushes each quote round to you, and you answer on the same socket. It replaces the inbound HTTP server that the webhook transport requires. Pick it when you want to price without operating a public endpoint. You need no TLS certificate, no public hostname, and no signature verification. The connection authenticates once, at connect. The trade path is unchanged: a 3-second auction, a 1-second last look, and a rejected trade when the last look goes unanswered.

Connect

Send your OAuth 2.0 access token as a bearer token on the upgrade request. It is the same token the REST API uses. See Authentication.
The token identifies your LP trader, so the socket carries no pricer ID and no signature.

Register a pricer first

The handshake refuses the upgrade when your trader has no pricer registration. Register once with an empty body: a socket pricer needs no webhook and gets no shared secret. Your registration outlives every connection, so reconnecting does not re-register. Register on QA while the socket is in preview. See Registration.

Handshake failures

Authentication fails before the upgrade, as a plain HTTP status code.

Message envelope

Client messages, acks, and channel events share one envelope.
Error frames are the exception. They are bare objects with no envelope. Recognize an error by its code field, not by event.
price, max_wager, and wager are JSON strings in both directions. This differs from the webhook /quote response, where price is a JSON number.

Channels

Subscriptions are per-connection. A reconnect carries none of them.
Subscribe to both channels to trade. rfq delivers the rounds you price; quotes delivers the quote_accepted last look you must answer. A maker subscribed only to rfq never hears that it won, and every trade it wins is rejected.

Round lifecycle

1

Novig opens a round

rfq_created arrives on the rfq channel with the legs and the deadline.
2

You answer

Send create_quote with your price and maximum wager, or decline to pass. Answer before expires_at.
3

Novig closes the auction

rfq_closed arrives. Stop pricing that round.
4

You win, and confirm

quote_accepted arrives on the quotes channel. Answer with confirm inside 1 second.

Client messages

Messages you send to Novig. Novig acks every one.
The data is a bare channel string, not an object. Acked with subscribed.
string
required
"rfq" or "quotes".
Acked with unsubscribed.
string
required
"rfq" or "quotes".
Acked with quote_submitted.
UUID string
required
The round, from rfq_created.
decimal string
required
Decimal probability in (0, 1). "0.45" means $0.45 stake per $1.00 payout. Resolved on a 0.001 grid.
decimal string
required
Largest taker stake this quote covers, in Novig Cash. Must be positive.
string
Your own reference, at most 256 characters. Returned to you as external_flag. Omit it when you don’t need one.
One quote per round. Your first quote stands. A second quote for the same rfq_id is dropped and acked with quote_superseded. To change a price, wait for the next round.
Acked with quote_declined.
UUID string
required
The round, from rfq_created.
Decline every round you do not quote. A decline records that you saw the round and passed; silence is indistinguishable from a pricer that is down or lagging.
Acked with confirm_recorded.
UUID string
required
From quote_accepted.
UUID string
required
From quote_accepted. Novig’s UUID, not your external_flag.
boolean
required
true fills the trade at your quoted price. false rejects it.
You have 1 second, and the last look fails closed. A confirm that misses the window rejects the trade, exactly as false does. A dropped connection between quote_accepted and your answer also rejects the trade.
The first answer wins. A second answer returns CONFIRM_ALREADY_DECIDED, or NO_CONFIRM_WINDOW once the window is gone.

Server events

Events Novig sends you. Subscribe to a channel to receive its events.
Price it before expires_at.
UUID string
required
The round. Name it on every message you send about this round.
array of UUID strings
required
The legs, in order. See Outcome IDs.
ISO-8601 string
required
When the auction closes, 3 seconds after Novig created the round.
Stop pricing the round. A create_quote that arrives after this is rejected with RFQ_CLOSED.
UUID string
required
The round that closed.
Every pricer sees this print, so it carries no identity.
UUID string
required
The round.
decimal string
required
Amount staked.
decimal string
required
Execution price.
ISO-8601 string
required
When the trade filled.
Novig recorded your quote at auction close.
UUID string
required
Novig’s identifier for your quote.
UUID string
required
The round.
UUID string
required
Your pricer.
The taker is executing against your quote.
UUID string
required
Novig’s identifier for your quote. Send this back on confirm.
UUID string
required
The round.
UUID string
required
Your pricer.
decimal string
required
The taker’s stake. Always at or below the max_wager you quoted.
decimal string
required
The price you quoted.
string or null
required
The quote_id you sent on create_quote. null when you sent none.
Two different fields are named quote_id. The one you send on create_quote is your own free-form string; it returns to you as external_flag. The one on quote_accepted is a Novig UUID, and it is the one confirm requires.
Carries the pricer identity the public print omits.
UUID string
required
Novig’s identifier for your quote.
UUID string
required
The round.
UUID string
required
Your pricer.
decimal string
required
Amount staked.
decimal string
required
Execution price.
ISO-8601 string
required
When the trade filled.
Novig sends this only for actionable drops. Losing on price is silent.
UUID string
required
Novig’s identifier for your quote.
UUID string
required
The round.
UUID string
required
Your pricer.
string
required
below_min_wager or unbacked. Each reason carries one extra field naming the number you must beat.

Acks

Novig answers every client message with an ack. An ack uses the standard envelope.
Answers your subscribe.
string
required
"rfq" or "quotes".
Answers your unsubscribe.
string
required
"rfq" or "quotes".
Answers your create_quote.
UUID string
required
The round your message named.
Answers your create_quote.
UUID string
required
The round your message named.
Answers your decline.
UUID string
required
The round your message named.
Answers your confirm.
UUID string
required
The round your message named.
UUID string
required
The quote your answer decided.

Errors

string
required
Stable, machine-matchable. Match on this, not on message.
string
required
Human-readable description.
string
The channel the failing request named. Omitted when absent.
UUID string
The round the failing request named. Omitted when absent.
Every code Novig sends, and what causes it:
An error never closes the socket. Novig answers with a frame and the connection stays up. Handle an error and keep trading; do not reconnect in response to one.
Novig checks your eligibility on every action, not at connect. A pricer deregistered or restricted mid-session keeps its socket and learns on its next create_quote, as a FORBIDDEN frame.

Timing and limits

Keepalive

The server sends a WebSocket protocol Ping every 15 seconds. Answer with a protocol Pong; standard clients do this automatically. A client that misses a ping interval is disconnected. There is no JSON ping message and no idle timeout. A socket that answers its Pings stays open indefinitely.

Reconnecting

Re-subscribe after every reconnect. Subscriptions live on the connection. A new socket carries none of them, and Novig sends no events until you subscribe again.
The socket has no replay and no backfill. It starts at the live edge, so anything sent while you were disconnected is lost. Recover missed executions from the executions feed. Novig closes a socket without a status code, so do not read meaning into a close frame. Reconnect with backoff, then re-subscribe. Event frames drop when your client cannot keep up, rather than blocking the server. Read promptly: a slow consumer silently misses quote rounds.

Running both transports

The webhook is a capability, not a mode. Registering a webhookUrl and connecting the socket are independent choices, and you may do both. With both configured, Novig confirms on whichever leg carried the winning quote. A round your webhook won is confirmed over HTTP; a round your socket won arrives as quote_accepted. Implement both confirm paths, or run one transport. Register with no webhookUrl to make the socket your only path. See Registration.