Websocket API

This API is currently in an invite-only beta testing phase. Please inquire here if you are interested in obtaining access.


The following documentation covers the Cryptowatch Websocket API for both streaming and trading. You can use this document to build your own client, or use one of our official SDKs.

We recommend using one of the SDKs since they properly handle authentication, connection logic, and provide many useful abstractions from our messaging layer. We have libraries written for Golang and Node.js:

The API consists of two separate back end services which both share the same connection and authentication logic. You can use one API key pair for both streaming and trading. However, during the beta testing period, you will have to explicitly be given access to these features.


All messages sent over the Websocket API are encoded using Protocol Buffers. Our protobuf definitions are publicly available here:

Strings Vs Floats

All price, ID, and subscription data are represented as strings. This is to prevent loss of significant digits from using float, as well as to provide a consistent and simple API.

Deprecation Warning

Most protobuf message fields that use float are deprecated in favor of a string replacement. It is recommended you use the latest version of our client libraries which properly handle this deprecation.


Connect to the streaming and trading services at the following urls.



Each connection to the Websocket API must be authenticated with an API key and secret key. After establishing a connection, the client sends an APIAuthenticationMessage containing their public key, a nonce, and a token which is an HMAC-SHA-512 created with the corresponding secret key. An example implementation of generating the token in Go can be found here.


Subscriptions (ClientSubscription) are the primary contract between the client and websocket server, and determine what you are streaming or trading. For streaming, subscriptions are data resources that receive live updates. For trading, subscriptions correspond with trading sessions for individual markets.

A ClientSubscription is always followed by a SubscriptionResult, which contains a list of the successful subscriptions, as well as any failed subscriptions if applicable. Similarly, unsubscribing (ClientUnsubscribeMessage) is always followed by a UnsubscriptionResult. When a subscription fails, it usually means the client does not have access, or the subscription key is invalid.


To stream data, clients should connect to wss://stream.cryptowat.ch and provide a list of ClientSubscriptions (StreamSubscription) as part of the as part of the APIAuthenticationMessage. The client will receive live updates for each subscription until it unsubscribes or the connection is closed.

The client can subscribe and unsubscribe to feeds dynamically with ClientSubscribeMessage and ClientUnsubscribeMessage respectively.

a StreamSubscription contains one property resource, which is a string formatted as a colon-separated scope, ID, and subject. For example, the resource exchanges:4:trades is a feed of all trades in the scope exchanges where the ID is 4 (Kraken) and the subject is trades. A client that subscribes to exchanges:4:trades will receive all trade updates for the Kraken exchange.

The following table shows the available subscription prefixes, and where to find the resource IDs using the REST API.

Example PrefixDescriptionResource IDs Endpoint
markets:86Market 86 (Kraken BTC/EUR)api.cryptowat.ch/markets
exchanges:4All markets for exchange 4 (Kraken)api.cryptowat.ch/exchanges
pairs:232All markets for pair 232 (BTC/EUR)api.cryptowat.ch/pairs
assets:60All markets for asset 60 (BTC)api.cryptowat.ch/assets

Public Trades

TradesUpdate is sent for every trade on a given market.

markets:68:tradesA feed of trades for a single marketreal-time
markets:*:tradesA feed of trades for all marketsreal-time
exchanges:4:tradesA feed of all trades on a given exchangereal-time
pairs:232:tradesA feed of all trades for a given pairreal-time
assets:60:tradesA feed of all trades for a given assetreal-time

See our example code for consuming trade feeds:

24-Hour Market Summary

A SummaryUpdate includes last price, high, low, # trades, volume (base and quote), and price change (percentage and absolute).

markets:68:summaryMarket summary updates for market 68real-time
markets:*:summaryMarket summary updates for all marketsreal-time
markets:*:summary-low-volumeMarket summary updates for all markets (throttled)2m
exchanges:4:summaryMarket summary updates for all markets in exchange 4real-time
pairs:232:summaryMarket summary updates for all markets with pair 232real-time
assets:60:summaryMarket summary updates for all markets with asset 60real-time

Candlestick Data (OHLC)

An OHLC subscription receives IntervalsUpdate, which contains the latest candlestick data for each interval period. See REST API OHLC data for a reference on interval periods.

markets:68:ohlcOHLC updates for market 68real-time
markets:*:ohlcOHLC updates for all marketsreal-time
exchanges:4:ohlcOHLC updates for all markets in exchange 4real-time
pairs:232:ohlcOHLC updates for all markets with pair 232real-time
assets:60:ohlcOHLC updates for all markets with asset 60real-time

Order Books

Order book data is separated into three streams for snapshots, deltas, and spread. Order book snapshots are broadcast once per minute, while the deltas are real-time. To maintain a real-time order book, apply deltas to the most recent snapshot. Both deltas and snapshots contain a sequence number, so you can determine if the data is recieved in the correct order.


OrderBookUpdate contains a snapshot of the order book to the highest degree of accuracy available from the exchange.

markets:68:book:snapshotsOrder book snapshots for market 681m
exchanges:4:book:snapshotsOrder book snapshots for all markets in exchange 41m
pairs:232:book:snapshotsOrder book snapshots for all markets with pair 2321m
assets:60:book:snapshotsOrder book snapshots for all markets with asset 601m


OrderBookDeltaUpdate is sent in real-time as updates to the order book occur. These deltas are meant to be applied to a snapshot to keep a real-time order book.

markets:68:book:deltasOrder book delta updates for market 68real-time
exchanges:4:book:deltasOrder book delta updates for all markets in exchange 4real-time
pairs:9:book:deltasOrder book delta updates for all markets with pair 9real-time
assets:60:book:deltasOrder book delta updates for all markets with asset 60real-time


OrderBookSpreadUpdate is sent when the order book spread (best bid & ask) changes.

markets:68:book:spreadOrder book spread updates for a given marketreal-time
markets:*:book:spreadOrder book spread updates for all marketsreal-time
exchanges:4:book:spreadOrder book spread updates for a given exchangereal-time
pairs:232:book:spreadOrder book spread updates for a given pairreal-time
assets:60:book:spreadOrder book spread updates for a given assetreal-time


To trade over the Websocket API, connect to wss://trading.service.cryptowat.ch and provide a list of ClientSubscriptions (TradeSubscription) for each market to trade on as part of the in the APIAuthenticationMessage.

You can find the market IDs you need using our REST API: https://api.cryptowat.ch/markets.

For each subscription, you can optionally provide TradeSessionAuth which enables you to provide exchange API keys. If left out, the exchange API keys loaded in your Cryptowatch account will be used.

Once authenticated, the trading back end will send a SessionStatusUpdate where initialized is true for each of the subscribed markets, after which point the client can place and cancel orders on the initialized markets. The client will also receive live updates for orders, trades, balances, and positions.

Session Updates

The trading back end keeps track of the following trading properties for each of the subscribed markets, and sends updates as they occur.


OrdersUpdate is sent for each new order and any subsequent change to that order. For example, if an order is partially filled, a new OrdersUpdate will be sent. OrdersUpdate always contains all active orders for the given market.


Initially, the last 1000 trades for the subscribed market are sent to the client in a TradesUpdate. Then any subsequent trade updates are sent in the same manner. The clients will maintain a cache of 1000 trades per market, removing the oldest as new updates occur.


BalancesUpdate contains a list of balances for each funding type (spot or margin) available to you on the exchange. is sent every time one of your balances changes on an exchange where you are subscribed to one of its markets.


PositionsUpdate is sent whenever your positions update on an exchange where you have a subscribed market. A position consists of a list of orders and trades, average price, amount open and closed, and the order side.

Placing Orders

Once a market trading session is initialized (indicated by SessionStatusUpdate), the client can place orders by sending PlaceOrderRequest, which contains a PrivateOrder. Some exchanges support a conditional close as well, which can be provided with the closingOrder field.

After an order has been placed, a RequestResolutionUpdate will be sent to the client containing the resulting PrivateOrder, as well as an error code. If the error code is 0, the order was placed successfully.

Any updates to your orders will be sent with OrdersUpdate.

Cancelling Orders

The client can cancel orders by sending a CancelOrderRequest with the order ID to cancel. Similar to PlaceOrderRequest, a RequestResolutionUpdate will also be received to confirm the order was cancelled. To verify a cancelled order, it is sufficient to simply check if the error code is 0.


Sending a SyncRequest forces an update by polling the exchange on behalf of the user. This is done automatically by the client libraries upon initialization.

Sync should not normally be called explicitly; it is only useful in two scenarios:

  • an order is placed or cancelled outside of this client
  • there is something preventing our trading back end from actively polling for updates. This happens rarely, and for various reasons. For example, an exchange may rate limit one of our servers.