Skip to content

WebSockets⚓︎

NEM publishes blockchain events over WebSockets, so applications can receive live updates without constantly polling the REST API.

Client applications open a WebSocket connection to any node in the network and subscribe to the channels they want to monitor. When an event occurs on a channel, the node notifies every subscribed client in real time.

Some channels also accept requests for immediate data, similar to the REST API. This can simplify applications that use WebSockets as their only API for both live notifications and on-demand updates.

Connection⚓︎

NEM serves WebSockets using the STOMP messaging protocol over SockJS, on a dedicated port (7778 by default) separate from the HTTP API port.

The SockJS endpoint is /w/messages, for example http://localhost:7778/w/messages.

Clients typically connect using either a SockJS client library or the native WebSocket API, together with a STOMP client library to handle messaging.

Connecting using native WebSockets

SockJS provides a WebSocket-like transport with cross-browser support and HTTP-based fallback options when native WebSockets are unavailable.

Clients with native WebSocket support can connect directly to the SockJS WebSocket transport endpoint at /w/messages/websocket, for example: ws://localhost:7778/w/messages/websocket.

This uses the WebSocket transport of SockJS without requiring the SockJS client library, while still relying on the SockJS server.

STOMP Session⚓︎

STOMP Session
A client-node conversation over a WebSocket connection, following the STOMP messaging protocol.

A client controls the session by exchanging STOMP Frames with the node:

  1. Send a CONNECT frame to start the STOMP session.
  2. Send a SUBSCRIBE frame for each channel to monitor. Each subscription requires a client-defined id.
  3. Send an optional registration request with a SEND frame to enable notifications for channels that require explicit registration.
  4. Receive a MESSAGE frame from the node for every event on a subscribed channel.
  5. Send an UNSUBSCRIBE frame for each subscribed channel to stop receiving its notifications.
  6. Send a DISCONNECT frame to end the session.

Connections can drop silently

The WebSocket connection can drop without notice, for example after being idle for too long. Most STOMP clients report this through a connection-closed callback, which is a good place to reconnect.

Reconnection starts a fresh session, so every channel must be subscribed again.

STOMP Frames⚓︎

STOMP Frame
A plain-text message adhering to the STOMP protocol, made of a command, optional header:value lines, and an optional body.

The client and node exchange the following frame types.

CONNECT⚓︎

Starts the STOMP session. The client must send this frame once, right after the connection opens. See the STOMP specification for full details.

Example
CONNECT
accept-version:1.2
heart-beat:0,0

SUBSCRIBE⚓︎

Subscribes to a channel, with a client-chosen id and destination. See the STOMP specification for full details.

Example
SUBSCRIBE
id:sub-0
destination:/blocks
  • id is unique only within a single connection (other clients can reuse the same value). It is echoed back as the subscription header on every message and used to UNSUBSCRIBE later.
  • destination identifies the channel, so the same connection can monitor multiple channels.

MESSAGE⚓︎

Delivers channel data from the node. It is the only frame type the node sends. See the STOMP specification for full details.

Example
MESSAGE
destination:/blocks
subscription:sub-0
message-id:befkedjj-6247

{ ... }
  • destination matches the channel from the SUBSCRIBE frame.
  • subscription matches the id from the SUBSCRIBE frame.
  • message-id is a unique identifier the server assigns to each message.
  • { ... } is the body, a JSON object whose shape depends on the channel. See the Message body tabs below.

SEND⚓︎

Sends a request to a /w/api destination. See the STOMP specification for full details.

Example
SEND
destination:/w/api/account/subscribe

{ "account": "{address}" }

UNSUBSCRIBE⚓︎

Cancels a subscription by its id. See the STOMP specification for full details.

Example
UNSUBSCRIBE
id:sub-0

DISCONNECT⚓︎

Ends the session. See the STOMP specification for full details.

Example
DISCONNECT

Channels⚓︎

WebSocket Channel
Node notifications are grouped into channels. Clients subscribe to each channel whose notifications they want to receive.

Every channel is subscribed to with a SUBSCRIBE frame.

The available channels are grouped here by the type of event they report.

Block Channels⚓︎

These channels report new blocks as they are added to the chain.

/blocks⚓︎

blocks

Notifies subscribed clients each time a new block is added to the chain.

If multiple blocks are added at once, for example while the node catches up with its peers or after a rollback, the channel sends a burst: one notification per block, delivered in quick succession and in chain order.

After a rollback, a notification can report a lower block height than a previously received notification because the new blocks replace blocks that were already reported.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/blocks
MESSAGE
destination:/blocks
subscription:sub-0
message-id:...

{ ... }
Followed by a Block JSON body.

/blocks/new⚓︎

blocks/new

Notifies subscribed clients each time the chain changes, with one notification per chain update that contains the height of the first block added or replaced.

Unlike blocks WS, this channel sends a single notification for each chain update, regardless of how many blocks it contains. For example, if five blocks are added at once, blocks WS sends five notifications while this channel sends only one, containing the height of the first block.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/blocks/new
MESSAGE
destination:/blocks/new
subscription:sub-0
message-id:...

{ "height": 1234567 }

Transaction Channels⚓︎

These channels report transaction activity, regardless of the accounts involved.

/unconfirmed⚓︎

unconfirmed

Notifies subscribed clients every time a transaction enters the unconfirmed pool, regardless of the accounts involved.

Every transaction type appears here, including cosignatures, which are not reported on any of the account channels. A multisig transaction appears as the outer multisig transaction, with the inner transaction nested inside.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/unconfirmed
MESSAGE
destination:/unconfirmed
subscription:sub-0
message-id:...

{ ... }
Followed by a Transaction JSON body.

Account Channels⚓︎

These channels report activity for a specific account, such as its balance, transactions, and the mosaics and namespaces it owns.

Address format

Wherever an address appears, either in a channel destination or a request body, it uses the encoded address format: uppercase letters and digits, without hyphens.

Example: TBULEAUG2CZQISUR442HWA6UAKGWIXHDABJVIPS4.

Account channels send a notification whenever the account is involved in a transaction, even if the account state does not change.

The accounts considered involved depend on the transaction type:

Transaction type Involved accounts
Transfer The signer and the recipient.
Importance transfer The signer and the remote account.
Multisig aggregate modification The signer and every cosignatory added or removed.
Provision namespace The signer.
Mosaic definition creation The signer, plus the levy recipient if the definition includes a levy.
Mosaic supply change The signer, plus the levy recipient if the mosaic definition includes a levy.
Multisig The initiating cosignatory, the multisig account, and others in the inner transaction.

Multisig transactions

An account that has multiple roles, for example the initiating cosignatory and the recipient of the inner transfer, receives one notification for each role.

When a multisig transaction requires multiple signatures, each additional cosignatory approves it by submitting a separate cosignature transaction. Cosignatures appear only on the global unconfirmed WS channel. They never reach account channels, not even the multisig account's or the submitting cosignatory's.

/account/{address}⚓︎

account/{address}

Notifies subscribed clients of the account's current state every time a confirmed block involves the address, either through a transaction it is involved in or by harvesting the block. Requires the address to be registered first.

Involvement in a transaction does not mean that the account changed. For example, the recipient of a transfer of zero XEM is notified even though its balance stays the same.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/account/{address}
MESSAGE
destination:/account/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by an AccountMetaDataPair JSON body.

/unconfirmed/{address}⚓︎

unconfirmed/{address}

Notifies subscribed clients every time a transaction involving the account enters the unconfirmed pool. Requires the address to be registered first.

Since the transaction is not yet included in a block, the meta.height field contains the placeholder value 9007199254740991, the largest integer that JSON parsers can represent safely.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/unconfirmed/{address}
MESSAGE
destination:/unconfirmed/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a TransactionMetaDataPair JSON body.

/transactions/{address}⚓︎

transactions/{address}
Notifies subscribed clients every time a confirmed block includes a transaction involving the account. Requires the address to be registered first.
Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/transactions/{address}
MESSAGE
destination:/transactions/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a TransactionMetaDataPair JSON body.

/account/mosaic/owned/{address}⚓︎

account/mosaic/owned/{address}

Notifies subscribed clients of the account's mosaics, every time a confirmed block might have changed them. The account's mosaics are the ones it holds a balance of, together with any it created.

A notification burst is sent when a block contains a mosaic-related transaction involving the account. A transfer that carries mosaics notifies the signer, the recipient, and any levy recipients. Mosaic definition creation and mosaic supply changes instead notify the mosaic's creator, plus any levy recipient.

The transaction does not need to change the account's mosaics. For example, a transfer of zero units of a mosaic still notifies both the sender and the recipient.

Each burst contains the account's full mosaic list, with one notification per mosaic, regardless of which mosaics changed.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/account/mosaic/owned/{address}
MESSAGE
destination:/account/mosaic/owned/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a Mosaic JSON body.

/account/mosaic/owned/definition/{address}⚓︎

account/mosaic/owned/definition/{address}

Notifies subscribed clients of the definitions of the account's mosaics, every time a confirmed block might have changed them.

This channel is triggered by the same transactions as  WS and covers the same mosaics. Each burst contains the account's full list of mosaic definitions, with one notification per definition, regardless of which mosaics changed.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/account/mosaic/owned/definition/{address}
MESSAGE
destination:/account/mosaic/owned/definition/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a MosaicDefinitionSupplyTuple JSON body.

/account/namespace/owned/{address}⚓︎

account/namespace/owned/{address}

Notifies subscribed clients of the namespaces the account owns, every time a confirmed block might have changed them.

A notification burst is sent when a block contains a provision namespace transaction signed by the account. Each burst contains the account's full list of owned namespaces, with one notification per namespace.

Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/account/namespace/owned/{address}
MESSAGE
destination:/account/namespace/owned/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a Namespace JSON body.

/recenttransactions/{address}⚓︎

recenttransactions/{address}
Notifies subscribed clients of the account's 25 most recent confirmed transactions, only in response to w/api/account/transfers/all REQ.
Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/recenttransactions/{address}
MESSAGE
destination:/recenttransactions/{address}
subscription:sub-0
message-id:...

{ ... }
Followed by a list of TransactionMetaDataPair wrapped in a data field.

System Channels⚓︎

These channels report node status and request errors, rather than blockchain events.

/node/info⚓︎

node/info
Notifies subscribed clients of the node's information, only in response to w/api/node/info REQ.
Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/node/info
MESSAGE
destination:/node/info
subscription:sub-0
message-id:...

{ ... }
Followed by a Node JSON body.

/errors⚓︎

errors
Notifies subscribed clients when a /w/api request fails, for example when its address payload is invalid. A client can subscribe to this channel right after connecting, so problems surface here instead of being silently dropped.
Subscription frame Notification frame
SUBSCRIBE
id:sub-0
destination:/errors
MESSAGE
destination:/errors
subscription:sub-0
message-id:...

{
    "timeStamp": 67191609,
    "status": 400,
    "error": "Bad Request",
    "message": "account is not valid"
}

Requests⚓︎

WebSocket Request
A message sent by the client to make the node deliver: either notifications on channels that require registration, or an immediate notification containing a snapshot of the state of the blockchain.

Requests are read-only and do not modify the chain state.

All requests are sent with a SEND frame to a destination that begins with /w/api/. Some requests return no answer, while others return results through one of the channels above.

Registration Requests⚓︎

Some account channels stay silent until the address is registered. These requests perform that registration, so those channels begin delivering notifications.

Registrations are shared

The node maintains a single list of registered addresses that is shared by all connected clients. After any client registers an address, all clients subscribed to that account's channels receive notifications for that address without registering it again. The registration remains active until the node restarts.

/w/api/account/subscribe⚓︎

w/api/account/subscribe
Registers the address so the node starts sending notifications on account channels.
Request frame
SEND
destination:/w/api/account/subscribe

{ "account": "{address}" }

/w/api/account/get⚓︎

w/api/account/get
Registers the address like w/api/account/subscribe REQ, and forces the node to send a notification containing the account's current state to account/{address} WS.
Request frame
SEND
destination:/w/api/account/get

{ "account": "{address}" }

Snapshot Requests⚓︎

Each request forces the node to send an immediate snapshot of current data to a channel, without waiting for a new event.

This allows applications to fetch current data on demand through the same channels used for live updates, instead of polling the REST API.

/w/api/account/transfers/all⚓︎

w/api/account/transfers/all
Forces the node to send the account's up to 25 most recent confirmed transactions to recenttransactions/{address} WS, plus its pending transactions exactly as w/api/account/transfers/unconfirmed REQ does.
Request frame
SEND
destination:/w/api/account/transfers/all

{ "account": "{address}" }

/w/api/account/transfers/unconfirmed⚓︎

w/api/account/transfers/unconfirmed
Forces the node to send up to 10 of the account's most recent pending transactions to unconfirmed/{address} WS and the global unconfirmed WS channel.
Request frame
SEND
destination:/w/api/account/transfers/unconfirmed

{ "account": "{address}" }

/w/api/account/mosaic/owned⚓︎

w/api/account/mosaic/owned
Forces the node to send a notification containing the mosaics the account owns to account/mosaic/owned/{address} WS.
Request frame
SEND
destination:/w/api/account/mosaic/owned

{ "account": "{address}" }

/w/api/account/mosaic/owned/definition⚓︎

w/api/account/mosaic/owned/definition
Forces the node to send a notification containing the mosaic definitions the account owns to account/mosaic/owned/definition/{address} WS.
Request frame
SEND
destination:/w/api/account/mosaic/owned/definition

{ "account": "{address}" }

/w/api/account/namespace/owned⚓︎

w/api/account/namespace/owned
Forces the node to send a notification containing the namespaces the account owns to account/namespace/owned/{address} WS.
Request frame
SEND
destination:/w/api/account/namespace/owned

{ "account": "{address}" }

/w/api/block/last⚓︎

w/api/block/last

Forces the node to send a notification containing the latest block to blocks WS.

The node processes the block as if it had just been added, so the account channels related to the accounts involved in it are notified again as well.

Request frame
SEND
destination:/w/api/block/last

/w/api/node/info⚓︎

w/api/node/info
Forces the node to send a notification containing its own information to node/info WS.
Request frame
SEND
destination:/w/api/node/info