API Reference

WebSocket

Connecting

Open a WebSocket to /v1/ws/market or /v1/ws/user. The first message you send picks the channel.

  • Subscribe within 10 seconds of connecting, or the connection is closed.
  • Send the text frame PING to keep the connection open. The server answers PONG. The server does not send pings of its own.
  • A connection that sends nothing for 60 seconds is closed, so ping more often than that.
  • Inbound messages are limited to 64 KiB.
  • Like the book endpoints, the connection is refused with 503 while order books are loading. Retry shortly.

Market Channel

The market channel is public. Subscribe with the token IDs you want to follow:

{ "type": "market", "assetsIds": ["<tokenId>", "<tokenId>"] }

Add or remove tokens on the same connection:

{ "operation": "subscribe",   "assetsIds": ["<tokenId>"] }
{ "operation": "unsubscribe", "assetsIds": ["<tokenId>"] }
  • A connection can follow up to 500 tokens.
  • The key is assetsIds, in camelCase.
  • Unknown token IDs are ignored without an error.

Market Events

Every message has an eventType and a timestamp in Unix milliseconds as a string.

book is sent once per token right after you subscribe. It is a full snapshot, merged with the other outcome the same way as GET /book. Bids are in ascending price order and asks in descending order, so the best price is last.

{
  "eventType": "book",
  "market": "0x<conditionId>",
  "assetId": "<tokenId>",
  "timestamp": "1760000000000",
  "hash": "<sha1 hex>",
  "bids": [ { "price": "0.47", "size": "50" }, { "price": "0.48", "size": "120" } ],
  "asks": [ { "price": "0.53", "size": "30" }, { "price": "0.52", "size": "80" } ]
}

price_change is sent about every 100 milliseconds while a followed book changes. Each entry gives the new size at a price level. A size of "0" means the level was removed.

{
  "eventType": "price_change",
  "market": "0x<conditionId>",
  "priceChanges": [
    {
      "assetId": "<tokenId>",
      "price": "0.48",
      "size": "0",
      "side": "BUY",
      "hash": "<sha1 hex>",
      "bestBid": "0.47",
      "bestAsk": "0.52"
    }
  ],
  "timestamp": "1760000000100"
}

last_trade_price is sent as soon as a trade is matched, before it settles on-chain, for both tokens of the market. transactionHash is empty in this event.

{
  "eventType": "last_trade_price",
  "market": "0x<conditionId>",
  "assetId": "<tokenId>",
  "price": "0.48",
  "side": "BUY",
  "size": "40",
  "feeRateBps": "0",
  "timestamp": "1760000000200",
  "transactionHash": ""
}

User Channel

The user channel streams events for orders placed with one API key. Authenticate with the key credentials in the subscribe message:

{
  "type": "user",
  "auth": { "apiKey": "<apiKey>", "secret": "<secret>", "passphrase": "<passphrase>" },
  "markets": ["0x<conditionId>"]
}
  • Send secret and passphrase exactly as issued. No request signature is used here.
  • An empty markets array follows every market. Sending the message again replaces the market list.
  • One connection follows one API key. The number of user connections per key is limited, so keep one connection per key.
  • Only orders placed with this key produce events. Orders placed with the wallet's other keys do not.

User Events

order events carry the same fields as the REST order object, plus type:

  • PLACEMENT when the order enters the book, with status LIVE.
  • CANCELLATION when the order is canceled or expires, with status CANCELED or EXPIRED.
{ "eventType": "order", "type": "PLACEMENT", "timestamp": "1760000000000", "id": "0x...", "status": "LIVE", ... }

trade events carry the REST trade fields from your side, with type set to TRADE and a bare status:

  • MATCHED when the trade is matched.
  • CONFIRMED when settlement is confirmed, with transactionHash.
  • FAILED when settlement fails.
{ "eventType": "trade", "type": "TRADE", "status": "MATCHED", "timestamp": "1760000000200", "id": "<trade ID>", ... }
There is no fill event on orders; follow fills through trade events. Orders closed by on-chain events, such as a nonce increase or market resolution, do not produce a CANCELLATION event. Use GET /data/order/{id} to confirm the final status.

Errors and Closing

  • Errors use the REST envelope, for example {"payload":null,"error":{"code":4001,"message":"malformed message: ..."}}. After an invalid message the connection stays open.
  • Failed authentication replies with code 4002 and invalid API key or signature, then closes the connection.
  • If the key is revoked, the connection receives an error within about 10 seconds and is closed.
  • After any disconnect, reconnect, subscribe again, and reload your open orders and recent trades over REST before you trust the stream.
  • A client that reads too slowly to keep up is disconnected.
  • Server-initiated closes use close code 1008 with a reason string.