Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bullet Trading API WebSocket Specification

WebSocket endpoint: ws://<host>:<port>/ws

  • Localnet: ws://localhost:3000/ws
  • Staging: wss://tradingapi.staging.bullet.xyz/ws
  • Testnet: wss://tradingapi.testnet.bullet.xyz/ws
  • Mainnet: wss://tradingapi.bullet.xyz/ws

Connection Lifecycle

WebSocket connections go through three phases: establishment, keepalive, and disconnection. The server uses status messages to inform clients of connection state changes (e.g., successful connection, impending disconnection with reason).

Status Message

FieldTypeDescriptionBinance Equivalent
estring"status"- (no equivalent)
Eu64event time (μs)-
statusstring"connected" or "disconnecting"-
clientIdstringUUID client identifier-
reasonstring?disconnect reason (only for disconnecting)-

Connection Establishment

  1. Client connects to WebSocket endpoint
  2. Server assigns unique clientId
  3. Server sends "connected" status message
{
  "e": "status",
  "E": 1706745600000000,
  "status": "connected",
  "clientId": "ws_abc123"
}

Disconnection

The server sends a "disconnecting" status message before closing:

{
  "e": "status",
  "E": 1706745600000000,
  "status": "disconnecting",
  "clientId": "ws_abc123",
  "reason": "pong_timeout"
}

Disconnect Reasons

ReasonDefaultDescription
idle_timeout60sno valid message within timeout
pong_timeout60sclient didn’t respond to ping
max_duration24hconnection exceeded max lifetime

Keepalive (Ping/Pong)

Connections are kept alive via WebSocket ping/pong frames. The server sends ping frames every 30 seconds; clients must respond with pong frames. WebSocket ping frames reset the keepalive timeout.

Ping

Ping the server to check connection health. Alternatively clients can also send WebSocket ping frames.

{
  "method": "ping",
  "id": 4
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"ping" or "PING"(WebSocket ping frame)
idu64norequest correlation id-

Possible errors: ValidationError (message parse)

Responses: Pong

Pong

{
  "e": "pong",
  "id": 4,
  "E": 1706745600000000
}
FieldTypeDescriptionBinance Equivalent
estring"pong"(WebSocket pong frame)
idu64?echoed request id-
Eu64event time (μs)-

Subscription Streams

All client messages use JSON format with method field. Method names are case-insensitive.

Subscribe

Subscribe to market data topics or user data streams.

{
  "method": "subscribe",
  "id": 1,
  "params": [
    "BTC-USD@aggTrade",
    "ETH-USD@depth10"
  ]
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"subscribe" or "SUBSCRIBE"method: "SUBSCRIBE"
paramsstring[]yesarray of topic stringsparams
idu64norequest correlation idid

Behavior: Idempotent with atomic validation. All topics validated first - if any fails, entire request fails. Already-subscribed topics silently skipped.

Possible errors: ValidationError, TooManyRequests, InvalidSubscriptionFormat, Unauthorized, InvalidSymbol, ClientNotFound

Responses:

Subscribe (success)

{
  "e": "subscribe",
  "id": 1,
  "E": 1706745600000000,
  "result": "success"
}
FieldTypeDescriptionBinance Equivalent
estring"subscribe"- (Binance uses result: null)
idu64?echoed request idid
Eu64event time (μs)-
resultstring"success"result: null

Unsubscribe

Unsubscribe from market data topics or user data streams.

{
  "method": "unsubscribe",
  "id": 5,
  "params": [
    "BTC-USD@aggTrade"
  ]
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"unsubscribe" or "UNSUBSCRIBE"method: "UNSUBSCRIBE"
paramsstring[]yestopics to unsubscribeparams
idu64norequest correlation idid

Behavior: Idempotent - always succeeds. Invalid or non-subscribed topics silently skipped.

Possible errors: ValidationError (message parse)

Responses:

Unsubscribe (success)

{
  "e": "unsubscribe",
  "id": 5,
  "E": 1706745600000000,
  "result": "success"
}
FieldTypeDescriptionBinance Equivalent
estring"unsubscribe"- (Binance uses result: null)
idu64?echoed request idid
Eu64event time (μs)-
resultstring"success"result: null

ListSubscriptions

List all active subscriptions for the client.

{
  "method": "list_subscriptions",
  "id": 6
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"list_subscriptions" or "LIST_SUBSCRIPTIONS"method: "LIST_SUBSCRIPTIONS"
idu64norequest correlation idid

Possible errors: ValidationError (message parse)

Responses:

ListSubscriptions (success)

{
  "e": "list_subscriptions",
  "id": 6,
  "E": 1706745600000000,
  "result": [
    "BTC-USD@depth10",
    "ETH-USD@aggTrade"
  ]
}
FieldTypeDescriptionBinance Equivalent
estring"list_subscriptions"-
idu64?echoed request idid
Eu64event time (μs)-
resultstring[]subscribed topicsresult: […]

Request-Response

OrderPlace

Place an order via WebSocket.

{
  "method": "order.place",
  "id": 10,
  "params": {
    "tx": "c2lnbmVkX3RyYW5zYWN0aW9uX2J5dGVz"
  }
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"order.place" or "ORDER.PLACE"method: "order.place"
params.txstringyessigned base64-encoded borsh transaction bytes(different: REST params)
idu64norequest correlation idid

Possible errors: ValidationError (empty tx), ServiceUnavailable (submission failed), Timeout, NewOrderRejected

Responses:


OrderCancel

Cancel an order via WebSocket.

{
  "method": "order.cancel",
  "id": 11,
  "params": {
    "tx": "c2lnbmVkX3RyYW5zYWN0aW9uX2J5dGVz"
  }
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"order.cancel" or "ORDER.CANCEL"method: "order.cancel"
params.txstringyessigned base64-encoded borsh transaction bytes(different: orderId/clientOrderId)
idu64norequest correlation idid

Possible errors: ValidationError (empty tx), ServiceUnavailable (submission failed), Timeout, CancelRejected

Responses:


OrderAmend

Amend an existing order via WebSocket.

{
  "method": "order.amend",
  "params": {
    "tx": "<signed-base64-borsh-tx>"
  },
  "id": 7
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"order.amend", "order.modify", or "ORDER.AMEND"-
params.txstringyessigned base64-encoded borsh transaction bytes-
idu64norequest correlation idid

Possible errors: ValidationError (empty tx), ServiceUnavailable (submission failed), Timeout, CancelRejected

Responses:


OrderCancelAll

Cancel all open orders for a market via WebSocket.

{
  "method": "order.cancelAll",
  "params": {
    "tx": "<signed-base64-borsh-tx>"
  },
  "id": 8
}
FieldTypeRequiredDescriptionBinance Equivalent
methodstringyes"order.cancelAll" or "ORDER.CANCEL_ALL"-
params.txstringyessigned base64-encoded borsh transaction bytes-
idu64norequest correlation idid

Possible errors: ValidationError (empty tx), ServiceUnavailable (submission failed), Timeout, CancelRejected

Responses:


Error

Error response to any client request.

{
  "e": "error",
  "id": 2,
  "E": 1706745600000000,
  "error": {
    "param": "invalid-topic-format",
    "code": -1004,
    "msg": "invalid subscription format: expected <symbol>@<stream>"
  }
}
FieldTypeDescriptionBinance Equivalent
estring"error"-
idu64?echoed request idid
Eu64event time (μs)-
error.codei32error codeerror.code
error.msgstringerror messageerror.msg
error.paramstring?parameter that caused error- (Bullet-specific)

OrderResult

Response to OrderPlace, OrderCancel, OrderAmend, or OrderCancelAll.

{
  "e": "order.place",
  "id": 10,
  "E": 1706745600000000,
  "results": {
    "tx_id": "0xabc123def456",
    "status": "processed",
    "order_ids": [
      1
    ],
    "client_order_ids": [
      1
    ]
  }
}
FieldTypeDescriptionBinance Equivalent
estring"order.place", "order.cancel", "order.amend", "order.cancelAll"-
idu64?echoed request idid
Eu64event time (μs)-
results.tx_idstringtransaction hash- (DEX-specific)
results.statusstringtx status ("processed", "skipped")- (DEX-specific)
results.order_idsu64[]affected order ids- (DEX-specific)
results.client_order_idsu64[]affected client order ids- (DEX-specific)

OrderError

Error response to OrderPlace, OrderCancel, OrderAmend, or OrderCancelAll.

{
  "id": 12,
  "E": 1706745600000000,
  "error": {
    "code": -2010,
    "msg": "new order rejected: insufficient margin"
  }
}
FieldTypeDescriptionBinance Equivalent
idu64?echoed request idid
Eu64event time (μs)-
error.codei32error codeerror.code
error.msgstringerror messageerror.msg

Market Data

All market data messages are pushed to subscribed clients. No type wrapper.

DepthUpdate

Topic: SYMBOL@depth, SYMBOL@depth5, SYMBOL@depth10, SYMBOL@depth20

{
  "e": "depthUpdate",
  "E": 1706745600000000,
  "T": 1706745600000000,
  "s": "BTC-USD",
  "U": 1000,
  "u": 1000,
  "pu": 0,
  "b": [
    [
      "50000.00",
      "1.5"
    ],
    [
      "49999.00",
      "2.0"
    ]
  ],
  "a": [
    [
      "50001.00",
      "1.2"
    ],
    [
      "50002.00",
      "3.0"
    ]
  ],
  "mt": "s"
}
FieldTypeDescriptionBinance Equivalent
estring"depthUpdate"e
Eu64event time (μs)E
Tu64transaction time (μs)T
sstringsymbols
Uu64first update idU
uu64last update id (always equals U)u
puu64previous update idpu
b[[price, qty], …]bids (descending)b
a[[price, qty], …]asks (ascending)a
mtstring"s" (snapshot) or "u" (update)- (Bullet-specific)

Note: U equals u and as we don’t batch updates.

AggTrade

Topic: SYMBOL@aggTrade

{
  "e": "aggTrade",
  "E": 1706745600000000,
  "s": "BTC-USD",
  "a": 200001,
  "p": "50000.50",
  "q": "0.5",
  "f": 200001,
  "l": 200001,
  "T": 1706745600000000,
  "m": false,
  "th": "0xabc123def456",
  "ua": "0xuser123",
  "oi": 100001,
  "mk": false,
  "ff": true,
  "lq": false,
  "fe": "0.025",
  "nf": "0.025",
  "fa": "USD",
  "sd": "BUY"
}
FieldTypeDescriptionBinance Equivalent
estring"aggTrade"e
Eu64event time (μs)E
sstringsymbols
au64aggregate trade ida
pstringpricep
qstringquantityq
fu64first trade idf
lu64last trade idl
Tu64trade time (μs)T
mboolis buyer makerm
thstringtransaction hash- (DEX-specific)
uastringtrader address- (DEX-specific)
oiu64order id- (DEX-specific)
mkboolis maker- (DEX-specific)
ffboolfully filled- (DEX-specific)
lqboolliquidation trade- (DEX-specific)
festringfee amount- (DEX-specific)
nfstringnet fee- (DEX-specific)
fastringfee asset- (DEX-specific)
costring?client order id- (DEX-specific)
sdstring"BUY" or "SELL"- (DEX-specific)

BookTicker

Topic: SYMBOL@bookTicker, !bookTicker

{
  "e": "bookTicker",
  "u": 1000,
  "E": 1706745600000000,
  "T": 1706745600000000,
  "s": "BTC-USD",
  "b": "50000.00",
  "B": "1.5",
  "a": "50001.00",
  "A": "1.2",
  "mt": "s"
}
FieldTypeDescriptionBinance Equivalent
estring"bookTicker"e
uu64update idu
Eu64event time (μs)E
Tu64transaction time (μs)T
sstringsymbols
bstringbest bid priceb
Bstringbest bid qtyB
astringbest ask pricea
Astringbest ask qtyA
mtstring"s" (snapshot) or "u" (update)- (Bullet-specific)

MarkPrice

Topic: SYMBOL@markPrice, !markPrice@arr

{
  "e": "markPriceUpdate",
  "E": 1706745600000000,
  "s": "BTC-USD",
  "p": "50000.50",
  "i": "50000.00",
  "r": "0.0001",
  "T": 1706774400000000
}
FieldTypeDescriptionBinance Equivalent
estring"markPriceUpdate"e
Eu64event time (μs)E
sstringsymbols
pstringmark pricep
istringindex price (median CEX price)i
Pstring?estimated settle priceP
rstringfunding rater
Tu64?next funding timeT
thstring?transaction hash- (DEX-specific)

Liquidation (ForceOrder)

Topic: SYMBOL@liquidations, SYMBOL@forceOrder, !liquidations, !forceOrder, liquidations, forceOrders

{
  "e": "liquidation",
  "E": 1706745600000000,
  "o": {
    "s": "BTC-USD",
    "S": "SELL",
    "o": "LIMIT",
    "f": "IOC",
    "p": "49000.00",
    "ap": "49000.00",
    "X": "FILLED",
    "l": "1.0",
    "T": 1706745600000000,
    "th": "0xabc123def456",
    "ua": "0xuser123",
    "oi": 100001,
    "ti": 200001
  }
}
FieldTypeDescriptionBinance Equivalent
estring"liquidation"e ("forceOrder")
Eu64event time (μs)E
o.sstringsymbolo.s
o.Sstringside ("BUY" or "SELL")o.S
o.ostringorder type ("LIMIT")o.o
o.fstringtime in force ("IOC")o.f
o.qstring?original quantityo.q
o.zstring?filled quantityo.z
o.pstringpriceo.p
o.apstringaverage priceo.ap
o.Xstringstatus ("FILLED")o.X
o.lstringlast filled qtyo.l
o.Tu64trade time (μs)o.T
o.thstringtransaction hash- (DEX-specific)
o.uastringliquidated address- (DEX-specific)
o.oiu64order id- (DEX-specific)
o.tiu64trade id- (DEX-specific)

OrderUpdate

Topic: [email protected], ADDRESS@ORDER_TRADE_UPDATE

Published for order lifecycle events (NEW, TRADE, CANCELED).

{
  "e": "orderTradeUpdate",
  "E": 1706745600000000,
  "o": {
    "s": "BTC-USD",
    "i": 100001,
    "X": "NEW",
    "x": "NEW",
    "T": 1706745600000000,
    "th": "0xabc123def456",
    "ua": "0xuser123",
    "S": "BUY",
    "o": "LIMIT",
    "f": "GTC",
    "p": "50000.00",
    "q": "1.0"
  }
}

Common fields (all events):

FieldTypeDescriptionBinance Equivalent
estring"orderTradeUpdate"e ("ORDER_TRADE_UPDATE")
Eu64event time (μs)E
o.sstringsymbolo.s
o.iu64order ido.i
o.Xstringorder statuso.X
o.xstringexecution typeo.x
o.Tu64transaction time (μs)o.T
o.thstringtransaction hash- (DEX-specific)
o.uastringuser address- (DEX-specific)

NEW order additional fields:

FieldTypeDescriptionBinance Equivalent
o.Sstringsideo.S
o.ostringorder typeo.o
o.fstringtime in forceo.f
o.pstringpriceo.p
o.qstringquantityo.q

TRADE fill additional fields:

FieldTypeDescriptionBinance Equivalent
o.Sstringsideo.S
o.lstringlast filled qtyo.l
o.Lstringlast filled priceo.L
o.nstringcommissiono.n

Topics

Symbol-Based Topics

Bullet TopicAliasesBinance EquivalentDescription
SYMBOL@depthsymbol@depthorderbook (default 10)
SYMBOL@depth5symbol@depth5orderbook 5 levels
SYMBOL@depth10symbol@depth10orderbook 10 levels
SYMBOL@depth20symbol@depth20orderbook 20 levels
SYMBOL@aggTradesymbol@aggTradetrades
SYMBOL@bookTickersymbol@bookTickerbest bid/offer
SYMBOL@markPricesymbol@markPricemark price + funding
SYMBOL@tickersymbol@ticker24hr ticker
SYMBOL@liquidationsSYMBOL@forceOrdersymbol@forceOrderliquidations
SYMBOL@kline_INTERVALsymbol@kline_INTERVALcandlesticks (coming soon)

Symbol format: Bullet uses BTC-USD (hyphen), Binance uses btcusdt (lowercase, no separator)

Kline intervals: 1m, 5m, 15m, 30m, 1h, 4h, 1d (coming soon)

Parse errors: InvalidFormat, MissingSymbol, InvalidDepth, InvalidInterval, UnknownTopic Resolution errors: SymbolNotFound

Broadcast Topics

Bullet TopicAliasesBinance Equivalent
tickers!ticker@arr, !ticker!ticker@arr
markPrices!markPrice@arr, !markPrice!markPrice@arr
bookTickers!bookTicker, !bookTicker@arr!bookTicker
liquidations!liquidations, !forceOrder, forceOrders!forceOrder@arr

Parse errors: InvalidFormat, UnknownTopic

User Data Topics

Bullet TopicAliasesBinance Equivalent
[email protected]ADDRESS@ORDER_TRADE_UPDATElistenKey stream

Key difference: Bullet uses address-prefixed topics directly. Binance requires a listenKey from REST API.

Resolution errors: MissingUserAddress (when address not provided)

Speed Suffixes

Speed suffixes are accepted but ignored: @100ms, @500ms, @1s

Example: BTC-USD@depth@100ms is equivalent to BTC-USD@depth


Error Codes

General

CodeNameDescriptionBinance Code
-1000Unknownunknown error-1000
-1001Disconnectedserver busy/disconnected-1001
-1002Unauthorizedauthentication required-1002
-1003TooManyRequestsrate limit exceeded-1003
-1006UnexpectedResponseunexpected response-1006
-1007Timeoutrequest timeout-1007
-1014UnknownOrderorder not found-1014
-1015TooManyOrdersorder rate limit-1015
-1016ServiceUnavailableservice down-1016
-1020UnsupportedOperationoperation not supported-1020
-1021InvalidTimestampbad timestamp-1021
-1022InvalidSignaturesignature invalid-1022

Parameters

CodeNameDescriptionBinance Code
-1102MandatoryParamMissingrequired param missing-1102
-1111BadPrecisionprecision error-1111
-1116InvalidOrderTypebad order type-1116
-1117InvalidSidebad side-1117
-1122InvalidSymbolinvalid symbol-1122
-1123InvalidUserAddressinvalid address- (Bullet-specific)

Subscriptions

CodeNameDescriptionBinance Code
-1004InvalidSubscriptionFormatbad topic format- (Bullet-specific)
-1005SymbolNotFoundsymbol not found- (Bullet-specific)
-1008ValidationErrorvalidation failed- (Bullet-specific)
-1010SubscriptionExistsalready subscribed- (Bullet-specific)

Orders

CodeNameDescriptionBinance Code
-2010NewOrderRejectedorder rejected-2010
-2011CancelRejectedcancel failed-2011
-2013NoSuchOrderorder doesn’t exist-2013
-2014ApiKeyFormatInvalidbad api key-2014
-2015InvalidApiKeyIpPermissionsauth failure-2015
-2021OrderWouldTriggerwould trigger immediately-2021

Internal

CodeNameDescriptionBinance Code
-4001ClientNotFoundclient not found- (internal)
-4002CouldNotSendMessagecould not send message- (internal)

Notes

DEX-Specific Fields

DEX-specific fields use 2-letter codes for compactness:

CodeFull NameDescription
thtx_hashon-chain transaction hash
uauser_addressuser’s wallet address
oiorder_idsequencer order ID
titrade_idsequencer trade ID
mkis_makerwhether the trade was a maker
ffis_full_fillfully filled indicator
lqis_liquidationliquidation trade indicator
fefeefee amount
nfnet_feenet fee after rebates
fafee_assetfee asset symbol
sdsidetrade side (BUY/SELL)
coclient_order_idclient-provided order ID

Message Type Field

The mt field in orderbook and BBO messages indicates:

  • "s" - snapshot (complete state at that depth level)
  • "u" - update (incremental changes since last update)

Response Format Differences

  • All responses use e field for event type (e.g., "e":"subscribe", "e":"error")
  • Order responses still use Binance-style format with status code
  • Market data messages use e field for event type (e.g., "e":"depthUpdate")