The pricing WebSocket receives order books streamed from market makers. Bebop uses your levels to determine whether a path exists for a user order.
Pricing updates are Protobufs sent to the /pricing endpoint. See Connection for WebSocket setup.
Levels you stream are combined to derive cross-pairs. See Routing › Cross-pair derivation.
Requirements
-
Stream levels against USDC or another chain-appropriate stablecoin. You can also stream against liquid majors like WETH.
-
Quote any cross-pair derivable from your streams.
-
Do not send pricing updates more frequently than every 400 ms.
-
Streamed levels must match the prices you actually quote. Solvers precompute expected prices from your stream; divergence gives them a worse realized price than estimated. Bebop monitors the gap between streams and firm quotes, and repeated divergence can get you banned.
-
Do not include duplicate prices in the same update:
"bids": [
[0.443005,100], // price, amount
[0.443005,100.2], // same price, NOT allowed
],
-
Avoid zero or negative prices and sizes.
-
Keep bids below asks. Bebop ignores pairs where bid ≥ ask until the spread is valid.
-
Bebop ignores pairs with spreads wider than 1000 bps until the spread tightens.
To skip a direction for a pair, send empty bids or asks as an empty array.
Message handling
When Bebop receives a valid pricing update, it sends a success message. Parsing or validation errors come back as error messages.
Success message (JSON)
Error message (JSON)
{
"chain_id": 1,
"msg_topic": "pricing",
"msg_type": "success",
"msg": {
"code": 10,
"text": "Message processed successfully",
"reason": ""
}
}
{
"chain_id": 1,
"msg_topic": "pricing",
"msg_type": "error",
"msg": {
"code": 1,
"text": "Unparsable message",
"reason": "Price or size from levels is zero or negative"
}
}
A non-Protobuf message on the Protobuf endpoint closes the WebSocket connection.
Sending pricing updates as Protobufs
Pricing updates must use Protobuf. JSON pricing is deprecated. See Connection › Endpoints for the pricing endpoint URL.
Schema
syntax = "proto3";
package bebop;
message LevelInfo {
bytes base_address = 1;
uint32 base_decimals = 2;
bytes quote_address = 3;
uint32 quote_decimals = 4;
repeated double bids = 5 [packed=true]; // [price, amount, price, amount, ...]
repeated double asks = 6 [packed=true]; // [price, amount, price, amount, ...]
}
message LevelMsg {
repeated LevelInfo levels = 1;
bytes maker_address = 2;
}
message LevelsSchema {
uint32 chain_id = 1;
string msg_topic = 2; // pricing
string msg_type = 3; // update
LevelMsg msg = 4;
}
syntax = "proto3";
package bebop;
message WebSocketMsg {
int32 code = 1;
string text = 2;
optional string reason = 3; // used for error messages
}
message WebSocketResponse {
uint32 chain_id = 1;
string msg_topic = 2;
string msg_type = 3;
WebSocketMsg msg = 4;
}
{
"chain_id": 137,
"msg_topic": "pricing",
"msg_type": "update",
"msg": {
"maker_address": "0xB9383B9c78d0D6319B1eF2cf41A3A65c5c484DA6",
"levels": [
{
"base_address": "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270", // WPOL
"base_decimals": 18,
"quote_address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", // USDC
"quote_decimals": 6,
"bids": [
[0.4430050467,100.0834049164], // price, amount
[0.4204167736282,100.29191720740000004]
],
"asks": [
[0.5537595439,100.0834049164], // price, amount
[0.5763478169713,100.29191720740000004]
]
},
{
"base_address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", // USDT
"base_decimals": 6,
"quote_address": "0x2791bca1f2de4661ed88a30c99a7a9449aa84174", // USDC
"quote_decimals": 6,
"bids": [
[1.002,1000000.23], // price, amount
[1.001,1000000.56]
],
"asks": [
[1.0003,10000000.23], // price, amount
[1.0004,10000000.12]
]
}
]
}
}
Parsing incoming messages
Generate Protobuf classes from the two schemas above using protoc. See protobuf.dev/installation if you’re new to Protobuf.
Then parse incoming WebSocket messages with the generated classes:
raw_message: bytes = await websocket.recv()
protobuf_msg: WebSocketResponse = websocket_response_pb2.WebSocketResponse.FromString(raw_message)