Skip to content

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.

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.

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.

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.

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.

  1. When you get a book, replace your book and keep its seq.
  2. If a book_update has a seq one above yours, apply it.
  3. If its seq is at or below yours, ignore it.
  4. If its seq is 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.

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.

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. 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"
}

The answer to each request you send.

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. 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"
}

What you get on the book channel.

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. 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. 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"
}

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
}

What you get on the status channel.

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"
}