From 07dcd091cbe1b1f61a7b44dffc57aaff6fd0d266 Mon Sep 17 00:00:00 2001 From: Gutica Stefan <123564494+stefangutica@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:17:14 +0200 Subject: [PATCH 1/7] Document MultiversX WebSocket Subscription API Added detailed documentation for the MultiversX WebSocket Subscription API, including connection details, subscription events, and payload structures. --- .../rest-api/ws-subscriptions.md | 308 ++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 docs/sdk-and-tools/rest-api/ws-subscriptions.md diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md new file mode 100644 index 00000000..24accc8d --- /dev/null +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -0,0 +1,308 @@ +# MultiversX WebSocket Subscription API +### Real-Time Streaming Guide (socket.io-client) + +The MultiversX WebSocket Subscription API provides real-time blockchain data identical in structure to the REST API responses from: + +``` +https://api.multiversx.com/ +https://devnet-api.multiversx.com/ +https://testnet-api.multiversx.com/ +``` + +All updates contain the same fields as their REST counterparts, and where applicable, a `Count` representing **the total number of items existing at the time the message was delivered**. + +--- + +# 1. Selecting the Correct WebSocket Endpoint + +The WebSocket endpoint depends on the network: + +## **Mainnet** +You must first determine which **cluster** you are allocated to. + +### 1. Call: +``` +https://api.multiversx.com/websocket/config +``` + +### Example response: +```json +{ + "url": "socket-api-ams.multiversx.com" +} +``` + +Clusters may be: +- `socket-api-ams.multiversx.com` +- `socket-api-ovh.multiversx.com` + +### 2. Connect using the provided cluster: +``` +https:///ws/subscription +``` + +--- + +## **Devnet** + +Direct endpoint: +``` +https://devnet-socket-api.multiversx.com/ws/subscription +``` +(Devnet always uses the `-ovh` cluster.) + +--- + +## **Testnet** + +Direct endpoint: +``` +https://testnet-socket-api.multiversx.com/ws/subscription +``` +(Testnet also always uses the `-ovh` cluster.) + +--- + +# 2. Connecting with socket.io-client + +```js +import { io } from "socket.io-client"; + +const socket = io("https://", { + path: "/ws/subscription", +}); +``` + +Replace `` depending on the network: +- Mainnet → result from `/websocket/config` +- Devnet → `devnet-socket-api.multiversx.com` +- Testnet → `testnet-socket-api.multiversx.com` + +--- + +# 3. Subscription Events (Overview) + +Each subscription type uses a dedicated event: + +| Stream | Subscribe Event | Update Event | Mirrors REST Route | +|--------|-----------------|--------------|---------------------| +| Transactions | `subscribeTransactions` | `transactionUpdate` | `/transactions` | +| Blocks | `subscribeBlocks` | `blocksUpdate` | `/blocks` | +| Pool (Mempool) | `subscribePool` | `poolUpdate` | `/pool` | +| Events | `subscribeEvents` | `eventsUpdate` | `/events` | +| Stats | `subscribeStats` | `statsUpdate` | `/stats` | + +All update events return objects structured **exactly like the REST API**, plus a `Count` where applicable (`transactionsCount`, `blocksCount`, etc.). + +--- + +# 4. Payload Structure (DTO Requirements) + +Below are the fields supported for each subscription. +All fields not listed below must NOT be sent. + +### Common Notes: +- `from` is **always required** and must be `0` +- `size` is **required** unless otherwise specified, and must be **1–50** +- All other filters are optional + +--- + +## 4.1 Transactions Subscription + +### Event +``` +subscribeTransactions +``` + +### Payload Fields + +| Field | Optional | Description | +|-------|----------|-------------| +| from | required | Must always be 0 | +| size | required | Number of items (1–50) | +| status | optional | Filter by status | +| order | optional | ASC or DESC | +| isRelayed | optional | Filter relayed txs | +| isScCall | optional | SC calls only | +| withScResults | optional | Attach SC results | +| withRelayedScresults | optional | Attach relayed SC results | +| withOperations | optional | Include operations | +| withLogs | optional | Include logs | +| withScamInfo | optional | Include scam info | +| withUsername | optional | Include username | +| withBlockInfo | optional | Include block metadata | +| withActionTransferValue | optional | Include transfer values | +| fields | optional | Select specific fields | + +### Example subscribe + +```js +socket.emit("subscribeTransactions", { + from: 0, + size: 25 +}); +``` + +### What you receive (generic) + +``` +transactionUpdate: +{ + "transactions": [...], // identical to REST API + "transactionsCount": // total items at that moment +} +``` + +--- + +## 4.2 Blocks Subscription + +### Event +``` +subscribeBlocks +``` + +### Payload Fields + +| Field | Optional | +|-------|----------| +| from | required | +| size | required | +| shard | optional | +| order | optional | +| withProposerIdentity | optional | + +### Example subscribe + +```js +socket.emit("subscribeBlocks", { + from: 0, + size: 25 +}); +``` + +### Update structure + +``` +blocksUpdate: +{ + "blocks": [...], // same as REST API + "blocksCount": // total blocks at that moment +} +``` + +--- + +## 4.3 Pool (Mempool) Subscription + +### Event +``` +subscribePool +``` + +### Payload Fields + +| Field | Optional | +|--------|----------| +| from | required | +| size | required | +| type | optional | + +### Example subscribe + +```js +socket.emit("subscribePool", { + from: 0, + size: 25, + type: "Transaction" +}); +``` + +### Update structure + +``` +poolUpdate: +{ + "pool": [...], // same as REST API + "poolCount": // total pool items at that moment +} +``` + +--- + +## 4.4 Events Subscription + +### Event +``` +subscribeEvents +``` + +### Payload Fields + +| Field | Optional | +|--------|----------| +| from | required | +| size | required | +| shard | optional | + +### Example + +```js +socket.emit("subscribeEvents", { + from: 0, + size: 25 +}); +``` + +### Update structure + +``` +eventsUpdate: +{ + "events": [...], // same as REST API + "eventsCount": // total events at that moment +} +``` + +--- + +## 4.5 Stats Subscription + +### Event +``` +subscribeStats +``` + +### Payload +No payload must be sent. + +### Example + +```js +socket.emit("subscribeStats"); +``` + +### Update structure + +``` +statsUpdate: +{ + ... same fields as GET /stats +} +``` + +--- + +# 5. Summary + +- WebSocket endpoint depends on network + - Mainnet → determined via `GET /websocket/config` + - Devnet/Testnet → fixed endpoint +- All subscriptions are made via event names (`subscribeBlocks`, etc.) +- Payload DTOs specify required and optional fields +- Update events return structures identical to REST API +- `Count` always reflects **the total number of items at that exact moment** +- Communication is done using `socket.io-client` + +This document contains everything required to use MultiversX WebSocket Subscriptions effectively. From 51447f4f2783610ed7575408ed962f0395884d6c Mon Sep 17 00:00:00 2001 From: Gutica Stefan <123564494+stefangutica@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:24:56 +0200 Subject: [PATCH 2/7] Update multiversx-api.md with WebSocket details Added WebSocket Subscription documentation section. --- docs/sdk-and-tools/rest-api/multiversx-api.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/sdk-and-tools/rest-api/multiversx-api.md b/docs/sdk-and-tools/rest-api/multiversx-api.md index 1b4e0a38..34fc30d0 100644 --- a/docs/sdk-and-tools/rest-api/multiversx-api.md +++ b/docs/sdk-and-tools/rest-api/multiversx-api.md @@ -95,7 +95,7 @@ An API instance can be started with the following behavior: - cache warmer: used to proactively fetch data & pushes it to cache, to improve performance & scalability - elastic updater: used to attach various extra information to items in the elasticsearch, for not having to fetch associated data from other external systems when performing listing requests - events notifier: perform various decisions based on incoming logs & events - +- subscription: used to manage subscriptions, fetch and broadcast data to subscribers [comment]: # (mx-context-auto) ## Rate limiting @@ -113,6 +113,13 @@ Rest API documentation of `api.multiversx.com` can be found on the [Swagger docs [comment]: # (mx-context-auto) +## WebSocket Subscription Documentation + +Real-time blockchain streaming is supported through the MultiversX WebSocket Subscription API. +A dedicated guide is available here [WebSocket Subscription Guide](./ws-subscriptions.md) + +[comment]: # (mx-context-auto) + ## References - Github repository: [https://github.com/multiversx/mx-api-service](https://github.com/multiversx/mx-api-service) From 520bac800c18846d910052e947d589de8c43a9fd Mon Sep 17 00:00:00 2001 From: bogdan-rosianu Date: Fri, 21 Nov 2025 11:34:56 +0200 Subject: [PATCH 3/7] organize pages --- docs/sdk-and-tools/rest-api/ws-subscriptions.md | 5 +++++ sidebars.js | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md index 24accc8d..a15e8ec4 100644 --- a/docs/sdk-and-tools/rest-api/ws-subscriptions.md +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -1,3 +1,8 @@ +--- +id: multiversx-api-ws +title: MultiversX API WebSocket +--- + # MultiversX WebSocket Subscription API ### Real-Time Streaming Guide (socket.io-client) diff --git a/sidebars.js b/sidebars.js index e14985bf..fcf56a01 100644 --- a/sidebars.js +++ b/sidebars.js @@ -267,7 +267,14 @@ const sidebars = { label: "Rest API", items: [ "sdk-and-tools/rest-api/rest-api", - "sdk-and-tools/rest-api/multiversx-api", + { + type: "category", + label: "MultiversX API", + items: [ + "sdk-and-tools/rest-api/multiversx-api", + "sdk-and-tools/rest-api/multiversx-api-ws" + ] + }, { type: "category", label: "MultiversX Gateway", From 786e3ce73cdc97003d66a446db8a4f07f0f5abfc Mon Sep 17 00:00:00 2001 From: Gutica Stefan <123564494+stefangutica@users.noreply.github.com> Date: Fri, 21 Nov 2025 12:18:29 +0200 Subject: [PATCH 4/7] Revise WebSocket Subscription API documentation Updated the WebSocket Subscription API documentation for clarity and consistency. --- .../rest-api/ws-subscriptions.md | 425 +++++++++++------- 1 file changed, 265 insertions(+), 160 deletions(-) diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md index a15e8ec4..0ab8b7c0 100644 --- a/docs/sdk-and-tools/rest-api/ws-subscriptions.md +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -6,7 +6,7 @@ title: MultiversX API WebSocket # MultiversX WebSocket Subscription API ### Real-Time Streaming Guide (socket.io-client) -The MultiversX WebSocket Subscription API provides real-time blockchain data identical in structure to the REST API responses from: +The MultiversX WebSocket Subscription API provides real-time blockchain data identical in structure to REST API responses: ``` https://api.multiversx.com/ @@ -14,133 +14,105 @@ https://devnet-api.multiversx.com/ https://testnet-api.multiversx.com/ ``` -All updates contain the same fields as their REST counterparts, and where applicable, a `Count` representing **the total number of items existing at the time the message was delivered**. +All updates include the same fields as REST responses, plus a `Count` representing **the total number of existing items at the moment the message was delivered**. --- -# 1. Selecting the Correct WebSocket Endpoint +# 1. Selecting the WebSocket Endpoint -The WebSocket endpoint depends on the network: +Before connecting, fetch the WebSocket cluster: -## **Mainnet** -You must first determine which **cluster** you are allocated to. - -### 1. Call: +## Mainnet ``` https://api.multiversx.com/websocket/config ``` -### Example response: -```json -{ - "url": "socket-api-ams.multiversx.com" -} +## Testnet +``` +https://testnet-api.multiversx.com/websocket/config ``` -Clusters may be: -- `socket-api-ams.multiversx.com` -- `socket-api-ovh.multiversx.com` - -### 2. Connect using the provided cluster: +## Devnet ``` -https:///ws/subscription +https://devnet-api.multiversx.com/websocket/config ``` ---- - -## **Devnet** +### Response example +```json +{ + "url": "socket-api-xxxx.multiversx.com" +} +``` -Direct endpoint: +### WebSocket endpoint ``` -https://devnet-socket-api.multiversx.com/ws/subscription +https:///ws/subscription ``` -(Devnet always uses the `-ovh` cluster.) --- -## **Testnet** +# 2. Subscription Events Overview -Direct endpoint: -``` -https://testnet-socket-api.multiversx.com/ws/subscription -``` -(Testnet also always uses the `-ovh` cluster.) +| Stream | Subscribe Event | Update Event | Mirrors REST Route | +|--------------|------------------------|---------------------|---------------------| +| Transactions | `subscribeTransactions`| `transactionUpdate`| `/transactions` | +| Blocks | `subscribeBlocks` | `blocksUpdate` | `/blocks` | +| Pool | `subscribePool` | `poolUpdate` | `/pool` | +| Events | `subscribeEvents` | `eventsUpdate` | `/events` | +| Stats | `subscribeStats` | `statsUpdate` | `/stats` | --- -# 2. Connecting with socket.io-client +# 3. Subscriptions (Full Flows) -```js -import { io } from "socket.io-client"; +Each subscription includes: -const socket = io("https://", { - path: "/ws/subscription", -}); -``` - -Replace `` depending on the network: -- Mainnet → result from `/websocket/config` -- Devnet → `devnet-socket-api.multiversx.com` -- Testnet → `testnet-socket-api.multiversx.com` +1. Connect +2. Payload (fields + types + required) +3. Subscribe +4. Listen +5. Update Example --- -# 3. Subscription Events (Overview) - -Each subscription type uses a dedicated event: - -| Stream | Subscribe Event | Update Event | Mirrors REST Route | -|--------|-----------------|--------------|---------------------| -| Transactions | `subscribeTransactions` | `transactionUpdate` | `/transactions` | -| Blocks | `subscribeBlocks` | `blocksUpdate` | `/blocks` | -| Pool (Mempool) | `subscribePool` | `poolUpdate` | `/pool` | -| Events | `subscribeEvents` | `eventsUpdate` | `/events` | -| Stats | `subscribeStats` | `statsUpdate` | `/stats` | +# 3.1 Transactions Subscription -All update events return objects structured **exactly like the REST API**, plus a `Count` where applicable (`transactionsCount`, `blocksCount`, etc.). +## Connect ---- - -# 4. Payload Structure (DTO Requirements) +```js +import { io } from "socket.io-client"; -Below are the fields supported for each subscription. -All fields not listed below must NOT be sent. +const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then(r => r.json()); -### Common Notes: -- `from` is **always required** and must be `0` -- `size` is **required** unless otherwise specified, and must be **1–50** -- All other filters are optional +const socket = io(`https://${url}`, { path: "/ws/subscription" }); +``` --- -## 4.1 Transactions Subscription +## Payload (DTO) + +| Field | Type | Required | +|-------|------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| status | `"success" \| "pending" \| "invalid" \| "fail"` | NO | +| order | `"asc" \| "desc"` | NO | +| isRelayed | boolean | NO | +| isScCall | boolean | NO | +| withScResults | boolean | NO | +| withRelayedScresults | boolean | NO | +| withOperations | boolean | NO | +| withLogs | boolean | NO | +| withScamInfo | boolean | NO | +| withUsername | boolean | NO | +| withBlockInfo | boolean | NO | +| withActionTransferValue | boolean | NO | +| fields | string[] | NO | -### Event -``` -subscribeTransactions -``` +--- -### Payload Fields - -| Field | Optional | Description | -|-------|----------|-------------| -| from | required | Must always be 0 | -| size | required | Number of items (1–50) | -| status | optional | Filter by status | -| order | optional | ASC or DESC | -| isRelayed | optional | Filter relayed txs | -| isScCall | optional | SC calls only | -| withScResults | optional | Attach SC results | -| withRelayedScresults | optional | Attach relayed SC results | -| withOperations | optional | Include operations | -| withLogs | optional | Include logs | -| withScamInfo | optional | Include scam info | -| withUsername | optional | Include username | -| withBlockInfo | optional | Include block metadata | -| withActionTransferValue | optional | Include transfer values | -| fields | optional | Select specific fields | - -### Example subscribe +## Subscribe ```js socket.emit("subscribeTransactions", { @@ -149,36 +121,64 @@ socket.emit("subscribeTransactions", { }); ``` -### What you receive (generic) +--- + +## Listen +```js +socket.on("transactionUpdate", (data) => { + console.log("Transactions update:", data); +}); ``` -transactionUpdate: + +--- + +## Update Example + +```json { - "transactions": [...], // identical to REST API - "transactionsCount": // total items at that moment + "transactions": [ + { + "txHash": "7f172e468e61210805815f33af8500d827aff36df6196cc96783c6d592a5fc76", + "sender": "erd1srdxd75cg7nkaxxy3llz4hmwqqkmcej0jelv8ults8m86g29aj3sxjkc45", + "receiver": "erd19waq9tlhj32ane9duhkv6jusm58ca5ylnthhg9h8fcumtp8srh4qrl3hjj", + "nonce": 211883, + "status": "pending", + "timestamp": 1763718888 + } + ], + "transactionsCount": 1234567 } ``` --- -## 4.2 Blocks Subscription +# 3.2 Blocks Subscription -### Event -``` -subscribeBlocks +## Connect + +```js +const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then(r => r.json()); + +const socket = io(`https://${url}`, { path: "/ws/subscription" }); ``` -### Payload Fields +--- + +## Payload (DTO) -| Field | Optional | -|-------|----------| -| from | required | -| size | required | -| shard | optional | -| order | optional | -| withProposerIdentity | optional | +| Field | Type | Required | +|-------|------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| shard | number | NO | +| order | `"asc" \| "desc"` | NO | +| withProposerIdentity | boolean | NO | -### Example subscribe +--- + +## Subscribe ```js socket.emit("subscribeBlocks", { @@ -187,34 +187,62 @@ socket.emit("subscribeBlocks", { }); ``` -### Update structure +--- + +## Listen +```js +socket.on("blocksUpdate", (data) => { + console.log("Blocks update:", data); +}); ``` -blocksUpdate: + +--- + +## Update Example + +```json { - "blocks": [...], // same as REST API - "blocksCount": // total blocks at that moment + "blocks": [ + { + "hash": "8576bb346bc95680f1ab0eb1fb8c43bbd03ef6e6ac8fd24a3c6e85d4c81be16b", + "epoch": 1939, + "nonce": 27918028, + "round": 27933551, + "shard": 0, + "timestamp": 1763718906 + } + ], + "blocksCount": 111636242 } ``` --- -## 4.3 Pool (Mempool) Subscription +# 3.3 Pool Subscription -### Event -``` -subscribePool +## Connect + +```js +const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then(r => r.json()); + +const socket = io(`https://${url}`, { path: "/ws/subscription" }); ``` -### Payload Fields +--- + +## Payload (DTO) -| Field | Optional | -|--------|----------| -| from | required | -| size | required | -| type | optional | +| Field | Type | Required | +|--------|------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| type | `"Transaction" \| "SmartContractResult" \| "Reward"` | NO | -### Example subscribe +--- + +## Subscribe ```js socket.emit("subscribePool", { @@ -224,34 +252,62 @@ socket.emit("subscribePool", { }); ``` -### Update structure +--- + +## Listen +```js +socket.on("poolUpdate", (data) => { + console.log("Pool update:", data); +}); ``` -poolUpdate: + +--- + +## Update Example + +```json { - "pool": [...], // same as REST API - "poolCount": // total pool items at that moment + "pool": [ + { + "txHash": "0b0cd3932689c6853e50ccc0f49feeb9c5f2a68858cbd213fd0825dd4bc0632b", + "sender": "erd1jfwjg6tl87rhe73zmd5ygm8xmc9u3ys80mjvakdc7ca3kknr2kjq7s98h3", + "receiver": "erd1qqqqqqqqqqqqqpgq0dsmyccxtlkrjvv0czyv2p4kcy72xvt3nzgq8j2q3y", + "nonce": 1166, + "function": "claim", + "type": "Transaction" + } + ], + "poolCount": 1902 } ``` --- -## 4.4 Events Subscription +# 3.4 Events Subscription -### Event -``` -subscribeEvents +## Connect + +```js +const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then(r => r.json()); + +const socket = io(`https://${url}`, { path: "/ws/subscription" }); ``` -### Payload Fields +--- + +## Payload (DTO) -| Field | Optional | -|--------|----------| -| from | required | -| size | required | -| shard | optional | +| Field | Type | Required | +|--------|------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| shard | number | NO | -### Example +--- + +## Subscribe ```js socket.emit("subscribeEvents", { @@ -260,54 +316,103 @@ socket.emit("subscribeEvents", { }); ``` -### Update structure +--- +## Listen + +```js +socket.on("eventsUpdate", (data) => { + console.log("Events update:", data); +}); ``` -eventsUpdate: + +--- + +## Update Example + +```json { - "events": [...], // same as REST API - "eventsCount": // total events at that moment + "events": [ + { + "txHash": "b5bde891df72e26fb36e7ab3acc14b74044bd9aa82b4852692f5b9a767e0391f-1-0", + "identifier": "signalError", + "address": "erd1jv5m4v3yr0wy6g2jtz2v344sfx572rw6aclum9c6r7rd4ej4l6csjej2wh", + "timestamp": 1763718864, + "topics": [ + "9329bab2241bdc4d21525894c8d6b049a9e50ddaee3fcd971a1f86dae655feb1", + "4865616c7468206e6f74206c6f7720656e6f75676820666f72206c69717569646174696f6e2e" + ], + "shardID": 1 + } + ], + "eventsCount": 109432 } ``` --- -## 4.5 Stats Subscription +# 3.5 Stats Subscription -### Event -``` -subscribeStats +## Connect + +```js +const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then(r => r.json()); + +const socket = io(`https://${url}`, { path: "/ws/subscription" }); ``` -### Payload -No payload must be sent. +--- + +## Payload (DTO) + +Stats does not accept payload. + +--- -### Example +## Subscribe ```js socket.emit("subscribeStats"); ``` -### Update structure +--- + +## Listen +```js +socket.on("statsUpdate", (data) => { + console.log("Stats update:", data); +}); ``` -statsUpdate: + +--- + +## Update Example + +```json { - ... same fields as GET /stats + "shards": 3, + "blocks": 111636242, + "accounts": 9126654, + "transactions": 569773975, + "scResults": 402596990, + "epoch": 1939, + "roundsPassed": 9478, + "roundsPerEpoch": 14400, + "refreshRate": 6000 } ``` --- -# 5. Summary +# 4. Summary -- WebSocket endpoint depends on network - - Mainnet → determined via `GET /websocket/config` - - Devnet/Testnet → fixed endpoint -- All subscriptions are made via event names (`subscribeBlocks`, etc.) -- Payload DTOs specify required and optional fields -- Update events return structures identical to REST API -- `Count` always reflects **the total number of items at that exact moment** -- Communication is done using `socket.io-client` +- WebSocket endpoint is dynamically obtained via `/websocket/config` +- Each stream has its own subscribe and update events +- Payload DTOs enforce strict field validation +- Update messages mirror REST API routes +- `Count` always reflects **total items at that moment** +- Uses `socket.io-client` This document contains everything required to use MultiversX WebSocket Subscriptions effectively. From 653966d2b482c82ce5704e856d9b13239730b4ca Mon Sep 17 00:00:00 2001 From: Gutica Stefan <123564494+stefangutica@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:12:38 +0200 Subject: [PATCH 5/7] Revise WebSocket subscriptions documentation Updated the WebSocket subscriptions documentation for clarity and consistency. Enhanced formatting and improved descriptions for payloads and examples. --- .../rest-api/ws-subscriptions.md | 343 ++++++++---------- 1 file changed, 142 insertions(+), 201 deletions(-) diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md index 0ab8b7c0..d9ad7e6a 100644 --- a/docs/sdk-and-tools/rest-api/ws-subscriptions.md +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -14,26 +14,26 @@ https://devnet-api.multiversx.com/ https://testnet-api.multiversx.com/ ``` -All updates include the same fields as REST responses, plus a `Count` representing **the total number of existing items at the moment the message was delivered**. +All updates mirror REST responses and include a `Count` field representing **the total number of existing items at the moment the update was delivered**. --- -# 1. Selecting the WebSocket Endpoint +# Selecting the WebSocket Endpoint Before connecting, fetch the WebSocket cluster: -## Mainnet -``` +### Mainnet +```text https://api.multiversx.com/websocket/config ``` -## Testnet -``` +### Testnet +```text https://testnet-api.multiversx.com/websocket/config ``` -## Devnet -``` +### Devnet +```text https://devnet-api.multiversx.com/websocket/config ``` @@ -45,94 +45,79 @@ https://devnet-api.multiversx.com/websocket/config ``` ### WebSocket endpoint -``` +```text https:///ws/subscription ``` --- -# 2. Subscription Events Overview +# Subscription Events Overview -| Stream | Subscribe Event | Update Event | Mirrors REST Route | -|--------------|------------------------|---------------------|---------------------| -| Transactions | `subscribeTransactions`| `transactionUpdate`| `/transactions` | -| Blocks | `subscribeBlocks` | `blocksUpdate` | `/blocks` | -| Pool | `subscribePool` | `poolUpdate` | `/pool` | -| Events | `subscribeEvents` | `eventsUpdate` | `/events` | -| Stats | `subscribeStats` | `statsUpdate` | `/stats` | +| Stream | Subscribe Event | Update Event | Mirrors REST Route | +|--------------|-------------------------|--------------------|---------------------| +| Transactions | `subscribeTransactions` | `transactionUpdate`| `/transactions` | +| Blocks | `subscribeBlocks` | `blocksUpdate` | `/blocks` | +| Pool | `subscribePool` | `poolUpdate` | `/pool` | +| Events | `subscribeEvents` | `eventsUpdate` | `/events` | +| Stats | `subscribeStats` | `statsUpdate` | `/stats` | --- -# 3. Subscriptions (Full Flows) +# Subscriptions Each subscription includes: -1. Connect -2. Payload (fields + types + required) -3. Subscribe -4. Listen -5. Update Example +- Payload (fields + types + required) +- Single code block with connect + payload + subscribe + listen +- Update example --- -# 3.1 Transactions Subscription +# Transactions Subscription + +## Payload (DTO) -## Connect +| Field | Type | Required | +|-------------------------|----------------------------------------------------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| status | `"success" \| "pending" \| "invalid" \| "fail"` | NO | +| order | `"asc" \| "desc"` | NO | +| isRelayed | boolean | NO | +| isScCall | boolean | NO | +| withScResults | boolean | NO | +| withRelayedScresults | boolean | NO | +| withOperations | boolean | NO | +| withLogs | boolean | NO | +| withScamInfo | boolean | NO | +| withUsername | boolean | NO | +| withBlockInfo | boolean | NO | +| withActionTransferValue | boolean | NO | +| fields | string[] | NO | + +## Example usage ```js import { io } from "socket.io-client"; -const { url } = await fetch("https://api.multiversx.com/websocket/config") - .then(r => r.json()); +async function main() { + const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then((r) => r.json()); -const socket = io(`https://${url}`, { path: "/ws/subscription" }); -``` - ---- + const socket = io(`https://${url}`, { path: "/ws/subscription" }); -## Payload (DTO) - -| Field | Type | Required | -|-------|------|----------| -| from | number | YES | -| size | number (1–50) | YES | -| status | `"success" \| "pending" \| "invalid" \| "fail"` | NO | -| order | `"asc" \| "desc"` | NO | -| isRelayed | boolean | NO | -| isScCall | boolean | NO | -| withScResults | boolean | NO | -| withRelayedScresults | boolean | NO | -| withOperations | boolean | NO | -| withLogs | boolean | NO | -| withScamInfo | boolean | NO | -| withUsername | boolean | NO | -| withBlockInfo | boolean | NO | -| withActionTransferValue | boolean | NO | -| fields | string[] | NO | + const payload = { from: 0, size: 25 }; ---- + socket.emit("subscribeTransactions", payload); -## Subscribe - -```js -socket.emit("subscribeTransactions", { - from: 0, - size: 25 -}); -``` - ---- - -## Listen + socket.on("transactionUpdate", (data) => { + console.log("Transactions update:", data); + }); +} -```js -socket.on("transactionUpdate", (data) => { - console.log("Transactions update:", data); -}); +main().catch(console.error); ``` ---- - ## Update Example ```json @@ -153,52 +138,41 @@ socket.on("transactionUpdate", (data) => { --- -# 3.2 Blocks Subscription - -## Connect +# Blocks Subscription -```js -const { url } = await fetch("https://api.multiversx.com/websocket/config") - .then(r => r.json()); - -const socket = io(`https://${url}`, { path: "/ws/subscription" }); -``` +## Payload (DTO) ---- +| Field | Type | Required | +|-----------------------|---------------------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| shard | number | NO | +| order | `"asc" \| "desc"` | NO | +| withProposerIdentity | boolean | NO | -## Payload (DTO) +## Example usage -| Field | Type | Required | -|-------|------|----------| -| from | number | YES | -| size | number (1–50) | YES | -| shard | number | NO | -| order | `"asc" \| "desc"` | NO | -| withProposerIdentity | boolean | NO | +```js +import { io } from "socket.io-client"; ---- +async function main() { + const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then((r) => r.json()); -## Subscribe + const socket = io(`https://${url}`, { path: "/ws/subscription" }); -```js -socket.emit("subscribeBlocks", { - from: 0, - size: 25 -}); -``` + const payload = { from: 0, size: 25 }; ---- + socket.emit("subscribeBlocks", payload); -## Listen + socket.on("blocksUpdate", (data) => { + console.log("Blocks update:", data); + }); +} -```js -socket.on("blocksUpdate", (data) => { - console.log("Blocks update:", data); -}); +main().catch(console.error); ``` ---- - ## Update Example ```json @@ -219,51 +193,39 @@ socket.on("blocksUpdate", (data) => { --- -# 3.3 Pool Subscription - -## Connect +# Pool Subscription -```js -const { url } = await fetch("https://api.multiversx.com/websocket/config") - .then(r => r.json()); +## Payload (DTO) -const socket = io(`https://${url}`, { path: "/ws/subscription" }); -``` +| Field | Type | Required | +|--------|-----------------------------------------------------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| type | `"Transaction" \| "SmartContractResult" \| "Reward"`| NO | ---- - -## Payload (DTO) +## Example usage -| Field | Type | Required | -|--------|------|----------| -| from | number | YES | -| size | number (1–50) | YES | -| type | `"Transaction" \| "SmartContractResult" \| "Reward"` | NO | +```js +import { io } from "socket.io-client"; ---- +async function main() { + const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then((r) => r.json()); -## Subscribe + const socket = io(`https://${url}`, { path: "/ws/subscription" }); -```js -socket.emit("subscribePool", { - from: 0, - size: 25, - type: "Transaction" -}); -``` + const payload = { from: 0, size: 25, type: "Transaction" }; ---- + socket.emit("subscribePool", payload); -## Listen + socket.on("poolUpdate", (data) => { + console.log("Pool update:", data); + }); +} -```js -socket.on("poolUpdate", (data) => { - console.log("Pool update:", data); -}); +main().catch(console.error); ``` ---- - ## Update Example ```json @@ -284,50 +246,39 @@ socket.on("poolUpdate", (data) => { --- -# 3.4 Events Subscription - -## Connect +# Events Subscription -```js -const { url } = await fetch("https://api.multiversx.com/websocket/config") - .then(r => r.json()); - -const socket = io(`https://${url}`, { path: "/ws/subscription" }); -``` +## Payload (DTO) ---- +| Field | Type | Required | +|-------|---------------|----------| +| from | number | YES | +| size | number (1–50) | YES | +| shard | number | NO | -## Payload (DTO) +## Example usage -| Field | Type | Required | -|--------|------|----------| -| from | number | YES | -| size | number (1–50) | YES | -| shard | number | NO | +```js +import { io } from "socket.io-client"; ---- +async function main() { + const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then((r) => r.json()); -## Subscribe + const socket = io(`https://${url}`, { path: "/ws/subscription" }); -```js -socket.emit("subscribeEvents", { - from: 0, - size: 25 -}); -``` + const payload = { from: 0, size: 25 }; ---- + socket.emit("subscribeEvents", payload); -## Listen + socket.on("eventsUpdate", (data) => { + console.log("Events update:", data); + }); +} -```js -socket.on("eventsUpdate", (data) => { - console.log("Events update:", data); -}); +main().catch(console.error); ``` ---- - ## Update Example ```json @@ -351,42 +302,32 @@ socket.on("eventsUpdate", (data) => { --- -# 3.5 Stats Subscription - -## Connect - -```js -const { url } = await fetch("https://api.multiversx.com/websocket/config") - .then(r => r.json()); - -const socket = io(`https://${url}`, { path: "/ws/subscription" }); -``` - ---- +# Stats Subscription ## Payload (DTO) -Stats does not accept payload. +Stats subscription does not accept any payload. ---- - -## Subscribe +## Example usage ```js -socket.emit("subscribeStats"); -``` +import { io } from "socket.io-client"; ---- +async function main() { + const { url } = await fetch("https://api.multiversx.com/websocket/config") + .then((r) => r.json()); -## Listen + const socket = io(`https://${url}`, { path: "/ws/subscription" }); -```js -socket.on("statsUpdate", (data) => { - console.log("Stats update:", data); -}); -``` + socket.emit("subscribeStats"); ---- + socket.on("statsUpdate", (data) => { + console.log("Stats update:", data); + }); +} + +main().catch(console.error); +``` ## Update Example @@ -406,13 +347,13 @@ socket.on("statsUpdate", (data) => { --- -# 4. Summary +# Summary -- WebSocket endpoint is dynamically obtained via `/websocket/config` -- Each stream has its own subscribe and update events -- Payload DTOs enforce strict field validation -- Update messages mirror REST API routes -- `Count` always reflects **total items at that moment** -- Uses `socket.io-client` +- WebSocket endpoint is dynamically obtained via `/websocket/config`. +- Each stream has its own subscribe and update events. +- Payload DTOs define allowed fields and required/optional rules. +- Update messages mirror REST API and include `Count` fields. +- `Count` reflects **total items at the moment of update**. +- Uses `socket.io-client`. This document contains everything required to use MultiversX WebSocket Subscriptions effectively. From 8488d86644afa92c41c82fb0027c0c6b6c62d7fa Mon Sep 17 00:00:00 2001 From: GuticaStefan Date: Fri, 21 Nov 2025 13:28:54 +0200 Subject: [PATCH 6/7] fix table of contents --- .../rest-api/ws-subscriptions.md | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md index d9ad7e6a..9daaebf6 100644 --- a/docs/sdk-and-tools/rest-api/ws-subscriptions.md +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -3,8 +3,7 @@ id: multiversx-api-ws title: MultiversX API WebSocket --- -# MultiversX WebSocket Subscription API -### Real-Time Streaming Guide (socket.io-client) +# MultiversX WebSocket Subscription API The MultiversX WebSocket Subscription API provides real-time blockchain data identical in structure to REST API responses: @@ -18,7 +17,7 @@ All updates mirror REST responses and include a `Count` field represen --- -# Selecting the WebSocket Endpoint +## Selecting the WebSocket Endpoint Before connecting, fetch the WebSocket cluster: @@ -51,7 +50,7 @@ https:///ws/subscription --- -# Subscription Events Overview +## Subscription Events Overview | Stream | Subscribe Event | Update Event | Mirrors REST Route | |--------------|-------------------------|--------------------|---------------------| @@ -63,19 +62,19 @@ https:///ws/subscription --- -# Subscriptions +## Subscriptions -Each subscription includes: +Each stream includes: -- Payload (fields + types + required) +- DTO payload table - Single code block with connect + payload + subscribe + listen - Update example --- -# Transactions Subscription +### Transactions Subscription -## Payload (DTO) +#### Payload (DTO) | Field | Type | Required | |-------------------------|----------------------------------------------------|----------| @@ -95,7 +94,7 @@ Each subscription includes: | withActionTransferValue | boolean | NO | | fields | string[] | NO | -## Example usage +#### Example usage ```js import { io } from "socket.io-client"; @@ -118,7 +117,7 @@ async function main() { main().catch(console.error); ``` -## Update Example +#### Update Example ```json { @@ -138,9 +137,9 @@ main().catch(console.error); --- -# Blocks Subscription +### Blocks Subscription -## Payload (DTO) +#### Payload (DTO) | Field | Type | Required | |-----------------------|---------------------|----------| @@ -150,7 +149,7 @@ main().catch(console.error); | order | `"asc" \| "desc"` | NO | | withProposerIdentity | boolean | NO | -## Example usage +#### Example usage ```js import { io } from "socket.io-client"; @@ -173,7 +172,7 @@ async function main() { main().catch(console.error); ``` -## Update Example +#### Update Example ```json { @@ -193,9 +192,9 @@ main().catch(console.error); --- -# Pool Subscription +### Pool Subscription -## Payload (DTO) +#### Payload (DTO) | Field | Type | Required | |--------|-----------------------------------------------------|----------| @@ -203,7 +202,7 @@ main().catch(console.error); | size | number (1–50) | YES | | type | `"Transaction" \| "SmartContractResult" \| "Reward"`| NO | -## Example usage +#### Example usage ```js import { io } from "socket.io-client"; @@ -226,7 +225,7 @@ async function main() { main().catch(console.error); ``` -## Update Example +#### Update Example ```json { @@ -240,15 +239,15 @@ main().catch(console.error); "type": "Transaction" } ], - "poolCount": 1902 + "poolCount": 1902 } ``` --- -# Events Subscription +### Events Subscription -## Payload (DTO) +#### Payload (DTO) | Field | Type | Required | |-------|---------------|----------| @@ -256,7 +255,7 @@ main().catch(console.error); | size | number (1–50) | YES | | shard | number | NO | -## Example usage +#### Example usage ```js import { io } from "socket.io-client"; @@ -279,7 +278,7 @@ async function main() { main().catch(console.error); ``` -## Update Example +#### Update Example ```json { @@ -302,13 +301,13 @@ main().catch(console.error); --- -# Stats Subscription +### Stats Subscription -## Payload (DTO) +#### Payload (DTO) Stats subscription does not accept any payload. -## Example usage +#### Example usage ```js import { io } from "socket.io-client"; @@ -329,7 +328,7 @@ async function main() { main().catch(console.error); ``` -## Update Example +#### Update Example ```json { @@ -347,7 +346,7 @@ main().catch(console.error); --- -# Summary +## Summary - WebSocket endpoint is dynamically obtained via `/websocket/config`. - Each stream has its own subscribe and update events. From f9ccd091e9bd08bf4ab678b6cb138650a1046640 Mon Sep 17 00:00:00 2001 From: bogdan-rosianu Date: Fri, 21 Nov 2025 13:55:19 +0200 Subject: [PATCH 7/7] further details --- .../rest-api/ws-subscriptions.md | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/sdk-and-tools/rest-api/ws-subscriptions.md b/docs/sdk-and-tools/rest-api/ws-subscriptions.md index 9daaebf6..377c3eb4 100644 --- a/docs/sdk-and-tools/rest-api/ws-subscriptions.md +++ b/docs/sdk-and-tools/rest-api/ws-subscriptions.md @@ -3,8 +3,28 @@ id: multiversx-api-ws title: MultiversX API WebSocket --- -# MultiversX WebSocket Subscription API +## MultiversX WebSocket Subscription API +Starting with the release [v1.17.0](https://github.com/multiversx/mx-api-service/releases/tag/v1.17.0) we introduced WebSocket Subscription functionality. + +It is useful for subscribing to new events, rather than performing polling (requesting latest events with a given refresh period). + +## Update Frequency and Duplicate Management +Subscribers receive the most recent events at regular intervals defined by the API. + +This means: +* You are **not** notified only when new events occur. + +* Instead, you receive an update every round (or according to the configured interval configured in MultiversX API). + +* Each update contains the latest events for that timeframe. + +*For example*: + +If you subscribe to the latest 25 blocks, you will receive those 25 blocks every second. +Because of this repeating interval, **duplicate events may appear across batches**, and it is the user’s responsibility to filter or handle those duplicates on their side. + +## Rest API models compatibility The MultiversX WebSocket Subscription API provides real-time blockchain data identical in structure to REST API responses: ``` @@ -15,8 +35,6 @@ https://testnet-api.multiversx.com/ All updates mirror REST responses and include a `Count` field representing **the total number of existing items at the moment the update was delivered**. ---- - ## Selecting the WebSocket Endpoint Before connecting, fetch the WebSocket cluster: