Market data
wss://inflection.exchange/ws/market-data
Public: no key needed. The socket sends nothing until you subscribe. For a walk-through with code, read the market data guide.
Connecting
Section titled “Connecting”If the exchange is not ready, it answers the upgrade with HTTP 503 and a
Retry-After header. Wait that many seconds, plus a random delay. Then try
again.
Send your first subscribe within 30 seconds. If you do not, the server closes
the socket.
Each frame holds one JSON message. Send text frames only. The server can compress the frames it sends.
The server sends a ping every 20 seconds. If it gets no pong within 20 seconds, it closes the socket. Most WebSocket libraries answer pings for you.
Subscribing
Section titled “Subscribing”Send a subscribe for one channel, naming markets, series or both.
| Channel | What you get |
|---|---|
book |
The order book of each market. With level l1, the best bid and the best ask. With l2, a snapshot of the whole book, then the levels that change. |
trades |
Each trade as it happens. There is no snapshot. |
status |
A status message when a market opens, closes or settles, with the outcome once it settles. |
A market is one window, named by its market_id. A series is a line of
windows, such as btc-updown-5m. A market lists its series in series. If
you subscribe to a series, each new window arrives when it starts trading, and
a market leaves your subscription after it settles.
A market has one level at a time. If you ask for the other level, it replaces
the first. The server then sends a new snapshot.
The server answers with subscribed, and then a snapshot of each book. It
lists in rejected each series or market it did not accept. You cannot
subscribe to book or trades for a market that has closed.
A message names at most 100 series and markets. You can hold at most 200 at
once, counted across the channels. A request that breaks these rules gets an
error.
Prices
Section titled “Prices”A book holds Up prices only, as [price_bps, quantity]. The quantity is in
lots. To read the book for Down, subtract each Up price from 10,000 and swap
the sides. A Down bid at 4,900 is an Up ask at 5,100.
Sequence numbers
Section titled “Sequence numbers”Each market has its own seq. It counts the changes to that market’s book:
1, 2, 3, with no gaps. book, book_update and l1 share the count.
- When you get a
book, replace your book and keep itsseq. - If a
book_updatehas aseqone above yours, apply it. - If its
seqis at or below yours, ignore it. - If its
seqis more than one above yours, you missed an update. Subscribe to that market’s book again.
An l1 holds the whole top of the book, so you replace what you hold. Its
seq can jump, because the server sends an l1 only when the best bid or ask
changes. A jump in l1 is not a gap. Ignore an l1 at or below your seq.
A trade has no seq. Its trade_id counts 1, 2, 3 in each market.
Closing
Section titled “Closing”The server closes the socket with one of these codes.
| Code | Why | What to do |
|---|---|---|
| 1001 | The server is restarting. | Connect again after a random delay. Then subscribe again. |
| 1008 | You sent no subscribe within 30 seconds, or you sent requests faster than the server could answer them (too many requests waiting). |
Subscribe soon after you connect. Send requests more slowly. |
| 1011 | The server got no answer to a ping. | Answer pings. Then connect again. |
| 1013 | You read too slowly and fell behind, or the server was under load and dropped you. | Connect again after a random delay. Then subscribe again. You get new snapshots. |
You send
Section titled “You send”Subscribe
Section titled “Subscribe”subscribe. Start receiving a channel for markets, series or both.
Name at least one series or market. The server answers with subscribed.
On the book channel, a snapshot of each market follows: a book at level
l2, or an l1 at level l1. A subscription to a series covers the windows
you can follow now, and each new window later. These are the trading windows
and the windows that ended in about the last 2 hours. A series with no
windows now, such as Nvidia at the weekend, is accepted. Its windows arrive
when they start trading.
You can subscribe again to a market you hold. This replaces its level, or gives you a fresh snapshot after a gap in its sequence numbers.
Send only the fields below. level goes only with a subscribe to book.
| Field | Type | Required | |
|---|---|---|---|
type |
"subscribe" |
yes | |
channel |
book | trades | status |
yes | |
level |
l1 | l2 |
no | l1 sends the best bid and ask when either changes. l2 sends the whole book, then changes. Default l1. |
series |
list of string | no | Series such as btc-updown-5m. At most 100 series and markets in one message. |
markets |
list of MarketId | no | Market ids. At most 100 series and markets in one message. |
{ "channel": "book", "level": "l2", "markets": [ 1234 ], "type": "subscribe"}{ "channel": "trades", "markets": [ 1234 ], "type": "subscribe"}{ "channel": "status", "markets": [ 99 ], "series": [ "btc-updown-5m", "eth-updown-5m" ], "type": "subscribe"}{ "channel": "book", "level": "l1", "markets": [ 1234 ], "type": "subscribe"}Unsubscribe
Section titled “Unsubscribe”unsubscribe. Stop receiving a channel for markets, series or both.
Name the same series or markets you subscribed to. The server answers with
unsubscribed. On the book channel, if a series you still hold covers a
market you removed, the server sends a fresh snapshot of that market.
| Field | Type | Required | |
|---|---|---|---|
type |
"unsubscribe" |
yes | |
channel |
book | trades | status |
yes | |
series |
list of string | no | |
markets |
list of MarketId | no |
{ "channel": "trades", "markets": [ 1234 ], "type": "unsubscribe"}You receive
Section titled “You receive”Replies
Section titled “Replies”The answer to each request you send.
Subscribed
Section titled “Subscribed”subscribed. The server accepted a subscribe.
series and markets list what you now hold from this request. markets
also holds the windows that each series covers now. Snapshots follow this
message.
Each rejected item names a series or a market_id, and a reason:
reason |
Means |
|---|---|
unknown_series |
No such series. |
unknown_market |
No such market. Also a window that is not trading and ended more than a few hours ago. |
market_closed |
The market is closed or settled, so you cannot follow it on this channel. |
| Field | Type | Always sent | |
|---|---|---|---|
type |
"subscribed" |
yes | |
channel |
book | trades | status |
yes | |
level |
l1 | l2 |
no | The level you now hold. Sent only for the book channel. |
series |
list of string | yes | |
markets |
list of MarketId | yes | |
rejected |
list of Rejected | yes | Each item has a reason, and a series or a market_id. |
{ "channel": "book", "level": "l2", "markets": [ 1234 ], "rejected": [], "series": [], "type": "subscribed"}{ "channel": "trades", "markets": [ 1234 ], "rejected": [], "series": [], "type": "subscribed"}{ "channel": "status", "markets": [ 1234 ], "rejected": [ { "reason": "unknown_series", "series": "eth-updown-5m" }, { "market_id": 99, "reason": "unknown_market" } ], "series": [ "btc-updown-5m" ], "type": "subscribed"}{ "channel": "book", "level": "l1", "markets": [ 1234 ], "rejected": [], "series": [], "type": "subscribed"}Unsubscribed
Section titled “Unsubscribed”unsubscribed. The server ended a subscription.
series and markets list what you held and now do not. An item you did not
hold is not listed.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"unsubscribed" |
yes | |
channel |
book | trades | status |
yes | |
series |
list of string | yes | |
markets |
list of MarketId | yes |
{ "channel": "trades", "markets": [ 1234 ], "series": [], "type": "unsubscribed"}error. The server could not act on a request. The socket stays open.
code |
Means |
|---|---|
bad_request |
The request is not valid. message says why: not JSON, a field the server does not know, a wrong value, or a binary frame. |
empty_subscription |
The request names no series and no market. |
too_many_subscriptions |
The request names more than 100 series and markets, or you would hold more than 200. |
catching_up |
The server is not ready. Subscribe again soon. |
| Field | Type | Always sent | |
|---|---|---|---|
type |
"error" |
yes | |
code |
bad_request | empty_subscription | too_many_subscriptions | catching_up |
yes | |
message |
string | yes |
{ "code": "bad_request", "message": "level is l1 or l2", "type": "error"}Order books
Section titled “Order books”What you get on the book channel.
Best prices
Section titled “Best prices”l1. The best Up bid and ask of a market.
Sent at level l1, first as a snapshot, and then when the best bid or ask
changes. bid and ask are the whole top of the book, so replace what you
hold. A side with no orders is null.
seq can jump between two l1 messages. This is not a gap.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"l1" |
yes | |
market_id |
integer | yes | The market’s market_id from the markets API. The markets service builds it from the market’s series and end time. An id is never reused. |
seq |
integer | yes | The market’s own count of book changes. See Sequence numbers above for how to use it. |
bid |
[price_bps, lots] or null |
yes | The best Up bid. |
ask |
[price_bps, lots] or null |
yes | The best Up ask. |
{ "ask": [ 5100, 15 ], "bid": [ 4950, 10 ], "market_id": 1234, "seq": 5, "type": "l1"}{ "ask": [ 5000, 5 ], "bid": [ 4950, 10 ], "market_id": 1234, "seq": 6, "type": "l1"}Book snapshot
Section titled “Book snapshot”book. The whole Up book of a market. Replaces the book you hold.
Sent at level l2, when you subscribe and when a new window of a series you
hold starts trading. Levels run from the best price to the worst. The
snapshot has no trades.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"book" |
yes | |
market_id |
integer | yes | The market’s market_id from the markets API. The markets service builds it from the market’s series and end time. An id is never reused. |
seq |
integer | yes | The market’s own count of book changes. See Sequence numbers above for how to use it. |
bids |
list of [price_bps, lots] |
yes | Up bids, highest price first. |
asks |
list of [price_bps, lots] |
yes | Up asks, lowest price first. |
{ "asks": [], "bids": [ [ 4900, 20 ], [ 4800, 35 ] ], "market_id": 1234, "seq": 2, "type": "book"}Book update
Section titled “Book update”book_update. The levels of an Up book that changed.
Sent at level l2. Each level holds the new total quantity at that price.
Quantity 0 removes the level. One message holds every level that one order,
change or cancel moved. Apply it by the rule for sequence numbers above.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"book_update" |
yes | |
market_id |
integer | yes | The market’s market_id from the markets API. The markets service builds it from the market’s series and end time. An id is never reused. |
seq |
integer | yes | The market’s own count of book changes. See Sequence numbers above for how to use it. |
bids |
list of [price_bps, lots] |
yes | Changed Up bids, highest price first. |
asks |
list of [price_bps, lots] |
yes | Changed Up asks, lowest price first. |
{ "asks": [ [ 5100, 15 ] ], "bids": [], "market_id": 1234, "seq": 3, "type": "book_update"}{ "asks": [], "bids": [ [ 6000, 6 ], [ 4950, 10 ] ], "market_id": 1234, "seq": 4, "type": "book_update"}{ "asks": [], "bids": [ [ 6000, 0 ] ], "market_id": 1234, "seq": 5, "type": "book_update"}Trades
Section titled “Trades”What you get on the trades channel.
trade. One match in a market.
The exchange sends one trade for each match, with the Up price.
taker_outcome and taker_side say what the order that took liquidity did.
To read the trade for Down, use 10,000 minus up_price_bps. For example,
down and buy at up_price_bps 6000 is a purchase of Down at 4000: 40¢.
A trade names no account and no order. If your own order traded, you also get
a fill on the trading socket.
A trade has no seq. Its trade_id counts 1, 2, 3 in the market.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"trade" |
yes | |
market_id |
integer | yes | The market’s market_id from the markets API. The markets service builds it from the market’s series and end time. An id is never reused. |
trade_id |
integer | yes | Counts 1, 2, 3 within the market. |
up_price_bps |
integer | yes | The price of Up in this trade. |
quantity |
integer | yes | Lots traded. |
taker_outcome |
up | down |
yes | The outcome the taker traded. |
taker_side |
buy | sell |
yes | Whether the taker bought or sold that outcome. |
time_ms |
integer | yes | When the trade happened, in epoch milliseconds. |
{ "market_id": 1234, "quantity": 6, "taker_outcome": "down", "taker_side": "buy", "time_ms": 1700000000123, "trade_id": 1, "type": "trade", "up_price_bps": 6000}Status
Section titled “Status”What you get on the status channel.
Market status
Section titled “Market status”status. A market opened, closed or settled.
You also get a status when you subscribe, for each market the request
covers. Here open means the market is trading, so it covers open, live and
halted in the markets API.
outcome is null until the market is settled. Then it is up or
down for the winner, or void when no price could decide the market. See
market_settled for what a void pays.
| Field | Type | Always sent | |
|---|---|---|---|
type |
"status" |
yes | |
market_id |
integer | yes | The market’s market_id from the markets API. The markets service builds it from the market’s series and end time. An id is never reused. |
series |
string or null | yes | The series of the market. |
status |
open | closed | settled |
yes | |
outcome |
up | down | void or null |
yes |
{ "market_id": 1234, "outcome": null, "series": "btc-updown-5m", "status": "open", "type": "status"}{ "market_id": 1234, "outcome": null, "series": "btc-updown-5m", "status": "closed", "type": "status"}{ "market_id": 1234, "outcome": "up", "series": "btc-updown-5m", "status": "settled", "type": "status"}